1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
2 Copyright (C) 1994-1995, 2000-2013 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
23 #include <mingw_time.h>
24 #include <stddef.h> /* for offsetof */
27 #include <float.h> /* for DBL_EPSILON */
34 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
36 #include <sys/utime.h>
39 /* must include CRT headers *before* config.h */
42 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
69 #include "epaths.h" /* for SHELL */
74 /* MinGW64 (_W64) defines these in its _mingw.h. */
75 #if defined(__GNUC__) && !defined(_W64)
76 #define _ANONYMOUS_UNION
77 #define _ANONYMOUS_STRUCT
80 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
81 use a different name to avoid compilation problems. */
82 typedef struct _MEMORY_STATUS_EX
{
85 DWORDLONG ullTotalPhys
;
86 DWORDLONG ullAvailPhys
;
87 DWORDLONG ullTotalPageFile
;
88 DWORDLONG ullAvailPageFile
;
89 DWORDLONG ullTotalVirtual
;
90 DWORDLONG ullAvailVirtual
;
91 DWORDLONG ullAvailExtendedVirtual
;
92 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
94 /* These are here so that GDB would know about these data types. This
95 allows to attach GDB to Emacs when a fatal exception is triggered
96 and Windows pops up the "application needs to be closed" dialog.
97 At that point, _gnu_exception_handler, the top-level exception
98 handler installed by the MinGW startup code, is somewhere on the
99 call-stack of the main thread, so going to that call frame and
100 looking at the argument to _gnu_exception_handler, which is a
101 PEXCEPTION_POINTERS pointer, can reveal the exception code
102 (excptr->ExceptionRecord->ExceptionCode) and the address where the
103 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
104 well as some additional information specific to the exception. */
105 PEXCEPTION_POINTERS excptr
;
106 PEXCEPTION_RECORD excprec
;
112 #include <tlhelp32.h>
117 #if _WIN32_WINNT < 0x0500
118 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
119 /* This either is not in psapi.h or guarded by higher value of
120 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
121 defines it in psapi.h */
122 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
124 DWORD PageFaultCount
;
125 SIZE_T PeakWorkingSetSize
;
126 SIZE_T WorkingSetSize
;
127 SIZE_T QuotaPeakPagedPoolUsage
;
128 SIZE_T QuotaPagedPoolUsage
;
129 SIZE_T QuotaPeakNonPagedPoolUsage
;
130 SIZE_T QuotaNonPagedPoolUsage
;
131 SIZE_T PagefileUsage
;
132 SIZE_T PeakPagefileUsage
;
134 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
138 #include <winioctl.h>
144 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
145 define them by hand if not already defined. */
146 #ifndef SDDL_REVISION_1
147 #define SDDL_REVISION_1 1
148 #endif /* SDDL_REVISION_1 */
150 #if defined(_MSC_VER) || defined(_W64)
151 /* MSVC and MinGW64 don't provide the definition of
152 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
153 which cannot be included because it triggers conflicts with other
154 Windows API headers. So we define it here by hand. */
156 typedef struct _REPARSE_DATA_BUFFER
{
158 USHORT ReparseDataLength
;
162 USHORT SubstituteNameOffset
;
163 USHORT SubstituteNameLength
;
164 USHORT PrintNameOffset
;
165 USHORT PrintNameLength
;
168 } SymbolicLinkReparseBuffer
;
170 USHORT SubstituteNameOffset
;
171 USHORT SubstituteNameLength
;
172 USHORT PrintNameOffset
;
173 USHORT PrintNameLength
;
175 } MountPointReparseBuffer
;
178 } GenericReparseBuffer
;
180 } REPARSE_DATA_BUFFER
, *PREPARSE_DATA_BUFFER
;
182 #ifndef FILE_DEVICE_FILE_SYSTEM
183 #define FILE_DEVICE_FILE_SYSTEM 9
185 #ifndef METHOD_BUFFERED
186 #define METHOD_BUFFERED 0
188 #ifndef FILE_ANY_ACCESS
189 #define FILE_ANY_ACCESS 0x00000000
192 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
194 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
195 #ifndef FSCTL_GET_REPARSE_POINT
196 #define FSCTL_GET_REPARSE_POINT \
197 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
201 /* TCP connection support. */
202 #include <sys/socket.h>
221 #include <iphlpapi.h> /* should be after winsock2.h */
225 #include "w32common.h"
227 #include "w32select.h"
229 #include "dispextern.h" /* for xstrcasecmp */
230 #include "coding.h" /* for Vlocale_coding_system */
232 #include "careadlinkat.h"
233 #include "allocator.h"
235 /* For serial_configure and serial_open. */
238 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
239 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
241 Lisp_Object QCloaded_from
;
243 void globals_of_w32 (void);
244 static DWORD
get_rid (PSID
);
245 static int is_symlink (const char *);
246 static char * chase_symlinks (const char *);
247 static int enable_privilege (LPCTSTR
, BOOL
, TOKEN_PRIVILEGES
*);
248 static int restore_privilege (TOKEN_PRIVILEGES
*);
249 static BOOL WINAPI
revert_to_self (void);
251 static int sys_access (const char *, int);
252 extern void *e_malloc (size_t);
253 extern int sys_select (int, SELECT_TYPE
*, SELECT_TYPE
*, SELECT_TYPE
*,
254 struct timespec
*, void *);
255 extern int sys_dup (int);
260 /* Initialization states.
262 WARNING: If you add any more such variables for additional APIs,
263 you MUST add initialization for them to globals_of_w32
264 below. This is because these variables might get set
265 to non-NULL values during dumping, but the dumped Emacs
266 cannot reuse those values, because it could be run on a
267 different version of the OS, where API addresses are
269 static BOOL g_b_init_is_windows_9x
;
270 static BOOL g_b_init_open_process_token
;
271 static BOOL g_b_init_get_token_information
;
272 static BOOL g_b_init_lookup_account_sid
;
273 static BOOL g_b_init_get_sid_sub_authority
;
274 static BOOL g_b_init_get_sid_sub_authority_count
;
275 static BOOL g_b_init_get_security_info
;
276 static BOOL g_b_init_get_file_security
;
277 static BOOL g_b_init_get_security_descriptor_owner
;
278 static BOOL g_b_init_get_security_descriptor_group
;
279 static BOOL g_b_init_is_valid_sid
;
280 static BOOL g_b_init_create_toolhelp32_snapshot
;
281 static BOOL g_b_init_process32_first
;
282 static BOOL g_b_init_process32_next
;
283 static BOOL g_b_init_open_thread_token
;
284 static BOOL g_b_init_impersonate_self
;
285 static BOOL g_b_init_revert_to_self
;
286 static BOOL g_b_init_get_process_memory_info
;
287 static BOOL g_b_init_get_process_working_set_size
;
288 static BOOL g_b_init_global_memory_status
;
289 static BOOL g_b_init_global_memory_status_ex
;
290 static BOOL g_b_init_get_length_sid
;
291 static BOOL g_b_init_equal_sid
;
292 static BOOL g_b_init_copy_sid
;
293 static BOOL g_b_init_get_native_system_info
;
294 static BOOL g_b_init_get_system_times
;
295 static BOOL g_b_init_create_symbolic_link
;
296 static BOOL g_b_init_get_security_descriptor_dacl
;
297 static BOOL g_b_init_convert_sd_to_sddl
;
298 static BOOL g_b_init_convert_sddl_to_sd
;
299 static BOOL g_b_init_is_valid_security_descriptor
;
300 static BOOL g_b_init_set_file_security
;
301 static BOOL g_b_init_get_adapters_info
;
304 BEGIN: Wrapper functions around OpenProcessToken
305 and other functions in advapi32.dll that are only
306 supported in Windows NT / 2k / XP
308 /* ** Function pointer typedefs ** */
309 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
310 HANDLE ProcessHandle
,
312 PHANDLE TokenHandle
);
313 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
315 TOKEN_INFORMATION_CLASS TokenInformationClass
,
316 LPVOID TokenInformation
,
317 DWORD TokenInformationLength
,
318 PDWORD ReturnLength
);
319 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
320 HANDLE process_handle
,
321 LPFILETIME creation_time
,
322 LPFILETIME exit_time
,
323 LPFILETIME kernel_time
,
324 LPFILETIME user_time
);
326 GetProcessTimes_Proc get_process_times_fn
= NULL
;
329 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
330 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
331 const char * const SetFileSecurity_Name
= "SetFileSecurityW";
333 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
334 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
335 const char * const SetFileSecurity_Name
= "SetFileSecurityA";
337 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
338 LPCTSTR lpSystemName
,
343 LPDWORD cbDomainName
,
344 PSID_NAME_USE peUse
);
345 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
348 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
350 typedef DWORD (WINAPI
* GetSecurityInfo_Proc
) (
352 SE_OBJECT_TYPE ObjectType
,
353 SECURITY_INFORMATION SecurityInfo
,
358 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
);
359 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
361 SECURITY_INFORMATION RequestedInformation
,
362 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
364 LPDWORD lpnLengthNeeded
);
365 typedef BOOL (WINAPI
*SetFileSecurity_Proc
) (
367 SECURITY_INFORMATION SecurityInformation
,
368 PSECURITY_DESCRIPTOR pSecurityDescriptor
);
369 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
370 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
372 LPBOOL lpbOwnerDefaulted
);
373 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
374 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
376 LPBOOL lpbGroupDefaulted
);
377 typedef BOOL (WINAPI
*GetSecurityDescriptorDacl_Proc
) (
378 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
379 LPBOOL lpbDaclPresent
,
381 LPBOOL lpbDaclDefaulted
);
382 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
384 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
386 DWORD th32ProcessID
);
387 typedef BOOL (WINAPI
* Process32First_Proc
) (
389 LPPROCESSENTRY32 lppe
);
390 typedef BOOL (WINAPI
* Process32Next_Proc
) (
392 LPPROCESSENTRY32 lppe
);
393 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
397 PHANDLE TokenHandle
);
398 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
399 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
400 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
401 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
403 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
405 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
407 PSIZE_T lpMinimumWorkingSetSize
,
408 PSIZE_T lpMaximumWorkingSetSize
);
409 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
410 LPMEMORYSTATUS lpBuffer
);
411 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
412 LPMEMORY_STATUS_EX lpBuffer
);
413 typedef BOOL (WINAPI
* CopySid_Proc
) (
414 DWORD nDestinationSidLength
,
415 PSID pDestinationSid
,
417 typedef BOOL (WINAPI
* EqualSid_Proc
) (
420 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
422 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
423 LPSYSTEM_INFO lpSystemInfo
);
424 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
425 LPFILETIME lpIdleTime
,
426 LPFILETIME lpKernelTime
,
427 LPFILETIME lpUserTime
);
428 typedef BOOLEAN (WINAPI
*CreateSymbolicLink_Proc
) (
429 LPTSTR lpSymlinkFileName
,
430 LPTSTR lpTargetFileName
,
432 typedef BOOL (WINAPI
*ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
) (
433 LPCTSTR StringSecurityDescriptor
,
434 DWORD StringSDRevision
,
435 PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
436 PULONG SecurityDescriptorSize
);
437 typedef BOOL (WINAPI
*ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
) (
438 PSECURITY_DESCRIPTOR SecurityDescriptor
,
439 DWORD RequestedStringSDRevision
,
440 SECURITY_INFORMATION SecurityInformation
,
441 LPTSTR
*StringSecurityDescriptor
,
442 PULONG StringSecurityDescriptorLen
);
443 typedef BOOL (WINAPI
*IsValidSecurityDescriptor_Proc
) (PSECURITY_DESCRIPTOR
);
444 typedef DWORD (WINAPI
*GetAdaptersInfo_Proc
) (
445 PIP_ADAPTER_INFO pAdapterInfo
,
448 /* ** A utility function ** */
452 static BOOL s_b_ret
= 0;
453 OSVERSIONINFO os_ver
;
454 if (g_b_init_is_windows_9x
== 0)
456 g_b_init_is_windows_9x
= 1;
457 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
458 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
459 if (GetVersionEx (&os_ver
))
461 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
467 static Lisp_Object
ltime (ULONGLONG
);
469 /* Get total user and system times for get-internal-run-time.
470 Returns a list of integers if the times are provided by the OS
471 (NT derivatives), otherwise it returns the result of current-time. */
473 w32_get_internal_run_time (void)
475 if (get_process_times_fn
)
477 FILETIME create
, exit
, kernel
, user
;
478 HANDLE proc
= GetCurrentProcess ();
479 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
481 LARGE_INTEGER user_int
, kernel_int
, total
;
482 user_int
.LowPart
= user
.dwLowDateTime
;
483 user_int
.HighPart
= user
.dwHighDateTime
;
484 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
485 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
486 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
487 return ltime (total
.QuadPart
);
491 return Fcurrent_time ();
494 /* ** The wrapper functions ** */
497 open_process_token (HANDLE ProcessHandle
,
501 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
502 HMODULE hm_advapi32
= NULL
;
503 if (is_windows_9x () == TRUE
)
507 if (g_b_init_open_process_token
== 0)
509 g_b_init_open_process_token
= 1;
510 hm_advapi32
= LoadLibrary ("Advapi32.dll");
511 s_pfn_Open_Process_Token
=
512 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
514 if (s_pfn_Open_Process_Token
== NULL
)
519 s_pfn_Open_Process_Token (
527 get_token_information (HANDLE TokenHandle
,
528 TOKEN_INFORMATION_CLASS TokenInformationClass
,
529 LPVOID TokenInformation
,
530 DWORD TokenInformationLength
,
533 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
534 HMODULE hm_advapi32
= NULL
;
535 if (is_windows_9x () == TRUE
)
539 if (g_b_init_get_token_information
== 0)
541 g_b_init_get_token_information
= 1;
542 hm_advapi32
= LoadLibrary ("Advapi32.dll");
543 s_pfn_Get_Token_Information
=
544 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
546 if (s_pfn_Get_Token_Information
== NULL
)
551 s_pfn_Get_Token_Information (
553 TokenInformationClass
,
555 TokenInformationLength
,
561 lookup_account_sid (LPCTSTR lpSystemName
,
566 LPDWORD cbDomainName
,
569 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
570 HMODULE hm_advapi32
= NULL
;
571 if (is_windows_9x () == TRUE
)
575 if (g_b_init_lookup_account_sid
== 0)
577 g_b_init_lookup_account_sid
= 1;
578 hm_advapi32
= LoadLibrary ("Advapi32.dll");
579 s_pfn_Lookup_Account_Sid
=
580 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
582 if (s_pfn_Lookup_Account_Sid
== NULL
)
587 s_pfn_Lookup_Account_Sid (
599 get_sid_sub_authority (PSID pSid
, DWORD n
)
601 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
602 static DWORD zero
= 0U;
603 HMODULE hm_advapi32
= NULL
;
604 if (is_windows_9x () == TRUE
)
608 if (g_b_init_get_sid_sub_authority
== 0)
610 g_b_init_get_sid_sub_authority
= 1;
611 hm_advapi32
= LoadLibrary ("Advapi32.dll");
612 s_pfn_Get_Sid_Sub_Authority
=
613 (GetSidSubAuthority_Proc
) GetProcAddress (
614 hm_advapi32
, "GetSidSubAuthority");
616 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
620 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
624 get_sid_sub_authority_count (PSID pSid
)
626 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
627 static UCHAR zero
= 0U;
628 HMODULE hm_advapi32
= NULL
;
629 if (is_windows_9x () == TRUE
)
633 if (g_b_init_get_sid_sub_authority_count
== 0)
635 g_b_init_get_sid_sub_authority_count
= 1;
636 hm_advapi32
= LoadLibrary ("Advapi32.dll");
637 s_pfn_Get_Sid_Sub_Authority_Count
=
638 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
639 hm_advapi32
, "GetSidSubAuthorityCount");
641 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
645 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
649 get_security_info (HANDLE handle
,
650 SE_OBJECT_TYPE ObjectType
,
651 SECURITY_INFORMATION SecurityInfo
,
656 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
)
658 static GetSecurityInfo_Proc s_pfn_Get_Security_Info
= NULL
;
659 HMODULE hm_advapi32
= NULL
;
660 if (is_windows_9x () == TRUE
)
664 if (g_b_init_get_security_info
== 0)
666 g_b_init_get_security_info
= 1;
667 hm_advapi32
= LoadLibrary ("Advapi32.dll");
668 s_pfn_Get_Security_Info
=
669 (GetSecurityInfo_Proc
) GetProcAddress (
670 hm_advapi32
, "GetSecurityInfo");
672 if (s_pfn_Get_Security_Info
== NULL
)
676 return (s_pfn_Get_Security_Info (handle
, ObjectType
, SecurityInfo
,
677 ppsidOwner
, ppsidGroup
, ppDacl
, ppSacl
,
678 ppSecurityDescriptor
));
682 get_file_security (LPCTSTR lpFileName
,
683 SECURITY_INFORMATION RequestedInformation
,
684 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
686 LPDWORD lpnLengthNeeded
)
688 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
689 HMODULE hm_advapi32
= NULL
;
690 if (is_windows_9x () == TRUE
)
695 if (g_b_init_get_file_security
== 0)
697 g_b_init_get_file_security
= 1;
698 hm_advapi32
= LoadLibrary ("Advapi32.dll");
699 s_pfn_Get_File_Security
=
700 (GetFileSecurity_Proc
) GetProcAddress (
701 hm_advapi32
, GetFileSecurity_Name
);
703 if (s_pfn_Get_File_Security
== NULL
)
708 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
709 pSecurityDescriptor
, nLength
,
714 set_file_security (LPCTSTR lpFileName
,
715 SECURITY_INFORMATION SecurityInformation
,
716 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
718 static SetFileSecurity_Proc s_pfn_Set_File_Security
= NULL
;
719 HMODULE hm_advapi32
= NULL
;
720 if (is_windows_9x () == TRUE
)
725 if (g_b_init_set_file_security
== 0)
727 g_b_init_set_file_security
= 1;
728 hm_advapi32
= LoadLibrary ("Advapi32.dll");
729 s_pfn_Set_File_Security
=
730 (SetFileSecurity_Proc
) GetProcAddress (
731 hm_advapi32
, SetFileSecurity_Name
);
733 if (s_pfn_Set_File_Security
== NULL
)
738 return (s_pfn_Set_File_Security (lpFileName
, SecurityInformation
,
739 pSecurityDescriptor
));
743 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
745 LPBOOL lpbOwnerDefaulted
)
747 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
748 HMODULE hm_advapi32
= NULL
;
749 if (is_windows_9x () == TRUE
)
754 if (g_b_init_get_security_descriptor_owner
== 0)
756 g_b_init_get_security_descriptor_owner
= 1;
757 hm_advapi32
= LoadLibrary ("Advapi32.dll");
758 s_pfn_Get_Security_Descriptor_Owner
=
759 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
760 hm_advapi32
, "GetSecurityDescriptorOwner");
762 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
767 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
772 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
774 LPBOOL lpbGroupDefaulted
)
776 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
777 HMODULE hm_advapi32
= NULL
;
778 if (is_windows_9x () == TRUE
)
783 if (g_b_init_get_security_descriptor_group
== 0)
785 g_b_init_get_security_descriptor_group
= 1;
786 hm_advapi32
= LoadLibrary ("Advapi32.dll");
787 s_pfn_Get_Security_Descriptor_Group
=
788 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
789 hm_advapi32
, "GetSecurityDescriptorGroup");
791 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
796 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
801 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
802 LPBOOL lpbDaclPresent
,
804 LPBOOL lpbDaclDefaulted
)
806 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl
= NULL
;
807 HMODULE hm_advapi32
= NULL
;
808 if (is_windows_9x () == TRUE
)
813 if (g_b_init_get_security_descriptor_dacl
== 0)
815 g_b_init_get_security_descriptor_dacl
= 1;
816 hm_advapi32
= LoadLibrary ("Advapi32.dll");
817 s_pfn_Get_Security_Descriptor_Dacl
=
818 (GetSecurityDescriptorDacl_Proc
) GetProcAddress (
819 hm_advapi32
, "GetSecurityDescriptorDacl");
821 if (s_pfn_Get_Security_Descriptor_Dacl
== NULL
)
826 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor
,
827 lpbDaclPresent
, pDacl
,
832 is_valid_sid (PSID sid
)
834 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
835 HMODULE hm_advapi32
= NULL
;
836 if (is_windows_9x () == TRUE
)
840 if (g_b_init_is_valid_sid
== 0)
842 g_b_init_is_valid_sid
= 1;
843 hm_advapi32
= LoadLibrary ("Advapi32.dll");
845 (IsValidSid_Proc
) GetProcAddress (
846 hm_advapi32
, "IsValidSid");
848 if (s_pfn_Is_Valid_Sid
== NULL
)
852 return (s_pfn_Is_Valid_Sid (sid
));
856 equal_sid (PSID sid1
, PSID sid2
)
858 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
859 HMODULE hm_advapi32
= NULL
;
860 if (is_windows_9x () == TRUE
)
864 if (g_b_init_equal_sid
== 0)
866 g_b_init_equal_sid
= 1;
867 hm_advapi32
= LoadLibrary ("Advapi32.dll");
869 (EqualSid_Proc
) GetProcAddress (
870 hm_advapi32
, "EqualSid");
872 if (s_pfn_Equal_Sid
== NULL
)
876 return (s_pfn_Equal_Sid (sid1
, sid2
));
880 get_length_sid (PSID sid
)
882 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
883 HMODULE hm_advapi32
= NULL
;
884 if (is_windows_9x () == TRUE
)
888 if (g_b_init_get_length_sid
== 0)
890 g_b_init_get_length_sid
= 1;
891 hm_advapi32
= LoadLibrary ("Advapi32.dll");
892 s_pfn_Get_Length_Sid
=
893 (GetLengthSid_Proc
) GetProcAddress (
894 hm_advapi32
, "GetLengthSid");
896 if (s_pfn_Get_Length_Sid
== NULL
)
900 return (s_pfn_Get_Length_Sid (sid
));
904 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
906 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
907 HMODULE hm_advapi32
= NULL
;
908 if (is_windows_9x () == TRUE
)
912 if (g_b_init_copy_sid
== 0)
914 g_b_init_copy_sid
= 1;
915 hm_advapi32
= LoadLibrary ("Advapi32.dll");
917 (CopySid_Proc
) GetProcAddress (
918 hm_advapi32
, "CopySid");
920 if (s_pfn_Copy_Sid
== NULL
)
924 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
928 END: Wrapper functions around OpenProcessToken
929 and other functions in advapi32.dll that are only
930 supported in Windows NT / 2k / XP
934 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
936 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
937 if (is_windows_9x () != TRUE
)
939 if (g_b_init_get_native_system_info
== 0)
941 g_b_init_get_native_system_info
= 1;
942 s_pfn_Get_Native_System_Info
=
943 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
944 "GetNativeSystemInfo");
946 if (s_pfn_Get_Native_System_Info
!= NULL
)
947 s_pfn_Get_Native_System_Info (lpSystemInfo
);
950 lpSystemInfo
->dwNumberOfProcessors
= -1;
954 get_system_times (LPFILETIME lpIdleTime
,
955 LPFILETIME lpKernelTime
,
956 LPFILETIME lpUserTime
)
958 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
959 if (is_windows_9x () == TRUE
)
963 if (g_b_init_get_system_times
== 0)
965 g_b_init_get_system_times
= 1;
966 s_pfn_Get_System_times
=
967 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
970 if (s_pfn_Get_System_times
== NULL
)
972 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
975 static BOOLEAN WINAPI
976 create_symbolic_link (LPTSTR lpSymlinkFilename
,
977 LPTSTR lpTargetFileName
,
980 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link
= NULL
;
983 if (is_windows_9x () == TRUE
)
988 if (g_b_init_create_symbolic_link
== 0)
990 g_b_init_create_symbolic_link
= 1;
992 s_pfn_Create_Symbolic_Link
=
993 (CreateSymbolicLink_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
994 "CreateSymbolicLinkW");
996 s_pfn_Create_Symbolic_Link
=
997 (CreateSymbolicLink_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
998 "CreateSymbolicLinkA");
1001 if (s_pfn_Create_Symbolic_Link
== NULL
)
1007 retval
= s_pfn_Create_Symbolic_Link (lpSymlinkFilename
, lpTargetFileName
,
1009 /* If we were denied creation of the symlink, try again after
1010 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1013 TOKEN_PRIVILEGES priv_current
;
1015 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME
, TRUE
, &priv_current
))
1017 retval
= s_pfn_Create_Symbolic_Link (lpSymlinkFilename
, lpTargetFileName
,
1019 restore_privilege (&priv_current
);
1027 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor
)
1029 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc
= NULL
;
1031 if (is_windows_9x () == TRUE
)
1037 if (g_b_init_is_valid_security_descriptor
== 0)
1039 g_b_init_is_valid_security_descriptor
= 1;
1040 s_pfn_Is_Valid_Security_Descriptor_Proc
=
1041 (IsValidSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1042 "IsValidSecurityDescriptor");
1044 if (s_pfn_Is_Valid_Security_Descriptor_Proc
== NULL
)
1050 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor
);
1054 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor
,
1055 DWORD RequestedStringSDRevision
,
1056 SECURITY_INFORMATION SecurityInformation
,
1057 LPTSTR
*StringSecurityDescriptor
,
1058 PULONG StringSecurityDescriptorLen
)
1060 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL
= NULL
;
1063 if (is_windows_9x () == TRUE
)
1069 if (g_b_init_convert_sd_to_sddl
== 0)
1071 g_b_init_convert_sd_to_sddl
= 1;
1073 s_pfn_Convert_SD_To_SDDL
=
1074 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1075 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1077 s_pfn_Convert_SD_To_SDDL
=
1078 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1079 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1082 if (s_pfn_Convert_SD_To_SDDL
== NULL
)
1088 retval
= s_pfn_Convert_SD_To_SDDL (SecurityDescriptor
,
1089 RequestedStringSDRevision
,
1090 SecurityInformation
,
1091 StringSecurityDescriptor
,
1092 StringSecurityDescriptorLen
);
1098 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor
,
1099 DWORD StringSDRevision
,
1100 PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
1101 PULONG SecurityDescriptorSize
)
1103 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD
= NULL
;
1106 if (is_windows_9x () == TRUE
)
1112 if (g_b_init_convert_sddl_to_sd
== 0)
1114 g_b_init_convert_sddl_to_sd
= 1;
1116 s_pfn_Convert_SDDL_To_SD
=
1117 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1118 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1120 s_pfn_Convert_SDDL_To_SD
=
1121 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1122 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1125 if (s_pfn_Convert_SDDL_To_SD
== NULL
)
1131 retval
= s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor
,
1134 SecurityDescriptorSize
);
1140 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo
, PULONG pOutBufLen
)
1142 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info
= NULL
;
1143 HMODULE hm_iphlpapi
= NULL
;
1145 if (is_windows_9x () == TRUE
)
1146 return ERROR_NOT_SUPPORTED
;
1148 if (g_b_init_get_adapters_info
== 0)
1150 g_b_init_get_adapters_info
= 1;
1151 hm_iphlpapi
= LoadLibrary ("Iphlpapi.dll");
1153 s_pfn_Get_Adapters_Info
= (GetAdaptersInfo_Proc
)
1154 GetProcAddress (hm_iphlpapi
, "GetAdaptersInfo");
1156 if (s_pfn_Get_Adapters_Info
== NULL
)
1157 return ERROR_NOT_SUPPORTED
;
1158 return s_pfn_Get_Adapters_Info (pAdapterInfo
, pOutBufLen
);
1163 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1164 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1166 This is called from alloc.c:valid_pointer_p. */
1168 w32_valid_pointer_p (void *p
, int size
)
1171 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
1175 unsigned char *buf
= alloca (size
);
1176 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
1187 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1188 codepage defined by file-name-coding-system. */
1190 /* Current codepage for encoding file names. */
1191 static int file_name_codepage
;
1193 /* Produce a Windows ANSI codepage suitable for encoding file names.
1194 Return the information about that codepage in CP_INFO. */
1196 codepage_for_filenames (CPINFO
*cp_info
)
1198 /* A simple cache to avoid calling GetCPInfo every time we need to
1199 encode/decode a file name. The file-name encoding is not
1200 supposed to be changed too frequently, if ever. */
1201 static Lisp_Object last_file_name_encoding
;
1203 Lisp_Object current_encoding
;
1205 current_encoding
= Vfile_name_coding_system
;
1206 if (NILP (current_encoding
))
1207 current_encoding
= Vdefault_file_name_coding_system
;
1209 if (!EQ (last_file_name_encoding
, current_encoding
))
1211 /* Default to the current ANSI codepage. */
1212 file_name_codepage
= w32_ansi_code_page
;
1214 if (NILP (current_encoding
))
1216 char *cpname
= SDATA (SYMBOL_NAME (current_encoding
));
1217 char *cp
= NULL
, *end
;
1220 if (strncmp (cpname
, "cp", 2) == 0)
1222 else if (strncmp (cpname
, "windows-", 8) == 0)
1228 cpnum
= strtol (cp
, &end
, 10);
1229 if (cpnum
&& *end
== '\0' && end
- cp
>= 2)
1230 file_name_codepage
= cpnum
;
1234 if (!file_name_codepage
)
1235 file_name_codepage
= CP_ACP
; /* CP_ACP = 0, but let's not assume that */
1237 if (!GetCPInfo (file_name_codepage
, &cp
))
1239 file_name_codepage
= CP_ACP
;
1240 if (!GetCPInfo (file_name_codepage
, &cp
))
1247 return file_name_codepage
;
1251 filename_to_utf16 (const char *fn_in
, wchar_t *fn_out
)
1253 int result
= MultiByteToWideChar (CP_UTF8
, MB_ERR_INVALID_CHARS
, fn_in
, -1,
1258 DWORD err
= GetLastError ();
1262 case ERROR_INVALID_FLAGS
:
1263 case ERROR_INVALID_PARAMETER
:
1266 case ERROR_INSUFFICIENT_BUFFER
:
1267 case ERROR_NO_UNICODE_TRANSLATION
:
1278 filename_from_utf16 (const wchar_t *fn_in
, char *fn_out
)
1280 int result
= WideCharToMultiByte (CP_UTF8
, 0, fn_in
, -1,
1281 fn_out
, MAX_UTF8_PATH
, NULL
, NULL
);
1285 DWORD err
= GetLastError ();
1289 case ERROR_INVALID_FLAGS
:
1290 case ERROR_INVALID_PARAMETER
:
1293 case ERROR_INSUFFICIENT_BUFFER
:
1294 case ERROR_NO_UNICODE_TRANSLATION
:
1305 filename_to_ansi (const char *fn_in
, char *fn_out
)
1307 wchar_t fn_utf16
[MAX_PATH
];
1309 if (filename_to_utf16 (fn_in
, fn_utf16
) == 0)
1312 int codepage
= codepage_for_filenames (NULL
);
1314 result
= WideCharToMultiByte (codepage
, 0, fn_utf16
, -1,
1315 fn_out
, MAX_PATH
, NULL
, NULL
);
1318 DWORD err
= GetLastError ();
1322 case ERROR_INVALID_FLAGS
:
1323 case ERROR_INVALID_PARAMETER
:
1326 case ERROR_INSUFFICIENT_BUFFER
:
1327 case ERROR_NO_UNICODE_TRANSLATION
:
1340 filename_from_ansi (const char *fn_in
, char *fn_out
)
1342 wchar_t fn_utf16
[MAX_PATH
];
1343 int codepage
= codepage_for_filenames (NULL
);
1344 int result
= MultiByteToWideChar (codepage
, MB_ERR_INVALID_CHARS
, fn_in
, -1,
1345 fn_utf16
, MAX_PATH
);
1349 DWORD err
= GetLastError ();
1353 case ERROR_INVALID_FLAGS
:
1354 case ERROR_INVALID_PARAMETER
:
1357 case ERROR_INSUFFICIENT_BUFFER
:
1358 case ERROR_NO_UNICODE_TRANSLATION
:
1365 return filename_from_utf16 (fn_utf16
, fn_out
);
1370 /* The directory where we started, in UTF-8. */
1371 static char startup_dir
[MAX_UTF8_PATH
];
1373 /* Get the current working directory. */
1375 getcwd (char *dir
, int dirsize
)
1382 if (dirsize
<= strlen (startup_dir
))
1388 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
1392 /* Emacs doesn't actually change directory itself, it stays in the
1393 same directory where it was started. */
1394 strcpy (dir
, startup_dir
);
1399 /* Emulate getloadavg. */
1401 struct load_sample
{
1408 /* Number of processors on this machine. */
1409 static unsigned num_of_processors
;
1411 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1412 static struct load_sample samples
[16*60];
1413 static int first_idx
= -1, last_idx
= -1;
1414 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
1419 int next_idx
= from
+ 1;
1421 if (next_idx
>= max_idx
)
1430 int prev_idx
= from
- 1;
1433 prev_idx
= max_idx
- 1;
1439 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
1441 SYSTEM_INFO sysinfo
;
1442 FILETIME ft_idle
, ft_user
, ft_kernel
;
1444 /* Initialize the number of processors on this machine. */
1445 if (num_of_processors
<= 0)
1447 get_native_system_info (&sysinfo
);
1448 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
1449 if (num_of_processors
<= 0)
1451 GetSystemInfo (&sysinfo
);
1452 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
1454 if (num_of_processors
<= 0)
1455 num_of_processors
= 1;
1458 /* TODO: Take into account threads that are ready to run, by
1459 sampling the "\System\Processor Queue Length" performance
1460 counter. The code below accounts only for threads that are
1461 actually running. */
1463 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
1465 ULARGE_INTEGER uidle
, ukernel
, uuser
;
1467 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
1468 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
1469 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
1470 *idle
= uidle
.QuadPart
;
1471 *kernel
= ukernel
.QuadPart
;
1472 *user
= uuser
.QuadPart
;
1482 /* Produce the load average for a given time interval, using the
1483 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1484 1-minute, 5-minute, or 15-minute average, respectively. */
1488 double retval
= -1.0;
1491 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
1492 time_t now
= samples
[last_idx
].sample_time
;
1494 if (first_idx
!= last_idx
)
1496 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
1498 tdiff
= difftime (now
, samples
[idx
].sample_time
);
1499 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
1502 samples
[last_idx
].kernel
+ samples
[last_idx
].user
1503 - (samples
[idx
].kernel
+ samples
[idx
].user
);
1504 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
1506 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
1509 if (idx
== first_idx
)
1518 getloadavg (double loadavg
[], int nelem
)
1521 ULONGLONG idle
, kernel
, user
;
1522 time_t now
= time (NULL
);
1524 /* Store another sample. We ignore samples that are less than 1 sec
1526 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
1528 sample_system_load (&idle
, &kernel
, &user
);
1529 last_idx
= buf_next (last_idx
);
1530 samples
[last_idx
].sample_time
= now
;
1531 samples
[last_idx
].idle
= idle
;
1532 samples
[last_idx
].kernel
= kernel
;
1533 samples
[last_idx
].user
= user
;
1534 /* If the buffer has more that 15 min worth of samples, discard
1536 if (first_idx
== -1)
1537 first_idx
= last_idx
;
1538 while (first_idx
!= last_idx
1539 && (difftime (now
, samples
[first_idx
].sample_time
)
1540 >= 15.0*60 + 2*DBL_EPSILON
*now
))
1541 first_idx
= buf_next (first_idx
);
1544 for (elem
= 0; elem
< nelem
; elem
++)
1546 double avg
= getavg (elem
);
1550 loadavg
[elem
] = avg
;
1556 /* Emulate getpwuid, getpwnam and others. */
1558 #define PASSWD_FIELD_SIZE 256
1560 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1561 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1562 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1563 static char dflt_passwd_dir
[MAX_UTF8_PATH
];
1564 static char dflt_passwd_shell
[MAX_UTF8_PATH
];
1566 static struct passwd dflt_passwd
=
1578 static char dflt_group_name
[GNLEN
+1];
1580 static struct group dflt_group
=
1582 /* When group information is not available, we return this as the
1583 group for all files. */
1591 return dflt_passwd
.pw_uid
;
1597 /* I could imagine arguing for checking to see whether the user is
1598 in the Administrators group and returning a UID of 0 for that
1599 case, but I don't know how wise that would be in the long run. */
1606 return dflt_passwd
.pw_gid
;
1616 getpwuid (unsigned uid
)
1618 if (uid
== dflt_passwd
.pw_uid
)
1619 return &dflt_passwd
;
1624 getgrgid (gid_t gid
)
1630 getpwnam (char *name
)
1634 pw
= getpwuid (getuid ());
1638 if (xstrcasecmp (name
, pw
->pw_name
))
1645 init_user_info (void)
1647 /* Find the user's real name by opening the process token and
1648 looking up the name associated with the user-sid in that token.
1650 Use the relative portion of the identifier authority value from
1651 the user-sid as the user id value (same for group id using the
1652 primary group sid from the process token). */
1654 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1655 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1656 DWORD glength
= sizeof (gname
);
1657 HANDLE token
= NULL
;
1658 SID_NAME_USE user_type
;
1659 unsigned char *buf
= NULL
;
1661 TOKEN_USER user_token
;
1662 TOKEN_PRIMARY_GROUP group_token
;
1665 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1668 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1669 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1671 buf
= xmalloc (blen
);
1672 result
= get_token_information (token
, TokenUser
,
1673 (LPVOID
)buf
, blen
, &needed
);
1676 memcpy (&user_token
, buf
, sizeof (user_token
));
1677 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1679 domain
, &dlength
, &user_type
);
1687 strcpy (dflt_passwd
.pw_name
, uname
);
1688 /* Determine a reasonable uid value. */
1689 if (xstrcasecmp ("administrator", uname
) == 0)
1691 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1692 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1696 /* Use the last sub-authority value of the RID, the relative
1697 portion of the SID, as user/group ID. */
1698 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1700 /* Get group id and name. */
1701 result
= get_token_information (token
, TokenPrimaryGroup
,
1702 (LPVOID
)buf
, blen
, &needed
);
1703 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1705 buf
= xrealloc (buf
, blen
= needed
);
1706 result
= get_token_information (token
, TokenPrimaryGroup
,
1707 (LPVOID
)buf
, blen
, &needed
);
1711 memcpy (&group_token
, buf
, sizeof (group_token
));
1712 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1713 dlength
= sizeof (domain
);
1714 /* If we can get at the real Primary Group name, use that.
1715 Otherwise, the default group name was already set to
1716 "None" in globals_of_w32. */
1717 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1718 gname
, &glength
, NULL
, &dlength
,
1720 strcpy (dflt_group_name
, gname
);
1723 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1726 /* If security calls are not supported (presumably because we
1727 are running under Windows 9X), fallback to this: */
1728 else if (GetUserName (uname
, &ulength
))
1730 strcpy (dflt_passwd
.pw_name
, uname
);
1731 if (xstrcasecmp ("administrator", uname
) == 0)
1732 dflt_passwd
.pw_uid
= 0;
1734 dflt_passwd
.pw_uid
= 123;
1735 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1739 strcpy (dflt_passwd
.pw_name
, "unknown");
1740 dflt_passwd
.pw_uid
= 123;
1741 dflt_passwd
.pw_gid
= 123;
1743 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1745 /* Set dir and shell from environment variables. */
1746 if (w32_unicode_filenames
)
1748 wchar_t *home
= _wgetenv (L
"HOME");
1749 wchar_t *shell
= _wgetenv (L
"SHELL");
1751 /* Ensure HOME and SHELL are defined. */
1756 filename_from_utf16 (home
, dflt_passwd
.pw_dir
);
1757 filename_from_utf16 (shell
, dflt_passwd
.pw_shell
);
1761 char *home
= getenv ("HOME");
1762 char *shell
= getenv ("SHELL");
1768 filename_from_ansi (home
, dflt_passwd
.pw_dir
);
1769 filename_from_ansi (shell
, dflt_passwd
.pw_shell
);
1774 CloseHandle (token
);
1780 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1781 return ((rand () << 15) | rand ());
1790 /* Return the maximum length in bytes of a multibyte character
1791 sequence encoded in the current ANSI codepage. This is required to
1792 correctly walk the encoded file names one character at a time. */
1794 max_filename_mbslen (void)
1798 codepage_for_filenames (&cp_info
);
1799 return cp_info
.MaxCharSize
;
1802 /* Normalize filename by converting in-place all of its path
1803 separators to the separator specified by PATH_SEP. */
1806 normalize_filename (register char *fp
, char path_sep
)
1810 /* Always lower-case drive letters a-z, even if the filesystem
1811 preserves case in filenames.
1812 This is so filenames can be compared by string comparison
1813 functions that are case-sensitive. Even case-preserving filesystems
1814 do not distinguish case in drive letters. */
1817 if (*p2
== ':' && *fp
>= 'A' && *fp
<= 'Z')
1825 if (*fp
== '/' || *fp
== '\\')
1831 /* Destructively turn backslashes into slashes. */
1833 dostounix_filename (register char *p
)
1835 normalize_filename (p
, '/');
1838 /* Destructively turn slashes into backslashes. */
1840 unixtodos_filename (register char *p
)
1842 normalize_filename (p
, '\\');
1845 /* Remove all CR's that are followed by a LF.
1846 (From msdos.c...probably should figure out a way to share it,
1847 although this code isn't going to ever change.) */
1849 crlf_to_lf (register int n
, register unsigned char *buf
)
1851 unsigned char *np
= buf
;
1852 unsigned char *startp
= buf
;
1853 unsigned char *endp
= buf
+ n
;
1857 while (buf
< endp
- 1)
1861 if (*(++buf
) != 0x0a)
1872 /* Parse the root part of file name, if present. Return length and
1873 optionally store pointer to char after root. */
1875 parse_root (const char * name
, const char ** pPath
)
1877 const char * start
= name
;
1882 /* find the root name of the volume if given */
1883 if (isalpha (name
[0]) && name
[1] == ':')
1885 /* skip past drive specifier */
1887 if (IS_DIRECTORY_SEP (name
[0]))
1890 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1897 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1902 if (IS_DIRECTORY_SEP (name
[0]))
1909 return name
- start
;
1912 /* Get long base name for name; name is assumed to be absolute. */
1914 get_long_basename (char * name
, char * buf
, int size
)
1917 char fname_utf8
[MAX_UTF8_PATH
];
1921 /* Must be valid filename, no wild cards or other invalid characters. */
1922 if (strpbrk (name
, "*?|<>\""))
1925 if (w32_unicode_filenames
)
1927 wchar_t fname_utf16
[MAX_PATH
];
1928 WIN32_FIND_DATAW find_data_wide
;
1930 filename_to_utf16 (name
, fname_utf16
);
1931 dir_handle
= FindFirstFileW (fname_utf16
, &find_data_wide
);
1932 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1933 cstatus
= filename_from_utf16 (find_data_wide
.cFileName
, fname_utf8
);
1937 char fname_ansi
[MAX_PATH
];
1938 WIN32_FIND_DATAA find_data_ansi
;
1940 filename_to_ansi (name
, fname_ansi
);
1941 dir_handle
= FindFirstFileA (fname_ansi
, &find_data_ansi
);
1942 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1943 cstatus
= filename_from_ansi (find_data_ansi
.cFileName
, fname_utf8
);
1946 if (cstatus
== 0 && (len
= strlen (fname_utf8
)) < size
)
1947 memcpy (buf
, fname_utf8
, len
+ 1);
1951 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1952 FindClose (dir_handle
);
1957 /* Get long name for file, if possible (assumed to be absolute). */
1959 w32_get_long_filename (char * name
, char * buf
, int size
)
1964 char full
[ MAX_UTF8_PATH
];
1967 len
= strlen (name
);
1968 if (len
>= MAX_UTF8_PATH
)
1971 /* Use local copy for destructive modification. */
1972 memcpy (full
, name
, len
+1);
1973 unixtodos_filename (full
);
1975 /* Copy root part verbatim. */
1976 len
= parse_root (full
, (const char **)&p
);
1977 memcpy (o
, full
, len
);
1982 while (p
!= NULL
&& *p
)
1985 p
= strchr (q
, '\\');
1987 len
= get_long_basename (full
, o
, size
);
2010 w32_get_short_filename (char * name
, char * buf
, int size
)
2012 if (w32_unicode_filenames
)
2014 wchar_t name_utf16
[MAX_PATH
], short_name
[MAX_PATH
];
2015 unsigned int retval
;
2017 filename_to_utf16 (name
, name_utf16
);
2018 retval
= GetShortPathNameW (name_utf16
, short_name
, size
);
2019 if (retval
&& retval
< size
)
2020 filename_from_utf16 (short_name
, buf
);
2025 char name_ansi
[MAX_PATH
];
2027 filename_to_ansi (name
, name_ansi
);
2028 return GetShortPathNameA (name_ansi
, buf
, size
);
2033 is_unc_volume (const char *filename
)
2035 const char *ptr
= filename
;
2037 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
2040 if (strpbrk (ptr
+ 2, "*?|<>\"\\/"))
2046 /* Emulate the Posix unsetenv. */
2048 unsetenv (const char *name
)
2054 if (name
== NULL
|| *name
== '\0' || strchr (name
, '=') != NULL
)
2059 name_len
= strlen (name
);
2060 /* MS docs says an environment variable cannot be longer than 32K. */
2061 if (name_len
> 32767)
2066 /* It is safe to use 'alloca' with 32K size, since the stack is at
2067 least 2MB, and we set it to 8MB in the link command line. */
2068 var
= alloca (name_len
+ 2);
2069 strncpy (var
, name
, name_len
);
2070 var
[name_len
++] = '=';
2071 var
[name_len
] = '\0';
2072 return _putenv (var
);
2075 /* MS _putenv doesn't support removing a variable when the argument
2076 does not include the '=' character, so we fix that here. */
2078 sys_putenv (char *str
)
2080 const char *const name_end
= strchr (str
, '=');
2082 if (name_end
== NULL
)
2084 /* Remove the variable from the environment. */
2085 return unsetenv (str
);
2088 return _putenv (str
);
2091 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2094 w32_get_resource (char *key
, LPDWORD lpdwtype
)
2097 HKEY hrootkey
= NULL
;
2100 /* Check both the current user and the local machine to see if
2101 we have any resources. */
2103 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
2107 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
2108 && (lpvalue
= xmalloc (cbData
)) != NULL
2109 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
2111 RegCloseKey (hrootkey
);
2117 RegCloseKey (hrootkey
);
2120 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
2124 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
2125 && (lpvalue
= xmalloc (cbData
)) != NULL
2126 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
2128 RegCloseKey (hrootkey
);
2134 RegCloseKey (hrootkey
);
2141 init_environment (char ** argv
)
2143 static const char * const tempdirs
[] = {
2144 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2149 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
2151 /* Implementation note: This function explicitly works with ANSI
2152 file names, not with UTF-8 encoded file names. This is because
2153 this function pushes variables into the Emacs's environment, and
2154 the environment variables are always assumed to be in the
2155 locale-specific encoding. Do NOT call any functions that accept
2156 UTF-8 file names from this function! */
2158 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2159 temporary files and assume "/tmp" if $TMPDIR is unset, which
2160 will break on DOS/Windows. Refuse to work if we cannot find
2161 a directory, not even "c:/", usable for that purpose. */
2162 for (i
= 0; i
< imax
; i
++)
2164 const char *tmp
= tempdirs
[i
];
2167 tmp
= getenv (tmp
+ 1);
2168 /* Note that `access' can lie to us if the directory resides on a
2169 read-only filesystem, like CD-ROM or a write-protected floppy.
2170 The only way to be really sure is to actually create a file and
2171 see if it succeeds. But I think that's too much to ask. */
2173 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2174 if (tmp
&& sys_access (tmp
, D_OK
) == 0)
2176 char * var
= alloca (strlen (tmp
) + 8);
2177 sprintf (var
, "TMPDIR=%s", tmp
);
2178 _putenv (strdup (var
));
2185 Fcons (build_string ("no usable temporary directories found!!"),
2187 "While setting TMPDIR: ");
2189 /* Check for environment variables and use registry settings if they
2190 don't exist. Fallback on default values where applicable. */
2195 char locale_name
[32];
2196 char default_home
[MAX_PATH
];
2199 static const struct env_entry
2205 /* If the default value is NULL, we will use the value from the
2206 outside environment or the Registry, but will not push the
2207 variable into the Emacs environment if it is defined neither
2208 in the Registry nor in the outside environment. */
2210 {"PRELOAD_WINSOCK", NULL
},
2211 {"emacs_dir", "C:/emacs"},
2212 {"EMACSLOADPATH", NULL
},
2213 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2214 {"EMACSDATA", NULL
},
2215 {"EMACSPATH", NULL
},
2222 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
2224 /* We need to copy dflt_envvars[] and work on the copy because we
2225 don't want the dumped Emacs to inherit the values of
2226 environment variables we saw during dumping (which could be on
2227 a different system). The defaults above must be left intact. */
2228 struct env_entry env_vars
[N_ENV_VARS
];
2230 for (i
= 0; i
< N_ENV_VARS
; i
++)
2231 env_vars
[i
] = dflt_envvars
[i
];
2233 /* For backwards compatibility, check if a .emacs file exists in C:/
2234 If not, then we can try to default to the appdata directory under the
2235 user's profile, which is more likely to be writable. */
2236 if (sys_access ("C:/.emacs", F_OK
) != 0)
2238 HRESULT profile_result
;
2239 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2240 of Windows 95 and NT4 that have not been updated to include
2242 ShGetFolderPath_fn get_folder_path
;
2243 get_folder_path
= (ShGetFolderPath_fn
)
2244 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2246 if (get_folder_path
!= NULL
)
2248 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
2251 /* If we can't get the appdata dir, revert to old behavior. */
2252 if (profile_result
== S_OK
)
2254 env_vars
[0].def_value
= default_home
;
2260 /* Get default locale info and use it for LANG. */
2261 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
2262 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
2263 locale_name
, sizeof (locale_name
)))
2265 for (i
= 0; i
< N_ENV_VARS
; i
++)
2267 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
2269 env_vars
[i
].def_value
= locale_name
;
2275 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2277 /* Treat emacs_dir specially: set it unconditionally based on our
2281 char modname
[MAX_PATH
];
2283 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
2285 if ((p
= _mbsrchr (modname
, '\\')) == NULL
)
2289 if ((p
= _mbsrchr (modname
, '\\'))
2290 /* From bin means installed Emacs, from src means uninstalled. */
2291 && (xstrcasecmp (p
, "\\bin") == 0 || xstrcasecmp (p
, "\\src") == 0))
2293 char buf
[SET_ENV_BUF_SIZE
];
2294 int within_build_tree
= xstrcasecmp (p
, "\\src") == 0;
2297 for (p
= modname
; *p
; p
= CharNext (p
))
2298 if (*p
== '\\') *p
= '/';
2300 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
2301 _putenv (strdup (buf
));
2302 /* If we are running from the Posix-like build tree, define
2303 SHELL to point to our own cmdproxy. The loop below will
2304 then disregard PATH_EXEC and the default value. */
2305 if (within_build_tree
)
2307 _snprintf (buf
, sizeof (buf
) - 1,
2308 "SHELL=%s/nt/cmdproxy.exe", modname
);
2309 _putenv (strdup (buf
));
2314 for (i
= 0; i
< N_ENV_VARS
; i
++)
2316 if (!getenv (env_vars
[i
].name
))
2319 char bufc
[SET_ENV_BUF_SIZE
];
2321 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
2322 /* Also ignore empty environment variables. */
2327 if (strcmp (env_vars
[i
].name
, "SHELL") == 0)
2329 /* Look for cmdproxy.exe in every directory in
2330 PATH_EXEC. FIXME: This does not find cmdproxy
2331 in nt/ when we run uninstalled. */
2332 char fname
[MAX_PATH
];
2333 const char *pstart
= PATH_EXEC
, *pend
;
2336 pend
= _mbschr (pstart
, ';');
2338 pend
= pstart
+ strlen (pstart
);
2339 /* Be defensive against series of ;;; characters. */
2342 strncpy (fname
, pstart
, pend
- pstart
);
2343 fname
[pend
- pstart
] = '/';
2344 strcpy (&fname
[pend
- pstart
+ 1], "cmdproxy.exe");
2345 ExpandEnvironmentStrings ((LPSTR
) fname
, bufc
,
2347 if (sys_access (bufc
, F_OK
) == 0)
2360 /* If not found in any directory, use the
2361 default as the last resort. */
2362 lpval
= env_vars
[i
].def_value
;
2363 dwType
= REG_EXPAND_SZ
;
2369 lpval
= env_vars
[i
].def_value
;
2370 dwType
= REG_EXPAND_SZ
;
2372 if (strcmp (env_vars
[i
].name
, "HOME") == 0 && !appdata
)
2373 Vdelayed_warnings_list
2374 = Fcons (listn (CONSTYPE_HEAP
, 2,
2375 intern ("initialization"),
2376 build_string ("Setting HOME to C:\\ by default is deprecated")),
2377 Vdelayed_warnings_list
);
2382 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
2384 if (dwType
== REG_EXPAND_SZ
)
2385 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
2386 else if (dwType
== REG_SZ
)
2387 strcpy (buf1
, lpval
);
2388 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
2390 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
2392 _putenv (strdup (buf2
));
2402 /* Rebuild system configuration to reflect invoking system. */
2403 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
2405 /* Another special case: on NT, the PATH variable is actually named
2406 "Path" although cmd.exe (perhaps NT itself) arranges for
2407 environment variable lookup and setting to be case insensitive.
2408 However, Emacs assumes a fully case sensitive environment, so we
2409 need to change "Path" to "PATH" to match the expectations of
2410 various elisp packages. We do this by the sneaky method of
2411 modifying the string in the C runtime environ entry.
2413 The same applies to COMSPEC. */
2417 for (envp
= environ
; *envp
; envp
++)
2418 if (_strnicmp (*envp
, "PATH=", 5) == 0)
2419 memcpy (*envp
, "PATH=", 5);
2420 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
2421 memcpy (*envp
, "COMSPEC=", 8);
2424 /* Remember the initial working directory for getcwd. */
2425 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2426 Does it matter anywhere in Emacs? */
2427 if (w32_unicode_filenames
)
2429 wchar_t wstartup_dir
[MAX_PATH
];
2431 if (!GetCurrentDirectoryW (MAX_PATH
, wstartup_dir
))
2433 filename_from_utf16 (wstartup_dir
, startup_dir
);
2437 char astartup_dir
[MAX_PATH
];
2439 if (!GetCurrentDirectoryA (MAX_PATH
, astartup_dir
))
2441 filename_from_ansi (astartup_dir
, startup_dir
);
2445 static char modname
[MAX_PATH
];
2447 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
2452 /* Determine if there is a middle mouse button, to allow parse_button
2453 to decide whether right mouse events should be mouse-2 or
2455 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
2460 /* Called from expand-file-name when default-directory is not a string. */
2463 emacs_root_dir (void)
2465 static char root_dir
[MAX_UTF8_PATH
];
2468 p
= getenv ("emacs_dir");
2471 filename_from_ansi (p
, root_dir
);
2472 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
2473 dostounix_filename (root_dir
);
2477 #include <sys/timeb.h>
2479 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2481 gettimeofday (struct timeval
*__restrict tv
, struct timezone
*__restrict tz
)
2486 tv
->tv_sec
= tb
.time
;
2487 tv
->tv_usec
= tb
.millitm
* 1000L;
2488 /* Implementation note: _ftime sometimes doesn't update the dstflag
2489 according to the new timezone when the system timezone is
2490 changed. We could fix that by using GetSystemTime and
2491 GetTimeZoneInformation, but that doesn't seem necessary, since
2492 Emacs always calls gettimeofday with the 2nd argument NULL (see
2493 current_emacs_time). */
2496 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
2497 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
2502 /* Emulate fdutimens. */
2504 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2505 TIMESPEC[0] and TIMESPEC[1], respectively.
2506 FD must be either negative -- in which case it is ignored --
2507 or a file descriptor that is open on FILE.
2508 If FD is nonnegative, then FILE can be NULL, which means
2509 use just futimes instead of utimes.
2510 If TIMESPEC is null, FAIL.
2511 Return 0 on success, -1 (setting errno) on failure. */
2514 fdutimens (int fd
, char const *file
, struct timespec
const timespec
[2])
2521 if (fd
< 0 && !file
)
2526 /* _futime's prototype defines 2nd arg as having the type 'struct
2527 _utimbuf', while utime needs to accept 'struct utimbuf' for
2528 compatibility with Posix. So we need to use 2 different (but
2529 equivalent) types to avoid compiler warnings, sigh. */
2532 struct _utimbuf _ut
;
2534 _ut
.actime
= timespec
[0].tv_sec
;
2535 _ut
.modtime
= timespec
[1].tv_sec
;
2536 return _futime (fd
, &_ut
);
2542 ut
.actime
= timespec
[0].tv_sec
;
2543 ut
.modtime
= timespec
[1].tv_sec
;
2544 /* Call 'utime', which is implemented below, not the MS library
2545 function, which fails on directories. */
2546 return utime (file
, &ut
);
2551 /* ------------------------------------------------------------------------- */
2552 /* IO support and wrapper functions for the Windows API. */
2553 /* ------------------------------------------------------------------------- */
2555 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2556 on network directories, so we handle that case here.
2557 (Ulrich Leodolter, 1/11/95). */
2559 sys_ctime (const time_t *t
)
2561 char *str
= (char *) ctime (t
);
2562 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2565 /* Emulate sleep...we could have done this with a define, but that
2566 would necessitate including windows.h in the files that used it.
2567 This is much easier. */
2569 sys_sleep (int seconds
)
2571 Sleep (seconds
* 1000);
2574 /* Internal MSVC functions for low-level descriptor munging */
2575 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2576 extern int __cdecl
_free_osfhnd (int fd
);
2578 /* parallel array of private info on file handles */
2579 filedesc fd_info
[ MAXDESC
];
2581 typedef struct volume_info_data
{
2582 struct volume_info_data
* next
;
2584 /* time when info was obtained */
2587 /* actual volume info */
2596 /* Global referenced by various functions. */
2597 static volume_info_data volume_info
;
2599 /* Vector to indicate which drives are local and fixed (for which cached
2600 data never expires). */
2601 static BOOL fixed_drives
[26];
2603 /* Consider cached volume information to be stale if older than 10s,
2604 at least for non-local drives. Info for fixed drives is never stale. */
2605 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2606 #define VOLINFO_STILL_VALID( root_dir, info ) \
2607 ( ( isalpha (root_dir[0]) && \
2608 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2609 || GetTickCount () - info->timestamp < 10000 )
2611 /* Cache support functions. */
2613 /* Simple linked list with linear search is sufficient. */
2614 static volume_info_data
*volume_cache
= NULL
;
2616 static volume_info_data
*
2617 lookup_volume_info (char * root_dir
)
2619 volume_info_data
* info
;
2621 for (info
= volume_cache
; info
; info
= info
->next
)
2622 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2628 add_volume_info (char * root_dir
, volume_info_data
* info
)
2630 info
->root_dir
= xstrdup (root_dir
);
2631 unixtodos_filename (info
->root_dir
);
2632 info
->next
= volume_cache
;
2633 volume_cache
= info
;
2637 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2638 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2639 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2640 static volume_info_data
*
2641 GetCachedVolumeInformation (char * root_dir
)
2643 volume_info_data
* info
;
2644 char default_root
[ MAX_UTF8_PATH
];
2645 char name
[MAX_PATH
+1];
2646 char type
[MAX_PATH
+1];
2648 /* NULL for root_dir means use root from current directory. */
2649 if (root_dir
== NULL
)
2651 if (w32_unicode_filenames
)
2653 wchar_t curdirw
[MAX_PATH
];
2655 if (GetCurrentDirectoryW (MAX_PATH
, curdirw
) == 0)
2657 filename_from_utf16 (curdirw
, default_root
);
2661 char curdira
[MAX_PATH
];
2663 if (GetCurrentDirectoryA (MAX_PATH
, curdira
) == 0)
2665 filename_from_ansi (curdira
, default_root
);
2667 parse_root (default_root
, (const char **)&root_dir
);
2669 root_dir
= default_root
;
2672 /* Local fixed drives can be cached permanently. Removable drives
2673 cannot be cached permanently, since the volume name and serial
2674 number (if nothing else) can change. Remote drives should be
2675 treated as if they are removable, since there is no sure way to
2676 tell whether they are or not. Also, the UNC association of drive
2677 letters mapped to remote volumes can be changed at any time (even
2678 by other processes) without notice.
2680 As a compromise, so we can benefit from caching info for remote
2681 volumes, we use a simple expiry mechanism to invalidate cache
2682 entries that are more than ten seconds old. */
2685 /* No point doing this, because WNetGetConnection is even slower than
2686 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2687 GetDriveType is about the only call of this type which does not
2688 involve network access, and so is extremely quick). */
2690 /* Map drive letter to UNC if remote. */
2691 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2693 char remote_name
[ 256 ];
2694 char drive
[3] = { root_dir
[0], ':' };
2696 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2698 /* do something */ ;
2702 info
= lookup_volume_info (root_dir
);
2704 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2710 /* Info is not cached, or is stale. */
2711 if (w32_unicode_filenames
)
2713 wchar_t root_w
[MAX_PATH
];
2714 wchar_t name_w
[MAX_PATH
+1];
2715 wchar_t type_w
[MAX_PATH
+1];
2717 filename_to_utf16 (root_dir
, root_w
);
2718 if (!GetVolumeInformationW (root_w
,
2719 name_w
, sizeof (name_w
),
2723 type_w
, sizeof (type_w
)))
2725 /* Hmm... not really 100% correct, as these 2 are not file
2727 filename_from_utf16 (name_w
, name
);
2728 filename_from_utf16 (type_w
, type
);
2732 char root_a
[MAX_PATH
];
2733 char name_a
[MAX_PATH
+1];
2734 char type_a
[MAX_PATH
+1];
2736 filename_to_ansi (root_dir
, root_a
);
2737 if (!GetVolumeInformationA (root_a
,
2738 name_a
, sizeof (name_a
),
2742 type_a
, sizeof (type_a
)))
2744 filename_from_ansi (name_a
, name
);
2745 filename_from_ansi (type_a
, type
);
2748 /* Cache the volume information for future use, overwriting existing
2749 entry if present. */
2752 info
= xmalloc (sizeof (volume_info_data
));
2753 add_volume_info (root_dir
, info
);
2761 info
->name
= xstrdup (name
);
2762 unixtodos_filename (info
->name
);
2763 info
->serialnum
= serialnum
;
2764 info
->maxcomp
= maxcomp
;
2765 info
->flags
= flags
;
2766 info
->type
= xstrdup (type
);
2767 info
->timestamp
= GetTickCount ();
2773 /* Get information on the volume where NAME is held; set path pointer to
2774 start of pathname in NAME (past UNC header\volume header if present),
2775 if pPath is non-NULL.
2777 Note: if NAME includes symlinks, the information is for the volume
2778 of the symlink, not of its target. That's because, even though
2779 GetVolumeInformation returns information about the symlink target
2780 of its argument, we only pass the root directory to
2781 GetVolumeInformation, not the full NAME. */
2783 get_volume_info (const char * name
, const char ** pPath
)
2785 char temp
[MAX_UTF8_PATH
];
2786 char *rootname
= NULL
; /* default to current volume */
2787 volume_info_data
* info
;
2788 int root_len
= parse_root (name
, pPath
);
2793 /* Copy the root name of the volume, if given. */
2796 strncpy (temp
, name
, root_len
);
2797 temp
[root_len
] = '\0';
2798 unixtodos_filename (temp
);
2802 info
= GetCachedVolumeInformation (rootname
);
2805 /* Set global referenced by other functions. */
2806 volume_info
= *info
;
2812 /* Determine if volume is FAT format (ie. only supports short 8.3
2813 names); also set path pointer to start of pathname in name, if
2814 pPath is non-NULL. */
2816 is_fat_volume (const char * name
, const char ** pPath
)
2818 if (get_volume_info (name
, pPath
))
2819 return (volume_info
.maxcomp
== 12);
2823 /* Convert all slashes in a filename to backslashes, and map filename
2824 to a valid 8.3 name if necessary. The result is a pointer to a
2825 static buffer, so CAVEAT EMPTOR! */
2827 map_w32_filename (const char * name
, const char ** pPath
)
2829 static char shortname
[MAX_UTF8_PATH
];
2830 char * str
= shortname
;
2833 const char * save_name
= name
;
2835 if (strlen (name
) >= sizeof (shortname
))
2837 /* Return a filename which will cause callers to fail. */
2838 strcpy (shortname
, "?");
2842 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2844 register int left
= 8; /* maximum number of chars in part */
2845 register int extn
= 0; /* extension added? */
2846 register int dots
= 2; /* maximum number of dots allowed */
2849 *str
++ = *name
++; /* skip past UNC header */
2851 while ((c
= *name
++))
2858 *str
++ = (c
== ':' ? ':' : '\\');
2859 extn
= 0; /* reset extension flags */
2860 dots
= 2; /* max 2 dots */
2861 left
= 8; /* max length 8 for main part */
2866 /* Convert path components of the form .xxx to _xxx,
2867 but leave . and .. as they are. This allows .emacs
2868 to be read as _emacs, for example. */
2872 IS_DIRECTORY_SEP (*name
))
2887 extn
= 1; /* we've got an extension */
2888 left
= 3; /* 3 chars in extension */
2892 /* any embedded dots after the first are converted to _ */
2897 case '#': /* don't lose these, they're important */
2899 str
[-1] = c
; /* replace last character of part */
2902 if ( left
&& 'A' <= c
&& c
<= 'Z' )
2904 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2906 dots
= 0; /* started a path component */
2915 strcpy (shortname
, name
);
2916 unixtodos_filename (shortname
);
2920 *pPath
= shortname
+ (path
- save_name
);
2926 is_exec (const char * name
)
2928 char * p
= strrchr (name
, '.');
2931 && (xstrcasecmp (p
, ".exe") == 0 ||
2932 xstrcasecmp (p
, ".com") == 0 ||
2933 xstrcasecmp (p
, ".bat") == 0 ||
2934 xstrcasecmp (p
, ".cmd") == 0));
2937 /* Emulate the Unix directory procedures opendir, closedir, and
2938 readdir. We rename them to sys_* names because some versions of
2939 MinGW startup code call opendir and readdir to glob wildcards, and
2940 the code that calls them doesn't grok UTF-8 encoded file names we
2941 produce in dirent->d_name[]. */
2943 struct dirent dir_static
; /* simulated directory contents */
2944 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2945 static int dir_is_fat
;
2946 static char dir_pathname
[MAX_UTF8_PATH
];
2947 static WIN32_FIND_DATAW dir_find_data_w
;
2948 static WIN32_FIND_DATAA dir_find_data_a
;
2950 /* Support shares on a network resource as subdirectories of a read-only
2952 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2953 static HANDLE
open_unc_volume (const char *);
2954 static void *read_unc_volume (HANDLE
, wchar_t *, char *, int);
2955 static void close_unc_volume (HANDLE
);
2958 sys_opendir (const char *filename
)
2962 /* Opening is done by FindFirstFile. However, a read is inherent to
2963 this operation, so we defer the open until read time. */
2965 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2967 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2970 /* Note: We don't support traversal of UNC volumes via symlinks.
2971 Doing so would mean punishing 99.99% of use cases by resolving
2972 all the possible symlinks in FILENAME, recursively. */
2973 if (is_unc_volume (filename
))
2975 wnet_enum_handle
= open_unc_volume (filename
);
2976 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2980 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2987 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAX_UTF8_PATH
- 1);
2988 dir_pathname
[MAX_UTF8_PATH
- 1] = '\0';
2989 /* Note: We don't support symlinks to file names on FAT volumes.
2990 Doing so would mean punishing 99.99% of use cases by resolving
2991 all the possible symlinks in FILENAME, recursively. */
2992 dir_is_fat
= is_fat_volume (filename
, NULL
);
2998 sys_closedir (DIR *dirp
)
3000 /* If we have a find-handle open, close it. */
3001 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
3003 FindClose (dir_find_handle
);
3004 dir_find_handle
= INVALID_HANDLE_VALUE
;
3006 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
3008 close_unc_volume (wnet_enum_handle
);
3009 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
3011 xfree ((char *) dirp
);
3015 sys_readdir (DIR *dirp
)
3017 int downcase
= !NILP (Vw32_downcase_file_names
);
3019 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
3021 if (!read_unc_volume (wnet_enum_handle
,
3022 dir_find_data_w
.cFileName
,
3023 dir_find_data_a
.cFileName
,
3027 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3028 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
3030 char filename
[MAX_UTF8_PATH
+ 2];
3033 strcpy (filename
, dir_pathname
);
3034 ln
= strlen (filename
) - 1;
3035 if (!IS_DIRECTORY_SEP (filename
[ln
]))
3036 strcat (filename
, "\\");
3037 strcat (filename
, "*");
3039 /* Note: No need to resolve symlinks in FILENAME, because
3040 FindFirst opens the directory that is the target of a
3042 if (w32_unicode_filenames
)
3044 wchar_t fnw
[MAX_PATH
];
3046 filename_to_utf16 (filename
, fnw
);
3047 dir_find_handle
= FindFirstFileW (fnw
, &dir_find_data_w
);
3053 filename_to_ansi (filename
, fna
);
3054 dir_find_handle
= FindFirstFileA (fna
, &dir_find_data_a
);
3057 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
3060 else if (w32_unicode_filenames
)
3062 if (!FindNextFileW (dir_find_handle
, &dir_find_data_w
))
3067 if (!FindNextFileA (dir_find_handle
, &dir_find_data_a
))
3071 /* Emacs never uses this value, so don't bother making it match
3072 value returned by stat(). */
3073 dir_static
.d_ino
= 1;
3075 if (w32_unicode_filenames
)
3077 if (downcase
|| dir_is_fat
)
3079 wchar_t tem
[MAX_PATH
];
3081 wcscpy (tem
, dir_find_data_w
.cFileName
);
3083 filename_from_utf16 (tem
, dir_static
.d_name
);
3086 filename_from_utf16 (dir_find_data_w
.cFileName
, dir_static
.d_name
);
3092 /* If the file name in cFileName[] includes `?' characters, it
3093 means the original file name used characters that cannot be
3094 represented by the current ANSI codepage. To avoid total
3095 lossage, retrieve the short 8+3 alias of the long file
3097 if (_mbspbrk (dir_find_data_a
.cFileName
, "?"))
3099 strcpy (tem
, dir_find_data_a
.cAlternateFileName
);
3100 /* 8+3 aliases are returned in all caps, which could break
3101 various alists that look at filenames' extensions. */
3104 else if (downcase
|| dir_is_fat
)
3105 strcpy (tem
, dir_find_data_a
.cFileName
);
3107 filename_from_ansi (dir_find_data_a
.cFileName
, dir_static
.d_name
);
3108 if (downcase
|| dir_is_fat
)
3111 filename_from_ansi (tem
, dir_static
.d_name
);
3115 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
3116 dir_static
.d_reclen
= sizeof (struct dirent
) - MAX_UTF8_PATH
+ 3 +
3117 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
3123 open_unc_volume (const char *path
)
3125 const char *fn
= map_w32_filename (path
, NULL
);
3129 if (w32_unicode_filenames
)
3132 wchar_t fnw
[MAX_PATH
];
3134 nrw
.dwScope
= RESOURCE_GLOBALNET
;
3135 nrw
.dwType
= RESOURCETYPE_DISK
;
3136 nrw
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
3137 nrw
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3138 nrw
.lpLocalName
= NULL
;
3139 filename_to_utf16 (fn
, fnw
);
3140 nrw
.lpRemoteName
= fnw
;
3141 nrw
.lpComment
= NULL
;
3142 nrw
.lpProvider
= NULL
;
3144 result
= WNetOpenEnumW (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
3145 RESOURCEUSAGE_CONNECTABLE
, &nrw
, &henum
);
3152 nra
.dwScope
= RESOURCE_GLOBALNET
;
3153 nra
.dwType
= RESOURCETYPE_DISK
;
3154 nra
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
3155 nra
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3156 nra
.lpLocalName
= NULL
;
3157 filename_to_ansi (fn
, fna
);
3158 nra
.lpRemoteName
= fna
;
3159 nra
.lpComment
= NULL
;
3160 nra
.lpProvider
= NULL
;
3162 result
= WNetOpenEnumA (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
3163 RESOURCEUSAGE_CONNECTABLE
, &nra
, &henum
);
3165 if (result
== NO_ERROR
)
3168 return INVALID_HANDLE_VALUE
;
3172 read_unc_volume (HANDLE henum
, wchar_t *fname_w
, char *fname_a
, int size
)
3177 DWORD bufsize
= 512;
3181 if (w32_unicode_filenames
)
3186 buffer
= alloca (bufsize
);
3187 result
= WNetEnumResourceW (henum
, &count
, buffer
, &bufsize
);
3188 if (result
!= NO_ERROR
)
3190 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3191 ptrw
= ((LPNETRESOURCEW
) buffer
)->lpRemoteName
;
3193 while (*ptrw
&& *ptrw
!= L
'/' && *ptrw
!= L
'\\') ptrw
++;
3195 wcsncpy (fname_w
, ptrw
, size
);
3200 int dbcs_p
= max_filename_mbslen () > 1;
3203 buffer
= alloca (bufsize
);
3204 result
= WNetEnumResourceA (henum
, &count
, buffer
, &bufsize
);
3205 if (result
!= NO_ERROR
)
3207 ptra
= ((LPNETRESOURCEA
) buffer
)->lpRemoteName
;
3210 while (*ptra
&& !IS_DIRECTORY_SEP (*ptra
)) ptra
++;
3213 while (*ptra
&& !IS_DIRECTORY_SEP (*ptra
))
3214 ptra
= CharNextExA (file_name_codepage
, ptra
, 0);
3217 strncpy (fname_a
, ptra
, size
);
3225 close_unc_volume (HANDLE henum
)
3227 if (henum
!= INVALID_HANDLE_VALUE
)
3228 WNetCloseEnum (henum
);
3232 unc_volume_file_attributes (const char *path
)
3237 henum
= open_unc_volume (path
);
3238 if (henum
== INVALID_HANDLE_VALUE
)
3241 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
3243 close_unc_volume (henum
);
3248 /* Ensure a network connection is authenticated. */
3250 logon_network_drive (const char *path
)
3252 char share
[MAX_UTF8_PATH
];
3259 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
3260 drvtype
= DRIVE_REMOTE
;
3261 else if (path
[0] == '\0' || path
[1] != ':')
3262 drvtype
= GetDriveType (NULL
);
3269 drvtype
= GetDriveType (drive
);
3272 /* Only logon to networked drives. */
3273 if (drvtype
!= DRIVE_REMOTE
)
3277 strncpy (share
, path
, MAX_UTF8_PATH
);
3278 /* Truncate to just server and share name. */
3279 for (p
= share
+ 2; *p
&& p
< share
+ MAX_UTF8_PATH
; p
++)
3281 if (IS_DIRECTORY_SEP (*p
) && ++n_slashes
> 3)
3288 if (w32_unicode_filenames
)
3290 NETRESOURCEW resourcew
;
3291 wchar_t share_w
[MAX_PATH
];
3293 resourcew
.dwScope
= RESOURCE_GLOBALNET
;
3294 resourcew
.dwType
= RESOURCETYPE_DISK
;
3295 resourcew
.dwDisplayType
= RESOURCEDISPLAYTYPE_SHARE
;
3296 resourcew
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3297 resourcew
.lpLocalName
= NULL
;
3298 filename_to_utf16 (share
, share_w
);
3299 resourcew
.lpRemoteName
= share_w
;
3300 resourcew
.lpProvider
= NULL
;
3302 val
= WNetAddConnection2W (&resourcew
, NULL
, NULL
, CONNECT_INTERACTIVE
);
3306 NETRESOURCEA resourcea
;
3307 char share_a
[MAX_PATH
];
3309 resourcea
.dwScope
= RESOURCE_GLOBALNET
;
3310 resourcea
.dwType
= RESOURCETYPE_DISK
;
3311 resourcea
.dwDisplayType
= RESOURCEDISPLAYTYPE_SHARE
;
3312 resourcea
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3313 resourcea
.lpLocalName
= NULL
;
3314 filename_to_ansi (share
, share_a
);
3315 resourcea
.lpRemoteName
= share_a
;
3316 resourcea
.lpProvider
= NULL
;
3318 val
= WNetAddConnection2A (&resourcea
, NULL
, NULL
, CONNECT_INTERACTIVE
);
3324 case ERROR_ALREADY_ASSIGNED
:
3326 case ERROR_ACCESS_DENIED
:
3327 case ERROR_LOGON_FAILURE
:
3333 case ERROR_BAD_NET_NAME
:
3334 case ERROR_NO_NET_OR_BAD_PATH
:
3335 case ERROR_NO_NETWORK
:
3336 case ERROR_CANCELLED
:
3343 /* Emulate faccessat(2). */
3345 faccessat (int dirfd
, const char * path
, int mode
, int flags
)
3349 if (dirfd
!= AT_FDCWD
3350 && !(IS_DIRECTORY_SEP (path
[0])
3351 || IS_DEVICE_SEP (path
[1])))
3357 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3358 newer versions blow up when passed D_OK. */
3359 path
= map_w32_filename (path
, NULL
);
3360 /* If the last element of PATH is a symlink, we need to resolve it
3361 to get the attributes of its target file. Note: any symlinks in
3362 PATH elements other than the last one are transparently resolved
3363 by GetFileAttributes below. */
3364 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0
3365 && (flags
& AT_SYMLINK_NOFOLLOW
) == 0)
3366 path
= chase_symlinks (path
);
3368 if (w32_unicode_filenames
)
3370 wchar_t path_w
[MAX_PATH
];
3372 filename_to_utf16 (path
, path_w
);
3373 attributes
= GetFileAttributesW (path_w
);
3377 char path_a
[MAX_PATH
];
3379 filename_to_ansi (path
, path_a
);
3380 attributes
= GetFileAttributesA (path_a
);
3383 if (attributes
== -1)
3385 DWORD w32err
= GetLastError ();
3389 case ERROR_INVALID_NAME
:
3390 case ERROR_BAD_PATHNAME
:
3391 if (is_unc_volume (path
))
3393 attributes
= unc_volume_file_attributes (path
);
3394 if (attributes
== -1)
3402 case ERROR_FILE_NOT_FOUND
:
3403 case ERROR_BAD_NETPATH
:
3412 if ((mode
& X_OK
) != 0
3413 && !(is_exec (path
) || (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0))
3418 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
3423 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
3431 /* A version of 'access' to be used locally with file names in
3432 locale-specific encoding. Does not resolve symlinks and does not
3433 support file names on FAT12 and FAT16 volumes, but that's OK, since
3434 we only invoke this function for files inside the Emacs source or
3435 installation tree, on directories (so any symlinks should have the
3436 directory bit set), and on short file names such as "C:/.emacs". */
3438 sys_access (const char *fname
, int mode
)
3440 char fname_copy
[MAX_PATH
], *p
;
3443 strcpy (fname_copy
, fname
);
3444 /* Do the equivalent of unixtodos_filename. */
3445 for (p
= fname_copy
; *p
; p
= CharNext (p
))
3449 if ((attributes
= GetFileAttributesA (fname_copy
)) == -1)
3451 DWORD w32err
= GetLastError ();
3455 case ERROR_INVALID_NAME
:
3456 case ERROR_BAD_PATHNAME
:
3457 case ERROR_FILE_NOT_FOUND
:
3458 case ERROR_BAD_NETPATH
:
3467 if ((mode
& X_OK
) != 0
3468 && !(is_exec (fname_copy
)
3469 || (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0))
3474 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
3479 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
3487 /* Shadow some MSVC runtime functions to map requests for long filenames
3488 to reasonable short names if necessary. This was originally added to
3489 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3493 sys_chdir (const char * path
)
3495 path
= map_w32_filename (path
, NULL
);
3496 if (w32_unicode_filenames
)
3498 wchar_t newdir_w
[MAX_PATH
];
3500 if (filename_to_utf16 (path
, newdir_w
) == 0)
3501 return _wchdir (newdir_w
);
3506 char newdir_a
[MAX_PATH
];
3508 if (filename_to_ansi (path
, newdir_a
) == 0)
3509 return _chdir (newdir_a
);
3515 sys_chmod (const char * path
, int mode
)
3517 path
= chase_symlinks (map_w32_filename (path
, NULL
));
3518 if (w32_unicode_filenames
)
3520 wchar_t path_w
[MAX_PATH
];
3522 filename_to_utf16 (path
, path_w
);
3523 return _wchmod (path_w
, mode
);
3527 char path_a
[MAX_PATH
];
3529 filename_to_ansi (path
, path_a
);
3530 return _chmod (path_a
, mode
);
3535 sys_creat (const char * path
, int mode
)
3537 path
= map_w32_filename (path
, NULL
);
3538 if (w32_unicode_filenames
)
3540 wchar_t path_w
[MAX_PATH
];
3542 filename_to_utf16 (path
, path_w
);
3543 return _wcreat (path_w
, mode
);
3547 char path_a
[MAX_PATH
];
3549 filename_to_ansi (path
, path_a
);
3550 return _creat (path_a
, mode
);
3555 sys_fopen (const char * path
, const char * mode
)
3559 const char * mode_save
= mode
;
3561 /* Force all file handles to be non-inheritable. This is necessary to
3562 ensure child processes don't unwittingly inherit handles that might
3563 prevent future file access. */
3567 else if (mode
[0] == 'w' || mode
[0] == 'a')
3568 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
3572 /* Only do simplistic option parsing. */
3576 oflag
&= ~(O_RDONLY
| O_WRONLY
);
3579 else if (mode
[0] == 'b')
3584 else if (mode
[0] == 't')
3591 path
= map_w32_filename (path
, NULL
);
3592 if (w32_unicode_filenames
)
3594 wchar_t path_w
[MAX_PATH
];
3596 filename_to_utf16 (path
, path_w
);
3597 fd
= _wopen (path_w
, oflag
| _O_NOINHERIT
, 0644);
3601 char path_a
[MAX_PATH
];
3603 filename_to_ansi (path
, path_a
);
3604 fd
= _open (path_a
, oflag
| _O_NOINHERIT
, 0644);
3609 return _fdopen (fd
, mode_save
);
3612 /* This only works on NTFS volumes, but is useful to have. */
3614 sys_link (const char * old
, const char * new)
3618 char oldname
[MAX_UTF8_PATH
], newname
[MAX_UTF8_PATH
];
3619 wchar_t oldname_w
[MAX_PATH
];
3620 char oldname_a
[MAX_PATH
];
3622 if (old
== NULL
|| new == NULL
)
3628 strcpy (oldname
, map_w32_filename (old
, NULL
));
3629 strcpy (newname
, map_w32_filename (new, NULL
));
3631 if (w32_unicode_filenames
)
3633 filename_to_utf16 (oldname
, oldname_w
);
3634 fileh
= CreateFileW (oldname_w
, 0, 0, NULL
, OPEN_EXISTING
,
3635 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
3639 filename_to_ansi (oldname
, oldname_a
);
3640 fileh
= CreateFileA (oldname_a
, 0, 0, NULL
, OPEN_EXISTING
,
3641 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
3643 if (fileh
!= INVALID_HANDLE_VALUE
)
3647 /* Confusingly, the "alternate" stream name field does not apply
3648 when restoring a hard link, and instead contains the actual
3649 stream data for the link (ie. the name of the link to create).
3650 The WIN32_STREAM_ID structure before the cStreamName field is
3651 the stream header, which is then immediately followed by the
3655 WIN32_STREAM_ID wid
;
3656 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
3659 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
3660 indicates that flag is unsupported for CP_UTF8, and OTOH says
3661 it is the default anyway. */
3662 wlen
= MultiByteToWideChar (CP_UTF8
, 0, newname
, -1,
3663 data
.wid
.cStreamName
, MAX_PATH
);
3666 LPVOID context
= NULL
;
3669 data
.wid
.dwStreamId
= BACKUP_LINK
;
3670 data
.wid
.dwStreamAttributes
= 0;
3671 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
3672 data
.wid
.Size
.HighPart
= 0;
3673 data
.wid
.dwStreamNameSize
= 0;
3675 if (BackupWrite (fileh
, (LPBYTE
)&data
,
3676 offsetof (WIN32_STREAM_ID
, cStreamName
)
3677 + data
.wid
.Size
.LowPart
,
3678 &wbytes
, FALSE
, FALSE
, &context
)
3679 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
3686 DWORD err
= GetLastError ();
3691 case ERROR_ACCESS_DENIED
:
3692 /* This is what happens when OLDNAME is a directory,
3693 since Windows doesn't support hard links to
3694 directories. Posix says to set errno to EPERM in
3696 if (w32_unicode_filenames
)
3697 attributes
= GetFileAttributesW (oldname_w
);
3699 attributes
= GetFileAttributesA (oldname_a
);
3700 if (attributes
!= -1
3701 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0)
3703 else if (attributes
== -1
3704 && is_unc_volume (oldname
)
3705 && unc_volume_file_attributes (oldname
) != -1)
3710 case ERROR_TOO_MANY_LINKS
:
3713 case ERROR_NOT_SAME_DEVICE
:
3723 CloseHandle (fileh
);
3732 sys_mkdir (const char * path
)
3734 path
= map_w32_filename (path
, NULL
);
3736 if (w32_unicode_filenames
)
3738 wchar_t path_w
[MAX_PATH
];
3740 filename_to_utf16 (path
, path_w
);
3741 return _wmkdir (path_w
);
3745 char path_a
[MAX_PATH
];
3747 filename_to_ansi (path
, path_a
);
3748 return _mkdir (path_a
);
3753 sys_open (const char * path
, int oflag
, int mode
)
3755 const char* mpath
= map_w32_filename (path
, NULL
);
3758 if (w32_unicode_filenames
)
3760 wchar_t mpath_w
[MAX_PATH
];
3762 filename_to_utf16 (mpath
, mpath_w
);
3763 /* If possible, try to open file without _O_CREAT, to be able to
3764 write to existing hidden and system files. Force all file
3765 handles to be non-inheritable. */
3766 if ((oflag
& (_O_CREAT
| _O_EXCL
)) != (_O_CREAT
| _O_EXCL
))
3767 res
= _wopen (mpath_w
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3769 res
= _wopen (mpath_w
, oflag
| _O_NOINHERIT
, mode
);
3773 char mpath_a
[MAX_PATH
];
3775 filename_to_ansi (mpath
, mpath_a
);
3776 if ((oflag
& (_O_CREAT
| _O_EXCL
)) != (_O_CREAT
| _O_EXCL
))
3777 res
= _open (mpath_a
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3779 res
= _open (mpath_a
, oflag
| _O_NOINHERIT
, mode
);
3785 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
3788 Standard algorithm for generating a temporary file name seems to be
3789 use pid or tid with a letter on the front (in place of the 6 X's)
3790 and cycle through the letters to find a unique name. We extend
3791 that to allow any reasonable character as the first of the 6 X's,
3792 so that the number of simultaneously used temporary files will be
3796 mkostemp (char * template, int flags
)
3800 unsigned uid
= GetCurrentThreadId ();
3801 int save_errno
= errno
;
3802 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3805 if (template == NULL
)
3808 p
= template + strlen (template);
3810 /* replace up to the last 5 X's with uid in decimal */
3811 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
3813 p
[0] = '0' + uid
% 10;
3817 if (i
< 0 && p
[0] == 'X')
3822 p
[0] = first_char
[i
];
3823 if ((fd
= sys_open (template,
3824 flags
| _O_CREAT
| _O_EXCL
| _O_RDWR
,
3825 S_IRUSR
| S_IWUSR
)) >= 0
3833 while (++i
< sizeof (first_char
));
3836 /* Template is badly formed or else we can't generate a unique name. */
3841 fchmod (int fd
, mode_t mode
)
3847 sys_rename_replace (const char *oldname
, const char *newname
, BOOL force
)
3850 char temp
[MAX_UTF8_PATH
], temp_a
[MAX_PATH
];;
3853 bool have_temp_a
= false;
3855 /* MoveFile on Windows 95 doesn't correctly change the short file name
3856 alias in a number of circumstances (it is not easy to predict when
3857 just by looking at oldname and newname, unfortunately). In these
3858 cases, renaming through a temporary name avoids the problem.
3860 A second problem on Windows 95 is that renaming through a temp name when
3861 newname is uppercase fails (the final long name ends up in
3862 lowercase, although the short alias might be uppercase) UNLESS the
3863 long temp name is not 8.3.
3865 So, on Windows 95 we always rename through a temp name, and we make sure
3866 the temp name has a long extension to ensure correct renaming. */
3868 strcpy (temp
, map_w32_filename (oldname
, NULL
));
3870 /* volume_info is set indirectly by map_w32_filename. */
3871 oldname_dev
= volume_info
.serialnum
;
3873 if (os_subtype
== OS_9X
)
3878 char oldname_a
[MAX_PATH
];
3880 oldname
= map_w32_filename (oldname
, NULL
);
3881 filename_to_ansi (oldname
, oldname_a
);
3882 filename_to_ansi (temp
, temp_a
);
3883 if ((o
= strrchr (oldname_a
, '\\')))
3886 o
= (char *) oldname_a
;
3888 if ((p
= strrchr (temp_a
, '\\')))
3895 /* Force temp name to require a manufactured 8.3 alias - this
3896 seems to make the second rename work properly. */
3897 sprintf (p
, "_.%s.%u", o
, i
);
3899 result
= rename (oldname_a
, temp_a
);
3901 /* This loop must surely terminate! */
3902 while (result
< 0 && errno
== EEXIST
);
3908 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
3909 (at least if it is a file; don't do this for directories).
3911 Since we mustn't do this if we are just changing the case of the
3912 file name (we would end up deleting the file we are trying to
3913 rename!), we let rename detect if the destination file already
3914 exists - that way we avoid the possible pitfalls of trying to
3915 determine ourselves whether two names really refer to the same
3916 file, which is not always possible in the general case. (Consider
3917 all the permutations of shared or subst'd drives, etc.) */
3919 newname
= map_w32_filename (newname
, NULL
);
3921 /* volume_info is set indirectly by map_w32_filename. */
3922 newname_dev
= volume_info
.serialnum
;
3924 if (w32_unicode_filenames
)
3926 wchar_t temp_w
[MAX_PATH
], newname_w
[MAX_PATH
];
3928 filename_to_utf16 (temp
, temp_w
);
3929 filename_to_utf16 (newname
, newname_w
);
3930 result
= _wrename (temp_w
, newname_w
);
3931 if (result
< 0 && force
)
3933 DWORD w32err
= GetLastError ();
3936 && newname_dev
!= oldname_dev
)
3938 /* The implementation of `rename' on Windows does not return
3939 errno = EXDEV when you are moving a directory to a
3940 different storage device (ex. logical disk). It returns
3941 EACCES instead. So here we handle such situations and
3945 if ((attributes
= GetFileAttributesW (temp_w
)) != -1
3946 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3949 else if (errno
== EEXIST
)
3951 if (_wchmod (newname_w
, 0666) != 0)
3953 if (_wunlink (newname_w
) != 0)
3955 result
= _wrename (temp_w
, newname_w
);
3957 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
3958 && is_symlink (temp
))
3960 /* This is Windows prohibiting the user from creating a
3961 symlink in another place, since that requires
3969 char newname_a
[MAX_PATH
];
3972 filename_to_ansi (temp
, temp_a
);
3973 filename_to_ansi (newname
, newname_a
);
3974 result
= rename (temp_a
, newname_a
);
3975 if (result
< 0 && force
)
3977 DWORD w32err
= GetLastError ();
3980 && newname_dev
!= oldname_dev
)
3984 if ((attributes
= GetFileAttributesA (temp_a
)) != -1
3985 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3988 else if (errno
== EEXIST
)
3990 if (_chmod (newname_a
, 0666) != 0)
3992 if (_unlink (newname_a
) != 0)
3994 result
= rename (temp_a
, newname_a
);
3996 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
3997 && is_symlink (temp
))
4006 sys_rename (char const *old
, char const *new)
4008 return sys_rename_replace (old
, new, TRUE
);
4012 sys_rmdir (const char * path
)
4014 return _rmdir (map_w32_filename (path
, NULL
));
4018 sys_unlink (const char * path
)
4020 path
= map_w32_filename (path
, NULL
);
4022 /* On Unix, unlink works without write permission. */
4023 _chmod (path
, 0666);
4024 return _unlink (path
);
4027 static FILETIME utc_base_ft
;
4028 static ULONGLONG utc_base
; /* In 100ns units */
4029 static int init
= 0;
4031 #define FILETIME_TO_U64(result, ft) \
4033 ULARGE_INTEGER uiTemp; \
4034 uiTemp.LowPart = (ft).dwLowDateTime; \
4035 uiTemp.HighPart = (ft).dwHighDateTime; \
4036 result = uiTemp.QuadPart; \
4040 initialize_utc_base (void)
4042 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4051 st
.wMilliseconds
= 0;
4053 SystemTimeToFileTime (&st
, &utc_base_ft
);
4054 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
4058 convert_time (FILETIME ft
)
4064 initialize_utc_base ();
4068 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
4071 FILETIME_TO_U64 (tmp
, ft
);
4072 return (time_t) ((tmp
- utc_base
) / 10000000L);
4076 convert_from_time_t (time_t time
, FILETIME
* pft
)
4082 initialize_utc_base ();
4086 /* time in 100ns units since 1-Jan-1601 */
4087 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
4088 pft
->dwHighDateTime
= tmp
.HighPart
;
4089 pft
->dwLowDateTime
= tmp
.LowPart
;
4092 static PSECURITY_DESCRIPTOR
4093 get_file_security_desc_by_handle (HANDLE h
)
4095 PSECURITY_DESCRIPTOR psd
= NULL
;
4097 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
4098 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
4100 err
= get_security_info (h
, SE_FILE_OBJECT
, si
,
4101 NULL
, NULL
, NULL
, NULL
, &psd
);
4102 if (err
!= ERROR_SUCCESS
)
4108 static PSECURITY_DESCRIPTOR
4109 get_file_security_desc_by_name (const char *fname
)
4111 PSECURITY_DESCRIPTOR psd
= NULL
;
4113 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
4114 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
4116 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
4118 err
= GetLastError ();
4119 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
4123 psd
= xmalloc (sd_len
);
4124 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
4136 unsigned n_subauthorities
;
4138 /* Use the last sub-authority value of the RID, the relative
4139 portion of the SID, as user/group ID. */
4140 n_subauthorities
= *get_sid_sub_authority_count (sid
);
4141 if (n_subauthorities
< 1)
4142 return 0; /* the "World" RID */
4143 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
4146 /* Caching SID and account values for faster lokup. */
4150 struct w32_id
*next
;
4152 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
4155 static struct w32_id
*w32_idlist
;
4158 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
4160 struct w32_id
*tail
, *found
;
4162 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
4164 if (equal_sid ((PSID
)tail
->sid
, sid
))
4173 strcpy (name
, found
->name
);
4181 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
4184 struct w32_id
*new_entry
;
4186 /* We don't want to leave behind stale cache from when Emacs was
4190 sid_len
= get_length_sid (sid
);
4191 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
4194 new_entry
->rid
= id
;
4195 strcpy (new_entry
->name
, name
);
4196 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
4197 new_entry
->next
= w32_idlist
;
4198 w32_idlist
= new_entry
;
4207 get_name_and_id (PSECURITY_DESCRIPTOR psd
, unsigned *id
, char *nm
, int what
)
4211 SID_NAME_USE ignore
;
4213 DWORD name_len
= sizeof (name
);
4215 DWORD domain_len
= sizeof (domain
);
4220 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
4221 else if (what
== GID
)
4222 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
4226 if (!result
|| !is_valid_sid (sid
))
4228 else if (!w32_cached_id (sid
, id
, nm
))
4230 if (!lookup_account_sid (NULL
, sid
, name
, &name_len
,
4231 domain
, &domain_len
, &ignore
)
4232 || name_len
> UNLEN
+1)
4236 *id
= get_rid (sid
);
4238 w32_add_to_cache (sid
, *id
, name
);
4245 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
, struct stat
*st
)
4247 int dflt_usr
= 0, dflt_grp
= 0;
4256 if (get_name_and_id (psd
, &st
->st_uid
, st
->st_uname
, UID
))
4258 if (get_name_and_id (psd
, &st
->st_gid
, st
->st_gname
, GID
))
4261 /* Consider files to belong to current user/group, if we cannot get
4262 more accurate information. */
4265 st
->st_uid
= dflt_passwd
.pw_uid
;
4266 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
4270 st
->st_gid
= dflt_passwd
.pw_gid
;
4271 strcpy (st
->st_gname
, dflt_group
.gr_name
);
4275 /* Return non-zero if NAME is a potentially slow filesystem. */
4277 is_slow_fs (const char *name
)
4282 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
4283 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
4284 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
4285 devtype
= GetDriveType (NULL
); /* use root of current drive */
4288 /* GetDriveType needs the root directory of the drive. */
4289 strncpy (drive_root
, name
, 2);
4290 drive_root
[2] = '\\';
4291 drive_root
[3] = '\0';
4292 devtype
= GetDriveType (drive_root
);
4294 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
4297 /* If this is non-zero, the caller wants accurate information about
4298 file's owner and group, which could be expensive to get. */
4299 int w32_stat_get_owner_group
;
4301 /* MSVC stat function can't cope with UNC names and has other bugs, so
4302 replace it with our own. This also allows us to calculate consistent
4303 inode values and owner/group without hacks in the main Emacs code. */
4306 stat_worker (const char * path
, struct stat
* buf
, int follow_symlinks
)
4308 char *name
, *save_name
, *r
;
4309 WIN32_FIND_DATA wfd
;
4311 unsigned __int64 fake_inode
= 0;
4314 int rootdir
= FALSE
;
4315 PSECURITY_DESCRIPTOR psd
= NULL
;
4316 int is_a_symlink
= 0;
4317 DWORD file_flags
= FILE_FLAG_BACKUP_SEMANTICS
;
4318 DWORD access_rights
= 0;
4319 DWORD fattrs
= 0, serialnum
= 0, fs_high
= 0, fs_low
= 0, nlinks
= 1;
4320 FILETIME ctime
, atime
, wtime
;
4323 if (path
== NULL
|| buf
== NULL
)
4329 save_name
= name
= (char *) map_w32_filename (path
, &path
);
4330 /* Must be valid filename, no wild cards or other invalid
4331 characters. We use _mbspbrk to support multibyte strings that
4332 might look to strpbrk as if they included literal *, ?, and other
4333 characters mentioned below that are disallowed by Windows
4335 if (_mbspbrk (name
, "*?|<>\""))
4341 /* Remove trailing directory separator, unless name is the root
4342 directory of a drive or UNC volume in which case ensure there
4343 is a trailing separator. */
4344 len
= strlen (name
);
4345 name
= strcpy (alloca (len
+ 2), name
);
4347 /* Avoid a somewhat costly call to is_symlink if the filesystem
4348 doesn't support symlinks. */
4349 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
4350 is_a_symlink
= is_symlink (name
);
4352 /* Plan A: Open the file and get all the necessary information via
4353 the resulting handle. This solves several issues in one blow:
4355 . retrieves attributes for the target of a symlink, if needed
4356 . gets attributes of root directories and symlinks pointing to
4357 root directories, thus avoiding the need for special-casing
4358 these and detecting them by examining the file-name format
4359 . retrieves more accurate attributes (e.g., non-zero size for
4360 some directories, esp. directories that are junction points)
4361 . correctly resolves "c:/..", "/.." and similar file names
4362 . avoids run-time penalties for 99% of use cases
4364 Plan A is always tried first, unless the user asked not to (but
4365 if the file is a symlink and we need to follow links, we try Plan
4366 A even if the user asked not to).
4368 If Plan A fails, we go to Plan B (below), where various
4369 potentially expensive techniques must be used to handle "special"
4370 files such as UNC volumes etc. */
4371 if (!(NILP (Vw32_get_true_file_attributes
)
4372 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
4373 /* Following symlinks requires getting the info by handle. */
4374 || (is_a_symlink
&& follow_symlinks
))
4376 BY_HANDLE_FILE_INFORMATION info
;
4378 if (is_a_symlink
&& !follow_symlinks
)
4379 file_flags
|= FILE_FLAG_OPEN_REPARSE_POINT
;
4380 /* READ_CONTROL access rights are required to get security info
4381 by handle. But if the OS doesn't support security in the
4382 first place, we don't need to try. */
4383 if (is_windows_9x () != TRUE
)
4384 access_rights
|= READ_CONTROL
;
4386 fh
= CreateFile (name
, access_rights
, 0, NULL
, OPEN_EXISTING
,
4388 /* If CreateFile fails with READ_CONTROL, try again with zero as
4390 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
4391 fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
4393 if (fh
== INVALID_HANDLE_VALUE
)
4394 goto no_true_file_attributes
;
4396 /* This is more accurate in terms of getting the correct number
4397 of links, but is quite slow (it is noticeable when Emacs is
4398 making a list of file name completions). */
4399 if (GetFileInformationByHandle (fh
, &info
))
4401 nlinks
= info
.nNumberOfLinks
;
4402 /* Might as well use file index to fake inode values, but this
4403 is not guaranteed to be unique unless we keep a handle open
4404 all the time (even then there are situations where it is
4405 not unique). Reputedly, there are at most 48 bits of info
4406 (on NTFS, presumably less on FAT). */
4407 fake_inode
= info
.nFileIndexHigh
;
4409 fake_inode
+= info
.nFileIndexLow
;
4410 serialnum
= info
.dwVolumeSerialNumber
;
4411 fs_high
= info
.nFileSizeHigh
;
4412 fs_low
= info
.nFileSizeLow
;
4413 ctime
= info
.ftCreationTime
;
4414 atime
= info
.ftLastAccessTime
;
4415 wtime
= info
.ftLastWriteTime
;
4416 fattrs
= info
.dwFileAttributes
;
4420 /* We don't go to Plan B here, because it's not clear that
4421 it's a good idea. The only known use case where
4422 CreateFile succeeds, but GetFileInformationByHandle fails
4423 (with ERROR_INVALID_FUNCTION) is for character devices
4424 such as NUL, PRN, etc. For these, switching to Plan B is
4425 a net loss, because we lose the character device
4426 attribute returned by GetFileType below (FindFirstFile
4427 doesn't set that bit in the attributes), and the other
4428 fields don't make sense for character devices anyway.
4429 Emacs doesn't really care for non-file entities in the
4430 context of l?stat, so neither do we. */
4432 /* w32err is assigned so one could put a breakpoint here and
4433 examine its value, when GetFileInformationByHandle
4435 DWORD w32err
= GetLastError ();
4439 case ERROR_FILE_NOT_FOUND
: /* can this ever happen? */
4445 /* Test for a symlink before testing for a directory, since
4446 symlinks to directories have the directory bit set, but we
4447 don't want them to appear as directories. */
4448 if (is_a_symlink
&& !follow_symlinks
)
4449 buf
->st_mode
= S_IFLNK
;
4450 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4451 buf
->st_mode
= S_IFDIR
;
4454 DWORD ftype
= GetFileType (fh
);
4458 case FILE_TYPE_DISK
:
4459 buf
->st_mode
= S_IFREG
;
4461 case FILE_TYPE_PIPE
:
4462 buf
->st_mode
= S_IFIFO
;
4464 case FILE_TYPE_CHAR
:
4465 case FILE_TYPE_UNKNOWN
:
4467 buf
->st_mode
= S_IFCHR
;
4470 /* We produce the fallback owner and group data, based on the
4471 current user that runs Emacs, in the following cases:
4473 . caller didn't request owner and group info
4474 . this is Windows 9X
4475 . getting security by handle failed, and we need to produce
4476 information for the target of a symlink (this is better
4477 than producing a potentially misleading info about the
4480 If getting security by handle fails, and we don't need to
4481 resolve symlinks, we try getting security by name. */
4482 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4483 get_file_owner_and_group (NULL
, buf
);
4486 psd
= get_file_security_desc_by_handle (fh
);
4489 get_file_owner_and_group (psd
, buf
);
4492 else if (!(is_a_symlink
&& follow_symlinks
))
4494 psd
= get_file_security_desc_by_name (name
);
4495 get_file_owner_and_group (psd
, buf
);
4499 get_file_owner_and_group (NULL
, buf
);
4505 no_true_file_attributes
:
4506 /* Plan B: Either getting a handle on the file failed, or the
4507 caller explicitly asked us to not bother making this
4508 information more accurate.
4510 Implementation note: In Plan B, we never bother to resolve
4511 symlinks, even if we got here because we tried Plan A and
4512 failed. That's because, even if the caller asked for extra
4513 precision by setting Vw32_get_true_file_attributes to t,
4514 resolving symlinks requires acquiring a file handle to the
4515 symlink, which we already know will fail. And if the user
4516 did not ask for extra precision, resolving symlinks will fly
4517 in the face of that request, since the user then wants the
4518 lightweight version of the code. */
4519 dbcs_p
= max_filename_mbslen () > 1;
4520 rootdir
= (path
>= save_name
+ len
- 1
4521 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
4523 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4524 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
4525 if (IS_DIRECTORY_SEP (r
[0])
4526 && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
4529 /* Note: If NAME is a symlink to the root of a UNC volume
4530 (i.e. "\\SERVER"), we will not detect that here, and we will
4531 return data about the symlink as result of FindFirst below.
4532 This is unfortunate, but that marginal use case does not
4533 justify a call to chase_symlinks which would impose a penalty
4534 on all the other use cases. (We get here for symlinks to
4535 roots of UNC volumes because CreateFile above fails for them,
4536 unlike with symlinks to root directories X:\ of drives.) */
4537 if (is_unc_volume (name
))
4539 fattrs
= unc_volume_file_attributes (name
);
4543 ctime
= atime
= wtime
= utc_base_ft
;
4549 if (!IS_DIRECTORY_SEP (name
[len
-1]))
4550 strcat (name
, "\\");
4554 char *end
= name
+ len
;
4555 char *n
= CharPrevExA (file_name_codepage
, name
, end
, 0);
4557 if (!IS_DIRECTORY_SEP (*n
))
4558 strcat (name
, "\\");
4560 if (GetDriveType (name
) < 2)
4566 fattrs
= FILE_ATTRIBUTE_DIRECTORY
;
4567 ctime
= atime
= wtime
= utc_base_ft
;
4573 if (IS_DIRECTORY_SEP (name
[len
-1]))
4578 char *end
= name
+ len
;
4579 char *n
= CharPrevExA (file_name_codepage
, name
, end
, 0);
4581 if (IS_DIRECTORY_SEP (*n
))
4585 /* (This is hacky, but helps when doing file completions on
4586 network drives.) Optimize by using information available from
4587 active readdir if possible. */
4588 len
= strlen (dir_pathname
);
4591 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
4596 char *end
= dir_pathname
+ len
;
4597 char *n
= CharPrevExA (file_name_codepage
, dir_pathname
, end
, 0);
4599 if (IS_DIRECTORY_SEP (*n
))
4602 if (dir_find_handle
!= INVALID_HANDLE_VALUE
4603 && !(is_a_symlink
&& follow_symlinks
)
4604 && strnicmp (save_name
, dir_pathname
, len
) == 0
4605 && IS_DIRECTORY_SEP (name
[len
])
4606 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
4608 /* This was the last entry returned by readdir. */
4609 wfd
= dir_find_data_a
; /* FIXME!!! */
4613 logon_network_drive (name
);
4615 fh
= FindFirstFile (name
, &wfd
);
4616 if (fh
== INVALID_HANDLE_VALUE
)
4623 /* Note: if NAME is a symlink, the information we get from
4624 FindFirstFile is for the symlink, not its target. */
4625 fattrs
= wfd
.dwFileAttributes
;
4626 ctime
= wfd
.ftCreationTime
;
4627 atime
= wfd
.ftLastAccessTime
;
4628 wtime
= wfd
.ftLastWriteTime
;
4629 fs_high
= wfd
.nFileSizeHigh
;
4630 fs_low
= wfd
.nFileSizeLow
;
4633 serialnum
= volume_info
.serialnum
;
4635 if (is_a_symlink
&& !follow_symlinks
)
4636 buf
->st_mode
= S_IFLNK
;
4637 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4638 buf
->st_mode
= S_IFDIR
;
4640 buf
->st_mode
= S_IFREG
;
4642 get_file_owner_and_group (NULL
, buf
);
4646 /* Not sure if there is any point in this. */
4647 if (!NILP (Vw32_generate_fake_inodes
))
4648 fake_inode
= generate_inode_val (name
);
4649 else if (fake_inode
== 0)
4651 /* For want of something better, try to make everything unique. */
4652 static DWORD gen_num
= 0;
4653 fake_inode
= ++gen_num
;
4657 buf
->st_ino
= fake_inode
;
4659 buf
->st_dev
= serialnum
;
4660 buf
->st_rdev
= serialnum
;
4662 buf
->st_size
= fs_high
;
4663 buf
->st_size
<<= 32;
4664 buf
->st_size
+= fs_low
;
4665 buf
->st_nlink
= nlinks
;
4667 /* Convert timestamps to Unix format. */
4668 buf
->st_mtime
= convert_time (wtime
);
4669 buf
->st_atime
= convert_time (atime
);
4670 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4671 buf
->st_ctime
= convert_time (ctime
);
4672 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4674 /* determine rwx permissions */
4675 if (is_a_symlink
&& !follow_symlinks
)
4676 permission
= S_IREAD
| S_IWRITE
| S_IEXEC
; /* Posix expectations */
4679 if (fattrs
& FILE_ATTRIBUTE_READONLY
)
4680 permission
= S_IREAD
;
4682 permission
= S_IREAD
| S_IWRITE
;
4684 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4685 permission
|= S_IEXEC
;
4686 else if (is_exec (name
))
4687 permission
|= S_IEXEC
;
4690 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4696 stat (const char * path
, struct stat
* buf
)
4698 return stat_worker (path
, buf
, 1);
4702 lstat (const char * path
, struct stat
* buf
)
4704 return stat_worker (path
, buf
, 0);
4708 fstatat (int fd
, char const *name
, struct stat
*st
, int flags
)
4710 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4711 This is good enough for the current usage in Emacs, but is fragile.
4713 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4714 Gnulib does this and can serve as a model. */
4715 char fullname
[MAX_PATH
];
4719 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
4722 errno
= ENAMETOOLONG
;
4728 return stat_worker (name
, st
, ! (flags
& AT_SYMLINK_NOFOLLOW
));
4731 /* Provide fstat and utime as well as stat for consistent handling of
4734 fstat (int desc
, struct stat
* buf
)
4736 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
4737 BY_HANDLE_FILE_INFORMATION info
;
4738 unsigned __int64 fake_inode
;
4741 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
4743 case FILE_TYPE_DISK
:
4744 buf
->st_mode
= S_IFREG
;
4745 if (!GetFileInformationByHandle (fh
, &info
))
4751 case FILE_TYPE_PIPE
:
4752 buf
->st_mode
= S_IFIFO
;
4754 case FILE_TYPE_CHAR
:
4755 case FILE_TYPE_UNKNOWN
:
4757 buf
->st_mode
= S_IFCHR
;
4759 memset (&info
, 0, sizeof (info
));
4760 info
.dwFileAttributes
= 0;
4761 info
.ftCreationTime
= utc_base_ft
;
4762 info
.ftLastAccessTime
= utc_base_ft
;
4763 info
.ftLastWriteTime
= utc_base_ft
;
4766 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4767 buf
->st_mode
= S_IFDIR
;
4769 buf
->st_nlink
= info
.nNumberOfLinks
;
4770 /* Might as well use file index to fake inode values, but this
4771 is not guaranteed to be unique unless we keep a handle open
4772 all the time (even then there are situations where it is
4773 not unique). Reputedly, there are at most 48 bits of info
4774 (on NTFS, presumably less on FAT). */
4775 fake_inode
= info
.nFileIndexHigh
;
4777 fake_inode
+= info
.nFileIndexLow
;
4779 /* MSVC defines _ino_t to be short; other libc's might not. */
4780 if (sizeof (buf
->st_ino
) == 2)
4781 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
4783 buf
->st_ino
= fake_inode
;
4785 /* If the caller so requested, get the true file owner and group.
4786 Otherwise, consider the file to belong to the current user. */
4787 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4788 get_file_owner_and_group (NULL
, buf
);
4791 PSECURITY_DESCRIPTOR psd
= NULL
;
4793 psd
= get_file_security_desc_by_handle (fh
);
4796 get_file_owner_and_group (psd
, buf
);
4800 get_file_owner_and_group (NULL
, buf
);
4803 buf
->st_dev
= info
.dwVolumeSerialNumber
;
4804 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
4806 buf
->st_size
= info
.nFileSizeHigh
;
4807 buf
->st_size
<<= 32;
4808 buf
->st_size
+= info
.nFileSizeLow
;
4810 /* Convert timestamps to Unix format. */
4811 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
4812 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
4813 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4814 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
4815 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4817 /* determine rwx permissions */
4818 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
4819 permission
= S_IREAD
;
4821 permission
= S_IREAD
| S_IWRITE
;
4823 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4824 permission
|= S_IEXEC
;
4827 #if 0 /* no way of knowing the filename */
4828 char * p
= strrchr (name
, '.');
4830 (xstrcasecmp (p
, ".exe") == 0 ||
4831 xstrcasecmp (p
, ".com") == 0 ||
4832 xstrcasecmp (p
, ".bat") == 0 ||
4833 xstrcasecmp (p
, ".cmd") == 0))
4834 permission
|= S_IEXEC
;
4838 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4843 /* A version of 'utime' which handles directories as well as
4847 utime (const char *name
, struct utimbuf
*times
)
4849 struct utimbuf deftime
;
4856 deftime
.modtime
= deftime
.actime
= time (NULL
);
4860 if (w32_unicode_filenames
)
4862 wchar_t name_utf16
[MAX_PATH
];
4864 if (filename_to_utf16 (name
, name_utf16
) != 0)
4865 return -1; /* errno set by filename_to_utf16 */
4867 /* Need write access to set times. */
4868 fh
= CreateFileW (name_utf16
, FILE_WRITE_ATTRIBUTES
,
4869 /* If NAME specifies a directory, FILE_SHARE_DELETE
4870 allows other processes to delete files inside it,
4871 while we have the directory open. */
4872 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
4873 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
4877 char name_ansi
[MAX_PATH
];
4879 if (filename_to_ansi (name
, name_ansi
) != 0)
4880 return -1; /* errno set by filename_to_ansi */
4882 fh
= CreateFileA (name_ansi
, FILE_WRITE_ATTRIBUTES
,
4883 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
4884 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
4886 if (fh
!= INVALID_HANDLE_VALUE
)
4888 convert_from_time_t (times
->actime
, &atime
);
4889 convert_from_time_t (times
->modtime
, &mtime
);
4890 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
4900 DWORD err
= GetLastError ();
4904 case ERROR_FILE_NOT_FOUND
:
4905 case ERROR_PATH_NOT_FOUND
:
4906 case ERROR_INVALID_DRIVE
:
4907 case ERROR_BAD_NETPATH
:
4908 case ERROR_DEV_NOT_EXIST
:
4909 /* ERROR_INVALID_NAME is the error CreateFile sets when the
4910 file name includes ?s, i.e. translation to ANSI failed. */
4911 case ERROR_INVALID_NAME
:
4914 case ERROR_TOO_MANY_OPEN_FILES
:
4917 case ERROR_ACCESS_DENIED
:
4918 case ERROR_SHARING_VIOLATION
:
4931 /* Symlink-related functions. */
4932 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4933 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4937 symlink (char const *filename
, char const *linkname
)
4939 char linkfn
[MAX_PATH
], *tgtfn
;
4941 int dir_access
, filename_ends_in_slash
;
4944 /* Diagnostics follows Posix as much as possible. */
4945 if (filename
== NULL
|| linkname
== NULL
)
4955 if (strlen (filename
) > MAX_PATH
|| strlen (linkname
) > MAX_PATH
)
4957 errno
= ENAMETOOLONG
;
4961 strcpy (linkfn
, map_w32_filename (linkname
, NULL
));
4962 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0)
4968 dbcs_p
= max_filename_mbslen () > 1;
4970 /* Note: since empty FILENAME was already rejected, we can safely
4971 refer to FILENAME[1]. */
4972 if (!(IS_DIRECTORY_SEP (filename
[0]) || IS_DEVICE_SEP (filename
[1])))
4974 /* Non-absolute FILENAME is understood as being relative to
4975 LINKNAME's directory. We need to prepend that directory to
4976 FILENAME to get correct results from faccessat below, since
4977 otherwise it will interpret FILENAME relative to the
4978 directory where the Emacs process runs. Note that
4979 make-symbolic-link always makes sure LINKNAME is a fully
4980 expanded file name. */
4982 char *p
= linkfn
+ strlen (linkfn
);
4986 while (p
> linkfn
&& !IS_ANY_SEP (p
[-1]))
4991 char *p1
= CharPrevExA (file_name_codepage
, linkfn
, p
, 0);
4993 while (p
> linkfn
&& !IS_ANY_SEP (*p1
))
4996 p1
= CharPrevExA (file_name_codepage
, linkfn
, p1
, 0);
5000 strncpy (tem
, linkfn
, p
- linkfn
);
5001 tem
[p
- linkfn
] = '\0';
5002 strcat (tem
, filename
);
5003 dir_access
= faccessat (AT_FDCWD
, tem
, D_OK
, AT_EACCESS
);
5006 dir_access
= faccessat (AT_FDCWD
, filename
, D_OK
, AT_EACCESS
);
5008 /* Since Windows distinguishes between symlinks to directories and
5009 to files, we provide a kludgy feature: if FILENAME doesn't
5010 exist, but ends in a slash, we create a symlink to directory. If
5011 FILENAME exists and is a directory, we always create a symlink to
5014 filename_ends_in_slash
= IS_DIRECTORY_SEP (filename
[strlen (filename
) - 1]);
5017 const char *end
= filename
+ strlen (filename
);
5018 const char *n
= CharPrevExA (file_name_codepage
, filename
, end
, 0);
5020 filename_ends_in_slash
= IS_DIRECTORY_SEP (*n
);
5022 if (dir_access
== 0 || filename_ends_in_slash
)
5023 flags
= SYMBOLIC_LINK_FLAG_DIRECTORY
;
5025 tgtfn
= (char *)map_w32_filename (filename
, NULL
);
5026 if (filename_ends_in_slash
)
5027 tgtfn
[strlen (tgtfn
) - 1] = '\0';
5030 if (!create_symbolic_link (linkfn
, tgtfn
, flags
))
5032 /* ENOSYS is set by create_symbolic_link, when it detects that
5033 the OS doesn't support the CreateSymbolicLink API. */
5034 if (errno
!= ENOSYS
)
5036 DWORD w32err
= GetLastError ();
5040 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5041 TGTFN point to the same file name, go figure. */
5043 case ERROR_FILE_EXISTS
:
5046 case ERROR_ACCESS_DENIED
:
5049 case ERROR_FILE_NOT_FOUND
:
5050 case ERROR_PATH_NOT_FOUND
:
5051 case ERROR_BAD_NETPATH
:
5052 case ERROR_INVALID_REPARSE_DATA
:
5055 case ERROR_DIRECTORY
:
5058 case ERROR_PRIVILEGE_NOT_HELD
:
5059 case ERROR_NOT_ALL_ASSIGNED
:
5062 case ERROR_DISK_FULL
:
5075 /* A quick inexpensive test of whether FILENAME identifies a file that
5076 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5077 must already be in the normalized form returned by
5080 Note: for repeated operations on many files, it is best to test
5081 whether the underlying volume actually supports symlinks, by
5082 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5083 avoid the call to this function if it doesn't. That's because the
5084 call to GetFileAttributes takes a non-negligible time, especially
5085 on non-local or removable filesystems. See stat_worker for an
5086 example of how to do that. */
5088 is_symlink (const char *filename
)
5091 WIN32_FIND_DATA wfd
;
5094 attrs
= GetFileAttributes (filename
);
5097 DWORD w32err
= GetLastError ();
5101 case ERROR_BAD_NETPATH
: /* network share, can't be a symlink */
5103 case ERROR_ACCESS_DENIED
:
5106 case ERROR_FILE_NOT_FOUND
:
5107 case ERROR_PATH_NOT_FOUND
:
5114 if ((attrs
& FILE_ATTRIBUTE_REPARSE_POINT
) == 0)
5116 logon_network_drive (filename
);
5117 fh
= FindFirstFile (filename
, &wfd
);
5118 if (fh
== INVALID_HANDLE_VALUE
)
5121 return (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
5122 && (wfd
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
5125 /* If NAME identifies a symbolic link, copy into BUF the file name of
5126 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5127 null-terminate the target name, even if it fits. Return the number
5128 of bytes copied, or -1 if NAME is not a symlink or any error was
5129 encountered while resolving it. The file name copied into BUF is
5130 encoded in the current ANSI codepage. */
5132 readlink (const char *name
, char *buf
, size_t buf_size
)
5135 TOKEN_PRIVILEGES privs
;
5136 int restore_privs
= 0;
5151 path
= map_w32_filename (name
, NULL
);
5153 if (strlen (path
) > MAX_PATH
)
5155 errno
= ENAMETOOLONG
;
5160 if (is_windows_9x () == TRUE
5161 || (volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0
5162 || !is_symlink (path
))
5165 errno
= EINVAL
; /* not a symlink */
5169 /* Done with simple tests, now we're in for some _real_ work. */
5170 if (enable_privilege (SE_BACKUP_NAME
, TRUE
, &privs
))
5172 /* Implementation note: From here and onward, don't return early,
5173 since that will fail to restore the original set of privileges of
5174 the calling thread. */
5176 retval
= -1; /* not too optimistic, are we? */
5178 /* Note: In the next call to CreateFile, we use zero as the 2nd
5179 argument because, when the symlink is a hidden/system file,
5180 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5181 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5182 and directory symlinks. */
5183 sh
= CreateFile (path
, 0, 0, NULL
, OPEN_EXISTING
,
5184 FILE_FLAG_OPEN_REPARSE_POINT
| FILE_FLAG_BACKUP_SEMANTICS
,
5186 if (sh
!= INVALID_HANDLE_VALUE
)
5188 BYTE reparse_buf
[MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
5189 REPARSE_DATA_BUFFER
*reparse_data
= (REPARSE_DATA_BUFFER
*)&reparse_buf
[0];
5192 if (!DeviceIoControl (sh
, FSCTL_GET_REPARSE_POINT
, NULL
, 0,
5193 reparse_buf
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
5196 else if (reparse_data
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
5200 /* Copy the link target name, in wide characters, from
5201 reparse_data, then convert it to multibyte encoding in
5202 the current locale's codepage. */
5204 BYTE lname
[MAX_PATH
];
5207 reparse_data
->SymbolicLinkReparseBuffer
.PrintNameLength
;
5209 reparse_data
->SymbolicLinkReparseBuffer
.PathBuffer
5210 + reparse_data
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
);
5211 /* This updates file_name_codepage which we need below. */
5212 int dbcs_p
= max_filename_mbslen () > 1;
5214 /* According to MSDN, PrintNameLength does not include the
5215 terminating null character. */
5216 lwname
= alloca ((lwname_len
+ 1) * sizeof(WCHAR
));
5217 memcpy (lwname
, lwname_src
, lwname_len
);
5218 lwname
[lwname_len
/sizeof(WCHAR
)] = 0; /* null-terminate */
5220 lname_len
= WideCharToMultiByte (file_name_codepage
, 0, lwname
, -1,
5221 lname
, MAX_PATH
, NULL
, NULL
);
5224 /* WideCharToMultiByte failed. */
5225 DWORD w32err1
= GetLastError ();
5229 case ERROR_INSUFFICIENT_BUFFER
:
5230 errno
= ENAMETOOLONG
;
5232 case ERROR_INVALID_PARAMETER
:
5235 case ERROR_NO_UNICODE_TRANSLATION
:
5245 size_t size_to_copy
= buf_size
;
5246 BYTE
*p
= lname
, *p2
;
5247 BYTE
*pend
= p
+ lname_len
;
5249 /* Normalize like dostounix_filename does, but we don't
5250 want to assume that lname is null-terminated. */
5252 p2
= CharNextExA (file_name_codepage
, p
, 0);
5255 if (*p
&& *p2
== ':' && *p
>= 'A' && *p
<= 'Z')
5266 p
= CharNextExA (file_name_codepage
, p
, 0);
5267 /* CharNextExA doesn't advance at null character. */
5274 /* Testing for null-terminated LNAME is paranoia:
5275 WideCharToMultiByte should always return a
5276 null-terminated string when its 4th argument is -1
5277 and its 3rd argument is null-terminated (which they
5279 if (lname
[lname_len
- 1] == '\0')
5281 if (lname_len
<= buf_size
)
5282 size_to_copy
= lname_len
;
5283 strncpy (buf
, lname
, size_to_copy
);
5285 retval
= size_to_copy
;
5292 /* CreateFile failed. */
5293 DWORD w32err2
= GetLastError ();
5297 case ERROR_FILE_NOT_FOUND
:
5298 case ERROR_PATH_NOT_FOUND
:
5301 case ERROR_ACCESS_DENIED
:
5302 case ERROR_TOO_MANY_OPEN_FILES
:
5312 restore_privilege (&privs
);
5320 readlinkat (int fd
, char const *name
, char *buffer
,
5323 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5324 as in fstatat. FIXME: Add proper support for readlinkat. */
5325 char fullname
[MAX_PATH
];
5329 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
5332 errno
= ENAMETOOLONG
;
5338 return readlink (name
, buffer
, buffer_size
);
5341 /* If FILE is a symlink, return its target (stored in a static
5342 buffer); otherwise return FILE.
5344 This function repeatedly resolves symlinks in the last component of
5345 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5346 until it arrives at a file whose last component is not a symlink,
5347 or some error occurs. It returns the target of the last
5348 successfully resolved symlink in the chain. If it succeeds to
5349 resolve even a single symlink, the value returned is an absolute
5350 file name with backslashes (result of GetFullPathName). By
5351 contrast, if the original FILE is returned, it is unaltered.
5353 Note: This function can set errno even if it succeeds.
5355 Implementation note: we only resolve the last portion ("basename")
5356 of the argument FILE and of each following file in the chain,
5357 disregarding any possible symlinks in its leading directories.
5358 This is because Windows system calls and library functions
5359 transparently resolve symlinks in leading directories and return
5360 correct information, as long as the basename is not a symlink. */
5362 chase_symlinks (const char *file
)
5364 static char target
[MAX_PATH
];
5365 char link
[MAX_PATH
];
5366 ssize_t res
, link_len
;
5370 if (is_windows_9x () == TRUE
|| !is_symlink (file
))
5371 return (char *)file
;
5373 if ((link_len
= GetFullPathName (file
, MAX_PATH
, link
, NULL
)) == 0)
5374 return (char *)file
;
5376 dbcs_p
= max_filename_mbslen () > 1;
5380 /* Remove trailing slashes, as we want to resolve the last
5381 non-trivial part of the link name. */
5384 while (link_len
> 3 && IS_DIRECTORY_SEP (link
[link_len
-1]))
5385 link
[link_len
--] = '\0';
5387 else if (link_len
> 3)
5389 char *n
= CharPrevExA (file_name_codepage
, link
, link
+ link_len
, 0);
5391 while (n
>= link
+ 2 && IS_DIRECTORY_SEP (*n
))
5394 n
= CharPrevExA (file_name_codepage
, link
, n
, 0);
5398 res
= readlink (link
, target
, MAX_PATH
);
5402 if (!(IS_DEVICE_SEP (target
[1])
5403 || (IS_DIRECTORY_SEP (target
[0]) && IS_DIRECTORY_SEP (target
[1]))))
5405 /* Target is relative. Append it to the directory part of
5406 the symlink, then copy the result back to target. */
5407 char *p
= link
+ link_len
;
5411 while (p
> link
&& !IS_ANY_SEP (p
[-1]))
5416 char *p1
= CharPrevExA (file_name_codepage
, link
, p
, 0);
5418 while (p
> link
&& !IS_ANY_SEP (*p1
))
5421 p1
= CharPrevExA (file_name_codepage
, link
, p1
, 0);
5425 strcpy (target
, link
);
5427 /* Resolve any "." and ".." to get a fully-qualified file name
5429 link_len
= GetFullPathName (target
, MAX_PATH
, link
, NULL
);
5431 } while (res
> 0 && link_len
> 0 && ++loop_count
<= 100);
5433 if (loop_count
> 100)
5436 if (target
[0] == '\0') /* not a single call to readlink succeeded */
5437 return (char *)file
;
5442 /* Posix ACL emulation. */
5445 acl_valid (acl_t acl
)
5447 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR
)acl
) ? 0 : -1;
5451 acl_to_text (acl_t acl
, ssize_t
*size
)
5454 SECURITY_INFORMATION flags
=
5455 OWNER_SECURITY_INFORMATION
|
5456 GROUP_SECURITY_INFORMATION
|
5457 DACL_SECURITY_INFORMATION
;
5458 char *retval
= NULL
;
5464 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR
)acl
, SDDL_REVISION_1
, flags
, &str_acl
, &local_size
))
5467 /* We don't want to mix heaps, so we duplicate the string in our
5468 heap and free the one allocated by the API. */
5469 retval
= xstrdup (str_acl
);
5472 LocalFree (str_acl
);
5474 else if (errno
!= ENOTSUP
)
5481 acl_from_text (const char *acl_str
)
5483 PSECURITY_DESCRIPTOR psd
, retval
= NULL
;
5489 if (convert_sddl_to_sd (acl_str
, SDDL_REVISION_1
, &psd
, &sd_size
))
5492 retval
= xmalloc (sd_size
);
5493 memcpy (retval
, psd
, sd_size
);
5496 else if (errno
!= ENOTSUP
)
5503 acl_free (void *ptr
)
5510 acl_get_file (const char *fname
, acl_type_t type
)
5512 PSECURITY_DESCRIPTOR psd
= NULL
;
5513 const char *filename
;
5515 if (type
== ACL_TYPE_ACCESS
)
5518 SECURITY_INFORMATION si
=
5519 OWNER_SECURITY_INFORMATION
|
5520 GROUP_SECURITY_INFORMATION
|
5521 DACL_SECURITY_INFORMATION
;
5524 filename
= map_w32_filename (fname
, NULL
);
5525 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5526 fname
= chase_symlinks (filename
);
5531 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
)
5532 && errno
!= ENOTSUP
)
5534 err
= GetLastError ();
5535 if (err
== ERROR_INSUFFICIENT_BUFFER
)
5537 psd
= xmalloc (sd_len
);
5538 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
5545 else if (err
== ERROR_FILE_NOT_FOUND
5546 || err
== ERROR_PATH_NOT_FOUND
)
5554 else if (type
!= ACL_TYPE_DEFAULT
)
5561 acl_set_file (const char *fname
, acl_type_t type
, acl_t acl
)
5563 TOKEN_PRIVILEGES old1
, old2
;
5565 int st
= 0, retval
= -1;
5566 SECURITY_INFORMATION flags
= 0;
5572 const char *filename
;
5574 if (acl_valid (acl
) != 0
5575 || (type
!= ACL_TYPE_DEFAULT
&& type
!= ACL_TYPE_ACCESS
))
5581 if (type
== ACL_TYPE_DEFAULT
)
5587 filename
= map_w32_filename (fname
, NULL
);
5588 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5589 fname
= chase_symlinks (filename
);
5593 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5595 flags
|= OWNER_SECURITY_INFORMATION
;
5596 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5598 flags
|= GROUP_SECURITY_INFORMATION
;
5599 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR
)acl
, &dacl_present
,
5602 flags
|= DACL_SECURITY_INFORMATION
;
5606 /* According to KB-245153, setting the owner will succeed if either:
5607 (1) the caller is the user who will be the new owner, and has the
5608 SE_TAKE_OWNERSHIP privilege, or
5609 (2) the caller has the SE_RESTORE privilege, in which case she can
5610 set any valid user or group as the owner
5612 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5613 privileges, and disregard any failures in obtaining them. If
5614 these privileges cannot be obtained, and do not already exist in
5615 the calling thread's security token, this function could fail
5617 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME
, TRUE
, &old1
))
5619 if (enable_privilege (SE_RESTORE_NAME
, TRUE
, &old2
))
5624 if (!set_file_security ((char *)fname
, flags
, (PSECURITY_DESCRIPTOR
)acl
))
5626 err
= GetLastError ();
5628 if (errno
== ENOTSUP
)
5630 else if (err
== ERROR_INVALID_OWNER
5631 || err
== ERROR_NOT_ALL_ASSIGNED
5632 || err
== ERROR_ACCESS_DENIED
)
5634 /* Maybe the requested ACL and the one the file already has
5635 are identical, in which case we can silently ignore the
5636 failure. (And no, Windows doesn't.) */
5637 acl_t current_acl
= acl_get_file (fname
, ACL_TYPE_ACCESS
);
5642 char *acl_from
= acl_to_text (current_acl
, NULL
);
5643 char *acl_to
= acl_to_text (acl
, NULL
);
5645 if (acl_from
&& acl_to
&& xstrcasecmp (acl_from
, acl_to
) == 0)
5651 acl_free (acl_from
);
5654 acl_free (current_acl
);
5657 else if (err
== ERROR_FILE_NOT_FOUND
|| err
== ERROR_PATH_NOT_FOUND
)
5671 restore_privilege (&old2
);
5672 restore_privilege (&old1
);
5680 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5681 have a fixed max size for file names, so we don't need the kind of
5682 alloc/malloc/realloc dance the gnulib version does. We also don't
5683 support FD-relative symlinks. */
5685 careadlinkat (int fd
, char const *filename
,
5686 char *buffer
, size_t buffer_size
,
5687 struct allocator
const *alloc
,
5688 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
5690 char linkname
[MAX_PATH
];
5693 link_size
= preadlinkat (fd
, filename
, linkname
, sizeof(linkname
));
5697 char *retval
= buffer
;
5699 linkname
[link_size
++] = '\0';
5700 if (link_size
> buffer_size
)
5701 retval
= (char *)(alloc
? alloc
->allocate
: xmalloc
) (link_size
);
5703 memcpy (retval
, linkname
, link_size
);
5711 /* Support for browsing other processes and their attributes. See
5712 process.c for the Lisp bindings. */
5714 /* Helper wrapper functions. */
5716 static HANDLE WINAPI
5717 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
5719 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
5721 if (g_b_init_create_toolhelp32_snapshot
== 0)
5723 g_b_init_create_toolhelp32_snapshot
= 1;
5724 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
5725 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5726 "CreateToolhelp32Snapshot");
5728 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
5730 return INVALID_HANDLE_VALUE
;
5732 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
5736 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5738 static Process32First_Proc s_pfn_Process32_First
= NULL
;
5740 if (g_b_init_process32_first
== 0)
5742 g_b_init_process32_first
= 1;
5743 s_pfn_Process32_First
= (Process32First_Proc
)
5744 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5747 if (s_pfn_Process32_First
== NULL
)
5751 return (s_pfn_Process32_First (hSnapshot
, lppe
));
5755 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5757 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
5759 if (g_b_init_process32_next
== 0)
5761 g_b_init_process32_next
= 1;
5762 s_pfn_Process32_Next
= (Process32Next_Proc
)
5763 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5766 if (s_pfn_Process32_Next
== NULL
)
5770 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
5774 open_thread_token (HANDLE ThreadHandle
,
5775 DWORD DesiredAccess
,
5777 PHANDLE TokenHandle
)
5779 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
5780 HMODULE hm_advapi32
= NULL
;
5781 if (is_windows_9x () == TRUE
)
5783 SetLastError (ERROR_NOT_SUPPORTED
);
5786 if (g_b_init_open_thread_token
== 0)
5788 g_b_init_open_thread_token
= 1;
5789 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5790 s_pfn_Open_Thread_Token
=
5791 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
5793 if (s_pfn_Open_Thread_Token
== NULL
)
5795 SetLastError (ERROR_NOT_SUPPORTED
);
5799 s_pfn_Open_Thread_Token (
5808 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
5810 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
5811 HMODULE hm_advapi32
= NULL
;
5812 if (is_windows_9x () == TRUE
)
5816 if (g_b_init_impersonate_self
== 0)
5818 g_b_init_impersonate_self
= 1;
5819 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5820 s_pfn_Impersonate_Self
=
5821 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
5823 if (s_pfn_Impersonate_Self
== NULL
)
5827 return s_pfn_Impersonate_Self (ImpersonationLevel
);
5831 revert_to_self (void)
5833 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
5834 HMODULE hm_advapi32
= NULL
;
5835 if (is_windows_9x () == TRUE
)
5839 if (g_b_init_revert_to_self
== 0)
5841 g_b_init_revert_to_self
= 1;
5842 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5843 s_pfn_Revert_To_Self
=
5844 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
5846 if (s_pfn_Revert_To_Self
== NULL
)
5850 return s_pfn_Revert_To_Self ();
5854 get_process_memory_info (HANDLE h_proc
,
5855 PPROCESS_MEMORY_COUNTERS mem_counters
,
5858 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
5859 HMODULE hm_psapi
= NULL
;
5860 if (is_windows_9x () == TRUE
)
5864 if (g_b_init_get_process_memory_info
== 0)
5866 g_b_init_get_process_memory_info
= 1;
5867 hm_psapi
= LoadLibrary ("Psapi.dll");
5869 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
5870 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
5872 if (s_pfn_Get_Process_Memory_Info
== NULL
)
5876 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
5880 get_process_working_set_size (HANDLE h_proc
,
5884 static GetProcessWorkingSetSize_Proc
5885 s_pfn_Get_Process_Working_Set_Size
= NULL
;
5887 if (is_windows_9x () == TRUE
)
5891 if (g_b_init_get_process_working_set_size
== 0)
5893 g_b_init_get_process_working_set_size
= 1;
5894 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
5895 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5896 "GetProcessWorkingSetSize");
5898 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
5902 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
5906 global_memory_status (MEMORYSTATUS
*buf
)
5908 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
5910 if (is_windows_9x () == TRUE
)
5914 if (g_b_init_global_memory_status
== 0)
5916 g_b_init_global_memory_status
= 1;
5917 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
5918 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5919 "GlobalMemoryStatus");
5921 if (s_pfn_Global_Memory_Status
== NULL
)
5925 return s_pfn_Global_Memory_Status (buf
);
5929 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
5931 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
5933 if (is_windows_9x () == TRUE
)
5937 if (g_b_init_global_memory_status_ex
== 0)
5939 g_b_init_global_memory_status_ex
= 1;
5940 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
5941 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5942 "GlobalMemoryStatusEx");
5944 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
5948 return s_pfn_Global_Memory_Status_Ex (buf
);
5952 list_system_processes (void)
5954 struct gcpro gcpro1
;
5955 Lisp_Object proclist
= Qnil
;
5958 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
5960 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
5962 PROCESSENTRY32 proc_entry
;
5968 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
5969 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
5970 res
= process32_next (h_snapshot
, &proc_entry
))
5972 proc_id
= proc_entry
.th32ProcessID
;
5973 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
5976 CloseHandle (h_snapshot
);
5978 proclist
= Fnreverse (proclist
);
5985 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
5987 TOKEN_PRIVILEGES priv
;
5988 DWORD priv_size
= sizeof (priv
);
5989 DWORD opriv_size
= sizeof (*old_priv
);
5990 HANDLE h_token
= NULL
;
5991 HANDLE h_thread
= GetCurrentThread ();
5995 res
= open_thread_token (h_thread
,
5996 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5998 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
6000 if (impersonate_self (SecurityImpersonation
))
6001 res
= open_thread_token (h_thread
,
6002 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
6007 priv
.PrivilegeCount
= 1;
6008 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
6009 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
6010 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
6011 old_priv
, &opriv_size
)
6012 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
6016 CloseHandle (h_token
);
6022 restore_privilege (TOKEN_PRIVILEGES
*priv
)
6024 DWORD priv_size
= sizeof (*priv
);
6025 HANDLE h_token
= NULL
;
6028 if (open_thread_token (GetCurrentThread (),
6029 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
6032 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
6033 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
6037 CloseHandle (h_token
);
6043 ltime (ULONGLONG time_100ns
)
6045 ULONGLONG time_sec
= time_100ns
/ 10000000;
6046 int subsec
= time_100ns
% 10000000;
6047 return list4i (time_sec
>> 16, time_sec
& 0xffff,
6048 subsec
/ 10, subsec
% 10 * 100000);
6051 #define U64_TO_LISP_TIME(time) ltime (time)
6054 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
6055 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
6058 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
6059 ULONGLONG tem1
, tem2
, tem3
, tem
;
6062 || !get_process_times_fn
6063 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
6064 &ft_kernel
, &ft_user
))
6067 GetSystemTimeAsFileTime (&ft_current
);
6069 FILETIME_TO_U64 (tem1
, ft_kernel
);
6070 *stime
= U64_TO_LISP_TIME (tem1
);
6072 FILETIME_TO_U64 (tem2
, ft_user
);
6073 *utime
= U64_TO_LISP_TIME (tem2
);
6076 *ttime
= U64_TO_LISP_TIME (tem3
);
6078 FILETIME_TO_U64 (tem
, ft_creation
);
6079 /* Process no 4 (System) returns zero creation time. */
6082 *ctime
= U64_TO_LISP_TIME (tem
);
6086 FILETIME_TO_U64 (tem3
, ft_current
);
6087 tem
= (tem3
- utc_base
) - tem
;
6089 *etime
= U64_TO_LISP_TIME (tem
);
6093 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
6104 system_process_attributes (Lisp_Object pid
)
6106 struct gcpro gcpro1
, gcpro2
, gcpro3
;
6107 Lisp_Object attrs
= Qnil
;
6108 Lisp_Object cmd_str
, decoded_cmd
, tem
;
6109 HANDLE h_snapshot
, h_proc
;
6112 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
6113 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
6114 DWORD glength
= sizeof (gname
);
6115 HANDLE token
= NULL
;
6116 SID_NAME_USE user_type
;
6117 unsigned char *buf
= NULL
;
6119 TOKEN_USER user_token
;
6120 TOKEN_PRIMARY_GROUP group_token
;
6123 PROCESS_MEMORY_COUNTERS mem
;
6124 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
6125 SIZE_T minrss
, maxrss
;
6127 MEMORY_STATUS_EX memstex
;
6128 double totphys
= 0.0;
6129 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
6131 BOOL result
= FALSE
;
6133 CHECK_NUMBER_OR_FLOAT (pid
);
6134 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
6136 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
6138 GCPRO3 (attrs
, decoded_cmd
, tem
);
6140 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
6145 pe
.dwSize
= sizeof (PROCESSENTRY32
);
6146 for (res
= process32_first (h_snapshot
, &pe
); res
;
6147 res
= process32_next (h_snapshot
, &pe
))
6149 if (proc_id
== pe
.th32ProcessID
)
6152 decoded_cmd
= build_string ("Idle");
6155 /* Decode the command name from locale-specific
6157 cmd_str
= build_unibyte_string (pe
.szExeFile
);
6160 code_convert_string_norecord (cmd_str
,
6161 Vlocale_coding_system
, 0);
6163 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
6164 attrs
= Fcons (Fcons (Qppid
,
6165 make_fixnum_or_float (pe
.th32ParentProcessID
)),
6167 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
6169 attrs
= Fcons (Fcons (Qthcount
,
6170 make_fixnum_or_float (pe
.cntThreads
)),
6177 CloseHandle (h_snapshot
);
6186 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
6188 /* If we were denied a handle to the process, try again after
6189 enabling the SeDebugPrivilege in our process. */
6192 TOKEN_PRIVILEGES priv_current
;
6194 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
6196 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
6198 restore_privilege (&priv_current
);
6204 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
6207 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
6208 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
6210 buf
= xmalloc (blen
);
6211 result
= get_token_information (token
, TokenUser
,
6212 (LPVOID
)buf
, blen
, &needed
);
6215 memcpy (&user_token
, buf
, sizeof (user_token
));
6216 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
6218 euid
= get_rid (user_token
.User
.Sid
);
6219 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
6224 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
6227 strcpy (uname
, "unknown");
6231 ulength
= strlen (uname
);
6237 /* Determine a reasonable euid and gid values. */
6238 if (xstrcasecmp ("administrator", uname
) == 0)
6240 euid
= 500; /* well-known Administrator uid */
6241 egid
= 513; /* well-known None gid */
6245 /* Get group id and name. */
6246 result
= get_token_information (token
, TokenPrimaryGroup
,
6247 (LPVOID
)buf
, blen
, &needed
);
6248 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
6250 buf
= xrealloc (buf
, blen
= needed
);
6251 result
= get_token_information (token
, TokenPrimaryGroup
,
6252 (LPVOID
)buf
, blen
, &needed
);
6256 memcpy (&group_token
, buf
, sizeof (group_token
));
6257 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
6259 egid
= get_rid (group_token
.PrimaryGroup
);
6260 dlength
= sizeof (domain
);
6262 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
6263 gname
, &glength
, NULL
, &dlength
,
6266 w32_add_to_cache (group_token
.PrimaryGroup
,
6270 strcpy (gname
, "None");
6274 glength
= strlen (gname
);
6282 if (!is_windows_9x ())
6284 /* We couldn't open the process token, presumably because of
6285 insufficient access rights. Assume this process is run
6287 strcpy (uname
, "SYSTEM");
6288 strcpy (gname
, "None");
6289 euid
= 18; /* SYSTEM */
6290 egid
= 513; /* None */
6291 glength
= strlen (gname
);
6292 ulength
= strlen (uname
);
6294 /* If we are running under Windows 9X, where security calls are
6295 not supported, we assume all processes are run by the current
6297 else if (GetUserName (uname
, &ulength
))
6299 if (xstrcasecmp ("administrator", uname
) == 0)
6304 strcpy (gname
, "None");
6305 glength
= strlen (gname
);
6306 ulength
= strlen (uname
);
6312 strcpy (uname
, "administrator");
6313 ulength
= strlen (uname
);
6314 strcpy (gname
, "None");
6315 glength
= strlen (gname
);
6318 CloseHandle (token
);
6321 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
6322 tem
= make_unibyte_string (uname
, ulength
);
6323 attrs
= Fcons (Fcons (Quser
,
6324 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
6326 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
6327 tem
= make_unibyte_string (gname
, glength
);
6328 attrs
= Fcons (Fcons (Qgroup
,
6329 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
6332 if (global_memory_status_ex (&memstex
))
6333 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
6334 totphys
= memstex
.ullTotalPhys
/ 1024.0;
6336 /* Visual Studio 6 cannot convert an unsigned __int64 type to
6337 double, so we need to do this for it... */
6339 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
6340 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
6341 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
6343 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
6345 #endif /* __GNUC__ || _MSC_VER >= 1300 */
6346 else if (global_memory_status (&memst
))
6347 totphys
= memst
.dwTotalPhys
/ 1024.0;
6350 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
6353 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
6355 attrs
= Fcons (Fcons (Qmajflt
,
6356 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
6358 attrs
= Fcons (Fcons (Qvsize
,
6359 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
6361 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
6363 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6366 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
6368 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
6370 attrs
= Fcons (Fcons (Qmajflt
,
6371 make_fixnum_or_float (mem
.PageFaultCount
)),
6373 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
6375 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6378 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
6380 DWORD rss
= maxrss
/ 1024;
6382 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
6384 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6387 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
6389 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
6390 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
6391 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
6392 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
6393 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
6394 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
6397 /* FIXME: Retrieve command line by walking the PEB of the process. */
6400 CloseHandle (h_proc
);
6406 /* Wrappers for winsock functions to map between our file descriptors
6407 and winsock's handles; also set h_errno for convenience.
6409 To allow Emacs to run on systems which don't have winsock support
6410 installed, we dynamically link to winsock on startup if present, and
6411 otherwise provide the minimum necessary functionality
6412 (eg. gethostname). */
6414 /* function pointers for relevant socket functions */
6415 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
6416 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
6417 int (PASCAL
*pfn_WSAGetLastError
) (void);
6418 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
6419 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
6420 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
6421 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
6422 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6423 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6424 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
6425 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
6426 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
6427 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
6428 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
6429 int (PASCAL
*pfn_WSACleanup
) (void);
6431 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
6432 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
6433 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
6434 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
6435 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
6436 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
6437 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
6438 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
6439 const char * optval
, int optlen
);
6440 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
6441 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
6443 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
6444 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
6445 struct sockaddr
* from
, int * fromlen
);
6446 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
6447 const struct sockaddr
* to
, int tolen
);
6449 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6450 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
6451 #ifndef HANDLE_FLAG_INHERIT
6452 #define HANDLE_FLAG_INHERIT 1
6456 static int winsock_inuse
;
6461 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
6463 release_listen_threads ();
6464 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6465 after WSAStartup returns successfully, but it seems reasonable
6466 to allow unloading winsock anyway in that case. */
6467 if (pfn_WSACleanup () == 0 ||
6468 pfn_WSAGetLastError () == WSAENETDOWN
)
6470 if (FreeLibrary (winsock_lib
))
6479 init_winsock (int load_now
)
6481 WSADATA winsockData
;
6483 if (winsock_lib
!= NULL
)
6486 pfn_SetHandleInformation
6487 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6488 "SetHandleInformation");
6490 winsock_lib
= LoadLibrary ("Ws2_32.dll");
6492 if (winsock_lib
!= NULL
)
6494 /* dynamically link to socket functions */
6496 #define LOAD_PROC(fn) \
6497 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6500 LOAD_PROC (WSAStartup
);
6501 LOAD_PROC (WSASetLastError
);
6502 LOAD_PROC (WSAGetLastError
);
6503 LOAD_PROC (WSAEventSelect
);
6504 LOAD_PROC (WSACreateEvent
);
6505 LOAD_PROC (WSACloseEvent
);
6508 LOAD_PROC (connect
);
6509 LOAD_PROC (ioctlsocket
);
6512 LOAD_PROC (closesocket
);
6513 LOAD_PROC (shutdown
);
6516 LOAD_PROC (inet_addr
);
6517 LOAD_PROC (gethostname
);
6518 LOAD_PROC (gethostbyname
);
6519 LOAD_PROC (getservbyname
);
6520 LOAD_PROC (getpeername
);
6521 LOAD_PROC (WSACleanup
);
6522 LOAD_PROC (setsockopt
);
6524 LOAD_PROC (getsockname
);
6526 LOAD_PROC (recvfrom
);
6530 /* specify version 1.1 of winsock */
6531 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
6533 if (winsockData
.wVersion
!= 0x101)
6538 /* Report that winsock exists and is usable, but leave
6539 socket functions disabled. I am assuming that calling
6540 WSAStartup does not require any network interaction,
6541 and in particular does not cause or require a dial-up
6542 connection to be established. */
6545 FreeLibrary (winsock_lib
);
6553 FreeLibrary (winsock_lib
);
6563 /* Function to map winsock error codes to errno codes for those errno
6564 code defined in errno.h (errno values not defined by errno.h are
6565 already in nt/inc/sys/socket.h). */
6572 if (winsock_lib
== NULL
)
6575 wsa_err
= pfn_WSAGetLastError ();
6579 case WSAEACCES
: errno
= EACCES
; break;
6580 case WSAEBADF
: errno
= EBADF
; break;
6581 case WSAEFAULT
: errno
= EFAULT
; break;
6582 case WSAEINTR
: errno
= EINTR
; break;
6583 case WSAEINVAL
: errno
= EINVAL
; break;
6584 case WSAEMFILE
: errno
= EMFILE
; break;
6585 case WSAENAMETOOLONG
: errno
= ENAMETOOLONG
; break;
6586 case WSAENOTEMPTY
: errno
= ENOTEMPTY
; break;
6587 default: errno
= wsa_err
; break;
6595 if (winsock_lib
!= NULL
)
6596 pfn_WSASetLastError (0);
6599 /* Extend strerror to handle the winsock-specific error codes. */
6603 } _wsa_errlist
[] = {
6604 {WSAEINTR
, "Interrupted function call"},
6605 {WSAEBADF
, "Bad file descriptor"},
6606 {WSAEACCES
, "Permission denied"},
6607 {WSAEFAULT
, "Bad address"},
6608 {WSAEINVAL
, "Invalid argument"},
6609 {WSAEMFILE
, "Too many open files"},
6611 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
6612 {WSAEINPROGRESS
, "Operation now in progress"},
6613 {WSAEALREADY
, "Operation already in progress"},
6614 {WSAENOTSOCK
, "Socket operation on non-socket"},
6615 {WSAEDESTADDRREQ
, "Destination address required"},
6616 {WSAEMSGSIZE
, "Message too long"},
6617 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
6618 {WSAENOPROTOOPT
, "Bad protocol option"},
6619 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
6620 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
6621 {WSAEOPNOTSUPP
, "Operation not supported"},
6622 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
6623 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
6624 {WSAEADDRINUSE
, "Address already in use"},
6625 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
6626 {WSAENETDOWN
, "Network is down"},
6627 {WSAENETUNREACH
, "Network is unreachable"},
6628 {WSAENETRESET
, "Network dropped connection on reset"},
6629 {WSAECONNABORTED
, "Software caused connection abort"},
6630 {WSAECONNRESET
, "Connection reset by peer"},
6631 {WSAENOBUFS
, "No buffer space available"},
6632 {WSAEISCONN
, "Socket is already connected"},
6633 {WSAENOTCONN
, "Socket is not connected"},
6634 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
6635 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
6636 {WSAETIMEDOUT
, "Connection timed out"},
6637 {WSAECONNREFUSED
, "Connection refused"},
6638 {WSAELOOP
, "Network loop"}, /* not sure */
6639 {WSAENAMETOOLONG
, "Name is too long"},
6640 {WSAEHOSTDOWN
, "Host is down"},
6641 {WSAEHOSTUNREACH
, "No route to host"},
6642 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
6643 {WSAEPROCLIM
, "Too many processes"},
6644 {WSAEUSERS
, "Too many users"}, /* not sure */
6645 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
6646 {WSAESTALE
, "Data is stale"}, /* not sure */
6647 {WSAEREMOTE
, "Remote error"}, /* not sure */
6649 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
6650 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
6651 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
6652 {WSAEDISCON
, "Graceful shutdown in progress"},
6654 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
6655 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
6656 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
6657 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
6658 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
6659 {WSASYSCALLFAILURE
, "System call failure"},
6660 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
6661 {WSATYPE_NOT_FOUND
, "Class type not found"},
6662 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
6663 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
6664 {WSAEREFUSED
, "Operation refused"}, /* not sure */
6667 {WSAHOST_NOT_FOUND
, "Host not found"},
6668 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
6669 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
6670 {WSANO_DATA
, "Valid name, no data record of requested type"},
6676 sys_strerror (int error_no
)
6679 static char unknown_msg
[40];
6681 if (error_no
>= 0 && error_no
< sys_nerr
)
6682 return sys_errlist
[error_no
];
6684 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
6685 if (_wsa_errlist
[i
].errnum
== error_no
)
6686 return _wsa_errlist
[i
].msg
;
6688 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
6692 /* [andrewi 3-May-96] I've had conflicting results using both methods,
6693 but I believe the method of keeping the socket handle separate (and
6694 insuring it is not inheritable) is the correct one. */
6696 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
6698 static int socket_to_fd (SOCKET s
);
6701 sys_socket (int af
, int type
, int protocol
)
6705 if (winsock_lib
== NULL
)
6708 return INVALID_SOCKET
;
6713 /* call the real socket function */
6714 s
= pfn_socket (af
, type
, protocol
);
6716 if (s
!= INVALID_SOCKET
)
6717 return socket_to_fd (s
);
6723 /* Convert a SOCKET to a file descriptor. */
6725 socket_to_fd (SOCKET s
)
6730 /* Although under NT 3.5 _open_osfhandle will accept a socket
6731 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
6732 that does not work under NT 3.1. However, we can get the same
6733 effect by using a backdoor function to replace an existing
6734 descriptor handle with the one we want. */
6736 /* allocate a file descriptor (with appropriate flags) */
6737 fd
= _open ("NUL:", _O_RDWR
);
6740 /* Make a non-inheritable copy of the socket handle. Note
6741 that it is possible that sockets aren't actually kernel
6742 handles, which appears to be the case on Windows 9x when
6743 the MS Proxy winsock client is installed. */
6745 /* Apparently there is a bug in NT 3.51 with some service
6746 packs, which prevents using DuplicateHandle to make a
6747 socket handle non-inheritable (causes WSACleanup to
6748 hang). The work-around is to use SetHandleInformation
6749 instead if it is available and implemented. */
6750 if (pfn_SetHandleInformation
)
6752 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
6756 HANDLE parent
= GetCurrentProcess ();
6757 HANDLE new_s
= INVALID_HANDLE_VALUE
;
6759 if (DuplicateHandle (parent
,
6765 DUPLICATE_SAME_ACCESS
))
6767 /* It is possible that DuplicateHandle succeeds even
6768 though the socket wasn't really a kernel handle,
6769 because a real handle has the same value. So
6770 test whether the new handle really is a socket. */
6771 long nonblocking
= 0;
6772 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
6774 pfn_closesocket (s
);
6779 CloseHandle (new_s
);
6784 eassert (fd
< MAXDESC
);
6785 fd_info
[fd
].hnd
= (HANDLE
) s
;
6787 /* set our own internal flags */
6788 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
6794 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6796 /* attach child_process to fd_info */
6797 if (fd_info
[ fd
].cp
!= NULL
)
6799 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
6803 fd_info
[ fd
].cp
= cp
;
6806 winsock_inuse
++; /* count open sockets */
6814 pfn_closesocket (s
);
6820 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
6822 if (winsock_lib
== NULL
)
6825 return SOCKET_ERROR
;
6829 if (fd_info
[s
].flags
& FILE_SOCKET
)
6831 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
6832 if (rc
== SOCKET_ERROR
)
6837 return SOCKET_ERROR
;
6841 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
6843 if (winsock_lib
== NULL
)
6846 return SOCKET_ERROR
;
6850 if (fd_info
[s
].flags
& FILE_SOCKET
)
6852 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
6853 if (rc
== SOCKET_ERROR
)
6858 return SOCKET_ERROR
;
6862 sys_htons (u_short hostshort
)
6864 return (winsock_lib
!= NULL
) ?
6865 pfn_htons (hostshort
) : hostshort
;
6869 sys_ntohs (u_short netshort
)
6871 return (winsock_lib
!= NULL
) ?
6872 pfn_ntohs (netshort
) : netshort
;
6876 sys_inet_addr (const char * cp
)
6878 return (winsock_lib
!= NULL
) ?
6879 pfn_inet_addr (cp
) : INADDR_NONE
;
6883 sys_gethostname (char * name
, int namelen
)
6885 if (winsock_lib
!= NULL
)
6890 retval
= pfn_gethostname (name
, namelen
);
6891 if (retval
== SOCKET_ERROR
)
6896 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
6897 return !GetComputerName (name
, (DWORD
*)&namelen
);
6900 return SOCKET_ERROR
;
6904 sys_gethostbyname (const char * name
)
6906 struct hostent
* host
;
6907 int h_err
= h_errno
;
6909 if (winsock_lib
== NULL
)
6911 h_errno
= NO_RECOVERY
;
6917 host
= pfn_gethostbyname (name
);
6929 sys_getservbyname (const char * name
, const char * proto
)
6931 struct servent
* serv
;
6933 if (winsock_lib
== NULL
)
6940 serv
= pfn_getservbyname (name
, proto
);
6947 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
6949 if (winsock_lib
== NULL
)
6952 return SOCKET_ERROR
;
6956 if (fd_info
[s
].flags
& FILE_SOCKET
)
6958 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
6959 if (rc
== SOCKET_ERROR
)
6964 return SOCKET_ERROR
;
6968 sys_shutdown (int s
, int how
)
6970 if (winsock_lib
== NULL
)
6973 return SOCKET_ERROR
;
6977 if (fd_info
[s
].flags
& FILE_SOCKET
)
6979 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
6980 if (rc
== SOCKET_ERROR
)
6985 return SOCKET_ERROR
;
6989 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
6991 if (winsock_lib
== NULL
)
6994 return SOCKET_ERROR
;
6998 if (fd_info
[s
].flags
& FILE_SOCKET
)
7000 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
7001 (const char *)optval
, optlen
);
7002 if (rc
== SOCKET_ERROR
)
7007 return SOCKET_ERROR
;
7011 sys_listen (int s
, int backlog
)
7013 if (winsock_lib
== NULL
)
7016 return SOCKET_ERROR
;
7020 if (fd_info
[s
].flags
& FILE_SOCKET
)
7022 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
7023 if (rc
== SOCKET_ERROR
)
7026 fd_info
[s
].flags
|= FILE_LISTEN
;
7030 return SOCKET_ERROR
;
7034 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
7036 if (winsock_lib
== NULL
)
7039 return SOCKET_ERROR
;
7043 if (fd_info
[s
].flags
& FILE_SOCKET
)
7045 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
7046 if (rc
== SOCKET_ERROR
)
7051 return SOCKET_ERROR
;
7055 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
7057 if (winsock_lib
== NULL
)
7064 if (fd_info
[s
].flags
& FILE_LISTEN
)
7066 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
7068 if (t
== INVALID_SOCKET
)
7071 fd
= socket_to_fd (t
);
7075 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7076 ResetEvent (fd_info
[s
].cp
->char_avail
);
7085 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
7086 struct sockaddr
* from
, int * fromlen
)
7088 if (winsock_lib
== NULL
)
7091 return SOCKET_ERROR
;
7095 if (fd_info
[s
].flags
& FILE_SOCKET
)
7097 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
7098 if (rc
== SOCKET_ERROR
)
7103 return SOCKET_ERROR
;
7107 sys_sendto (int s
, const char * buf
, int len
, int flags
,
7108 const struct sockaddr
* to
, int tolen
)
7110 if (winsock_lib
== NULL
)
7113 return SOCKET_ERROR
;
7117 if (fd_info
[s
].flags
& FILE_SOCKET
)
7119 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
7120 if (rc
== SOCKET_ERROR
)
7125 return SOCKET_ERROR
;
7128 /* Windows does not have an fcntl function. Provide an implementation
7129 good enough for Emacs. */
7131 fcntl (int s
, int cmd
, int options
)
7133 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
7134 invoked in a context where fd1 is closed and all descriptors less
7135 than fd1 are open, so sys_dup is an adequate implementation. */
7136 if (cmd
== F_DUPFD_CLOEXEC
)
7139 if (winsock_lib
== NULL
)
7146 if (fd_info
[s
].flags
& FILE_SOCKET
)
7148 if (cmd
== F_SETFL
&& options
== O_NONBLOCK
)
7150 unsigned long nblock
= 1;
7151 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
7152 if (rc
== SOCKET_ERROR
)
7154 /* Keep track of the fact that we set this to non-blocking. */
7155 fd_info
[s
].flags
|= FILE_NDELAY
;
7161 return SOCKET_ERROR
;
7165 return SOCKET_ERROR
;
7169 /* Shadow main io functions: we need to handle pipes and sockets more
7170 intelligently, and implement non-blocking mode as well. */
7183 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
7185 child_process
* cp
= fd_info
[fd
].cp
;
7187 fd_info
[fd
].cp
= NULL
;
7189 if (CHILD_ACTIVE (cp
))
7191 /* if last descriptor to active child_process then cleanup */
7193 for (i
= 0; i
< MAXDESC
; i
++)
7197 if (fd_info
[i
].cp
== cp
)
7202 if (fd_info
[fd
].flags
& FILE_SOCKET
)
7204 if (winsock_lib
== NULL
) emacs_abort ();
7206 pfn_shutdown (SOCK_HANDLE (fd
), 2);
7207 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
7209 winsock_inuse
--; /* count open sockets */
7211 /* If the process handle is NULL, it's either a socket
7212 or serial connection, or a subprocess that was
7213 already reaped by reap_subprocess, but whose
7214 resources were not yet freed, because its output was
7215 not fully read yet by the time it was reaped. (This
7216 usually happens with async subprocesses whose output
7217 is being read by Emacs.) Otherwise, this process was
7218 not reaped yet, so we set its FD to a negative value
7219 to make sure sys_select will eventually get to
7220 calling the SIGCHLD handler for it, which will then
7221 invoke waitpid and reap_subprocess. */
7222 if (cp
->procinfo
.hProcess
== NULL
)
7230 if (fd
>= 0 && fd
< MAXDESC
)
7231 fd_info
[fd
].flags
= 0;
7233 /* Note that sockets do not need special treatment here (at least on
7234 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
7235 closesocket is equivalent to CloseHandle, which is to be expected
7236 because socket handles are fully fledged kernel handles. */
7248 if (new_fd
>= 0 && new_fd
< MAXDESC
)
7250 /* duplicate our internal info as well */
7251 fd_info
[new_fd
] = fd_info
[fd
];
7257 sys_dup2 (int src
, int dst
)
7261 if (dst
< 0 || dst
>= MAXDESC
)
7267 /* make sure we close the destination first if it's a pipe or socket */
7268 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
7271 rc
= _dup2 (src
, dst
);
7274 /* duplicate our internal info as well */
7275 fd_info
[dst
] = fd_info
[src
];
7281 pipe2 (int * phandles
, int pipe2_flags
)
7286 eassert (pipe2_flags
== O_CLOEXEC
);
7288 /* make pipe handles non-inheritable; when we spawn a child, we
7289 replace the relevant handle with an inheritable one. Also put
7290 pipes into binary mode; we will do text mode translation ourselves
7292 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
7296 /* Protect against overflow, since Windows can open more handles than
7297 our fd_info array has room for. */
7298 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
7300 _close (phandles
[0]);
7301 _close (phandles
[1]);
7307 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
7308 fd_info
[phandles
[0]].flags
= flags
;
7310 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
7311 fd_info
[phandles
[1]].flags
= flags
;
7318 /* Function to do blocking read of one byte, needed to implement
7319 select. It is only allowed on communication ports, sockets, or
7322 _sys_read_ahead (int fd
)
7327 if (fd
< 0 || fd
>= MAXDESC
)
7328 return STATUS_READ_ERROR
;
7330 cp
= fd_info
[fd
].cp
;
7332 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
7333 return STATUS_READ_ERROR
;
7335 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
7336 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
7338 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
7342 cp
->status
= STATUS_READ_IN_PROGRESS
;
7344 if (fd_info
[fd
].flags
& FILE_PIPE
)
7346 rc
= _read (fd
, &cp
->chr
, sizeof (char));
7348 /* Give subprocess time to buffer some more output for us before
7349 reporting that input is available; we need this because Windows 95
7350 connects DOS programs to pipes by making the pipe appear to be
7351 the normal console stdout - as a result most DOS programs will
7352 write to stdout without buffering, ie. one character at a
7353 time. Even some W32 programs do this - "dir" in a command
7354 shell on NT is very slow if we don't do this. */
7357 int wait
= w32_pipe_read_delay
;
7363 /* Yield remainder of our time slice, effectively giving a
7364 temporary priority boost to the child process. */
7368 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7370 HANDLE hnd
= fd_info
[fd
].hnd
;
7371 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7374 /* Configure timeouts for blocking read. */
7375 if (!GetCommTimeouts (hnd
, &ct
))
7377 cp
->status
= STATUS_READ_ERROR
;
7378 return STATUS_READ_ERROR
;
7380 ct
.ReadIntervalTimeout
= 0;
7381 ct
.ReadTotalTimeoutMultiplier
= 0;
7382 ct
.ReadTotalTimeoutConstant
= 0;
7383 if (!SetCommTimeouts (hnd
, &ct
))
7385 cp
->status
= STATUS_READ_ERROR
;
7386 return STATUS_READ_ERROR
;
7389 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
7391 if (GetLastError () != ERROR_IO_PENDING
)
7393 cp
->status
= STATUS_READ_ERROR
;
7394 return STATUS_READ_ERROR
;
7396 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7398 cp
->status
= STATUS_READ_ERROR
;
7399 return STATUS_READ_ERROR
;
7403 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
7405 unsigned long nblock
= 0;
7406 /* We always want this to block, so temporarily disable NDELAY. */
7407 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7408 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7410 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
7412 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7415 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7419 if (rc
== sizeof (char))
7420 cp
->status
= STATUS_READ_SUCCEEDED
;
7422 cp
->status
= STATUS_READ_FAILED
;
7428 _sys_wait_accept (int fd
)
7434 if (fd
< 0 || fd
>= MAXDESC
)
7435 return STATUS_READ_ERROR
;
7437 cp
= fd_info
[fd
].cp
;
7439 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
7440 return STATUS_READ_ERROR
;
7442 cp
->status
= STATUS_READ_FAILED
;
7444 hEv
= pfn_WSACreateEvent ();
7445 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
7446 if (rc
!= SOCKET_ERROR
)
7449 rc
= WaitForSingleObject (hEv
, 500);
7451 } while (rc
== WAIT_TIMEOUT
7452 && cp
->status
!= STATUS_READ_ERROR
7454 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
7455 if (rc
== WAIT_OBJECT_0
)
7456 cp
->status
= STATUS_READ_SUCCEEDED
;
7458 pfn_WSACloseEvent (hEv
);
7464 sys_read (int fd
, char * buffer
, unsigned int count
)
7469 char * orig_buffer
= buffer
;
7477 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7479 child_process
*cp
= fd_info
[fd
].cp
;
7481 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
7489 /* re-read CR carried over from last read */
7490 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
7492 if (fd_info
[fd
].flags
& FILE_BINARY
) emacs_abort ();
7496 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
7499 /* presence of a child_process structure means we are operating in
7500 non-blocking mode - otherwise we just call _read directly.
7501 Note that the child_process structure might be missing because
7502 reap_subprocess has been called; in this case the pipe is
7503 already broken, so calling _read on it is okay. */
7506 int current_status
= cp
->status
;
7508 switch (current_status
)
7510 case STATUS_READ_FAILED
:
7511 case STATUS_READ_ERROR
:
7512 /* report normal EOF if nothing in buffer */
7514 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7517 case STATUS_READ_READY
:
7518 case STATUS_READ_IN_PROGRESS
:
7519 DebPrint (("sys_read called when read is in progress\n"));
7520 errno
= EWOULDBLOCK
;
7523 case STATUS_READ_SUCCEEDED
:
7524 /* consume read-ahead char */
7525 *buffer
++ = cp
->chr
;
7528 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7529 ResetEvent (cp
->char_avail
);
7531 case STATUS_READ_ACKNOWLEDGED
:
7535 DebPrint (("sys_read: bad status %d\n", current_status
));
7540 if (fd_info
[fd
].flags
& FILE_PIPE
)
7542 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
7543 to_read
= min (waiting
, (DWORD
) count
);
7546 nchars
+= _read (fd
, buffer
, to_read
);
7548 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7550 HANDLE hnd
= fd_info
[fd
].hnd
;
7551 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7557 /* Configure timeouts for non-blocking read. */
7558 if (!GetCommTimeouts (hnd
, &ct
))
7563 ct
.ReadIntervalTimeout
= MAXDWORD
;
7564 ct
.ReadTotalTimeoutMultiplier
= 0;
7565 ct
.ReadTotalTimeoutConstant
= 0;
7566 if (!SetCommTimeouts (hnd
, &ct
))
7572 if (!ResetEvent (ovl
->hEvent
))
7577 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
7579 if (GetLastError () != ERROR_IO_PENDING
)
7584 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7593 else /* FILE_SOCKET */
7595 if (winsock_lib
== NULL
) emacs_abort ();
7597 /* do the equivalent of a non-blocking read */
7598 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
7599 if (waiting
== 0 && nchars
== 0)
7601 errno
= EWOULDBLOCK
;
7607 /* always use binary mode for sockets */
7608 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
7609 if (res
== SOCKET_ERROR
)
7611 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
7612 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7622 int nread
= _read (fd
, buffer
, count
);
7625 else if (nchars
== 0)
7630 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7631 /* Perform text mode translation if required. */
7632 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7634 nchars
= crlf_to_lf (nchars
, orig_buffer
);
7635 /* If buffer contains only CR, return that. To be absolutely
7636 sure we should attempt to read the next char, but in
7637 practice a CR to be followed by LF would not appear by
7638 itself in the buffer. */
7639 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
7641 fd_info
[fd
].flags
|= FILE_LAST_CR
;
7647 nchars
= _read (fd
, buffer
, count
);
7652 /* From w32xfns.c */
7653 extern HANDLE interrupt_handle
;
7655 /* For now, don't bother with a non-blocking mode */
7657 sys_write (int fd
, const void * buffer
, unsigned int count
)
7667 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7669 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
7675 /* Perform text mode translation if required. */
7676 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7678 char * tmpbuf
= alloca (count
* 2);
7679 unsigned char * src
= (void *)buffer
;
7680 unsigned char * dst
= tmpbuf
;
7685 unsigned char *next
;
7686 /* copy next line or remaining bytes */
7687 next
= _memccpy (dst
, src
, '\n', nbytes
);
7690 /* copied one line ending with '\n' */
7691 int copied
= next
- dst
;
7694 /* insert '\r' before '\n' */
7701 /* copied remaining partial line -> now finished */
7708 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
7710 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
7711 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
7712 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
7715 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
7717 if (GetLastError () != ERROR_IO_PENDING
)
7722 if (detect_input_pending ())
7723 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
7726 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
7727 if (active
== WAIT_OBJECT_0
)
7728 { /* User pressed C-g, cancel write, then leave. Don't bother
7729 cleaning up as we may only get stuck in buggy drivers. */
7730 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
7735 if (active
== WAIT_OBJECT_0
+ 1
7736 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
7743 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
7745 unsigned long nblock
= 0;
7746 if (winsock_lib
== NULL
) emacs_abort ();
7748 /* TODO: implement select() properly so non-blocking I/O works. */
7749 /* For now, make sure the write blocks. */
7750 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7751 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7753 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
7755 /* Set the socket back to non-blocking if it was before,
7756 for other operations that support it. */
7757 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7760 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7763 if (nchars
== SOCKET_ERROR
)
7765 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
7766 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7772 /* Some networked filesystems don't like too large writes, so
7773 break them into smaller chunks. See the Comments section of
7774 the MSDN documentation of WriteFile for details behind the
7775 choice of the value of CHUNK below. See also the thread
7776 http://thread.gmane.org/gmane.comp.version-control.git/145294
7777 in the git mailing list. */
7778 const unsigned char *p
= buffer
;
7779 const unsigned chunk
= 30 * 1024 * 1024;
7784 unsigned this_chunk
= count
< chunk
? count
: chunk
;
7785 int n
= _write (fd
, p
, this_chunk
);
7793 else if (n
< this_chunk
)
7804 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
7806 extern Lisp_Object
conv_sockaddr_to_lisp (struct sockaddr
*, int);
7808 /* Return information about network interface IFNAME, or about all
7809 interfaces (if IFNAME is nil). */
7811 network_interface_get_info (Lisp_Object ifname
)
7813 ULONG ainfo_len
= sizeof (IP_ADAPTER_INFO
);
7814 IP_ADAPTER_INFO
*adapter
, *ainfo
= xmalloc (ainfo_len
);
7815 DWORD retval
= get_adapters_info (ainfo
, &ainfo_len
);
7816 Lisp_Object res
= Qnil
;
7818 if (retval
== ERROR_BUFFER_OVERFLOW
)
7820 ainfo
= xrealloc (ainfo
, ainfo_len
);
7821 retval
= get_adapters_info (ainfo
, &ainfo_len
);
7824 if (retval
== ERROR_SUCCESS
)
7826 int eth_count
= 0, tr_count
= 0, fddi_count
= 0, ppp_count
= 0;
7827 int sl_count
= 0, wlan_count
= 0, lo_count
= 0, ifx_count
= 0;
7829 struct sockaddr_in sa
;
7831 /* For the below, we need some winsock functions, so make sure
7832 the winsock DLL is loaded. If we cannot successfully load
7833 it, they will have no use of the information we provide,
7835 if (!winsock_lib
&& !init_winsock (1))
7838 for (adapter
= ainfo
; adapter
; adapter
= adapter
->Next
)
7840 char namebuf
[MAX_ADAPTER_NAME_LENGTH
+ 4];
7842 /* Present Unix-compatible interface names, instead of the
7843 Windows names, which are really GUIDs not readable by
7845 static const char *ifmt
[] = {
7846 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
7861 switch (adapter
->Type
)
7863 case MIB_IF_TYPE_ETHERNET
:
7864 /* Windows before Vista reports wireless adapters as
7865 Ethernet. Work around by looking at the Description
7867 if (strstr (adapter
->Description
, "Wireless "))
7870 if_num
= wlan_count
++;
7874 ifmt_idx
= ETHERNET
;
7875 if_num
= eth_count
++;
7878 case MIB_IF_TYPE_TOKENRING
:
7879 ifmt_idx
= TOKENRING
;
7880 if_num
= tr_count
++;
7882 case MIB_IF_TYPE_FDDI
:
7884 if_num
= fddi_count
++;
7886 case MIB_IF_TYPE_PPP
:
7888 if_num
= ppp_count
++;
7890 case MIB_IF_TYPE_SLIP
:
7892 if_num
= sl_count
++;
7894 case IF_TYPE_IEEE80211
:
7896 if_num
= wlan_count
++;
7898 case MIB_IF_TYPE_LOOPBACK
:
7901 ifmt_idx
= LOOPBACK
;
7902 if_num
= lo_count
++;
7908 ifmt_idx
= OTHER_IF
;
7909 if_num
= ifx_count
++;
7912 if (ifmt_idx
== NONE
)
7914 sprintf (namebuf
, ifmt
[ifmt_idx
], if_num
);
7916 sa
.sin_family
= AF_INET
;
7917 ip_addr
= sys_inet_addr (adapter
->IpAddressList
.IpAddress
.String
);
7918 if (ip_addr
== INADDR_NONE
)
7920 /* Bogus address, skip this interface. */
7923 sa
.sin_addr
.s_addr
= ip_addr
;
7926 res
= Fcons (Fcons (build_string (namebuf
),
7927 conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7928 sizeof (struct sockaddr
))),
7930 else if (strcmp (namebuf
, SSDATA (ifname
)) == 0)
7932 Lisp_Object hwaddr
= Fmake_vector (make_number (6), Qnil
);
7933 register struct Lisp_Vector
*p
= XVECTOR (hwaddr
);
7934 Lisp_Object flags
= Qnil
;
7938 /* Flags. We guess most of them by type, since the
7939 Windows flags are different and hard to get by. */
7940 flags
= Fcons (intern ("up"), flags
);
7941 if (ifmt_idx
== ETHERNET
|| ifmt_idx
== WLAN
)
7943 flags
= Fcons (intern ("broadcast"), flags
);
7944 flags
= Fcons (intern ("multicast"), flags
);
7946 flags
= Fcons (intern ("running"), flags
);
7947 if (ifmt_idx
== PPP
)
7949 flags
= Fcons (intern ("pointopoint"), flags
);
7950 flags
= Fcons (intern ("noarp"), flags
);
7952 if (adapter
->HaveWins
)
7953 flags
= Fcons (intern ("WINS"), flags
);
7954 if (adapter
->DhcpEnabled
)
7955 flags
= Fcons (intern ("dynamic"), flags
);
7957 res
= Fcons (flags
, res
);
7959 /* Hardware address and its family. */
7960 for (n
= 0; n
< adapter
->AddressLength
; n
++)
7961 p
->u
.contents
[n
] = make_number ((int) adapter
->Address
[n
]);
7962 /* Windows does not support AF_LINK or AF_PACKET family
7963 of addresses. Use an arbitrary family number that is
7964 identical to what GNU/Linux returns. */
7965 res
= Fcons (Fcons (make_number (1), hwaddr
), res
);
7968 sa
.sin_family
= AF_INET
;
7969 net_mask
= sys_inet_addr (adapter
->IpAddressList
.IpMask
.String
);
7970 if (net_mask
!= INADDR_NONE
)
7972 sa
.sin_addr
.s_addr
= net_mask
;
7974 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7975 sizeof (struct sockaddr
)),
7979 res
= Fcons (Qnil
, res
);
7981 sa
.sin_family
= AF_INET
;
7982 if (ip_addr
!= INADDR_NONE
)
7984 /* Broadcast address is only reported by
7985 GetAdaptersAddresses, which is of limited
7986 availability. Generate it on our own. */
7987 u_long bcast_addr
= (ip_addr
& net_mask
) | ~net_mask
;
7989 sa
.sin_addr
.s_addr
= bcast_addr
;
7991 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7992 sizeof (struct sockaddr
)),
7996 sa
.sin_addr
.s_addr
= ip_addr
;
7998 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7999 sizeof (struct sockaddr
)),
8003 res
= Fcons (Qnil
, Fcons (Qnil
, res
));
8006 /* GetAdaptersInfo is documented to not report loopback
8007 interfaces, so we generate one out of thin air. */
8010 sa
.sin_family
= AF_INET
;
8014 sa
.sin_addr
.s_addr
= sys_inet_addr ("127.0.0.1");
8015 res
= Fcons (Fcons (build_string ("lo"),
8016 conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8017 sizeof (struct sockaddr
))),
8020 else if (strcmp (SSDATA (ifname
), "lo") == 0)
8022 res
= Fcons (Fcons (intern ("running"),
8023 Fcons (intern ("loopback"),
8024 Fcons (intern ("up"), Qnil
))), Qnil
);
8025 /* 772 is what 3 different GNU/Linux systems report for
8026 the loopback interface. */
8027 res
= Fcons (Fcons (make_number (772),
8028 Fmake_vector (make_number (6),
8031 sa
.sin_addr
.s_addr
= sys_inet_addr ("255.0.0.0");
8032 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8033 sizeof (struct sockaddr
)),
8035 sa
.sin_addr
.s_addr
= sys_inet_addr ("0.0.0.0");
8036 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8037 sizeof (struct sockaddr
)),
8039 sa
.sin_addr
.s_addr
= sys_inet_addr ("127.0.0.1");
8040 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8041 sizeof (struct sockaddr
)),
8054 network_interface_list (void)
8056 return network_interface_get_info (Qnil
);
8060 network_interface_info (Lisp_Object ifname
)
8062 return network_interface_get_info (ifname
);
8066 /* The Windows CRT functions are "optimized for speed", so they don't
8067 check for timezone and DST changes if they were last called less
8068 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
8069 all Emacs features that repeatedly call time functions (e.g.,
8070 display-time) are in real danger of missing timezone and DST
8071 changes. Calling tzset before each localtime call fixes that. */
8073 sys_localtime (const time_t *t
)
8076 return localtime (t
);
8081 /* Try loading LIBRARY_ID from the file(s) specified in
8082 Vdynamic_library_alist. If the library is loaded successfully,
8083 return the handle of the DLL, and record the filename in the
8084 property :loaded-from of LIBRARY_ID. If the library could not be
8085 found, or when it was already loaded (because the handle is not
8086 recorded anywhere, and so is lost after use), return NULL.
8088 We could also save the handle in :loaded-from, but currently
8089 there's no use case for it. */
8091 w32_delayed_load (Lisp_Object library_id
)
8093 HMODULE library_dll
= NULL
;
8095 CHECK_SYMBOL (library_id
);
8097 if (CONSP (Vdynamic_library_alist
)
8098 && NILP (Fassq (library_id
, Vlibrary_cache
)))
8100 Lisp_Object found
= Qnil
;
8101 Lisp_Object dlls
= Fassq (library_id
, Vdynamic_library_alist
);
8104 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
8106 CHECK_STRING_CAR (dlls
);
8107 if ((library_dll
= LoadLibrary (SDATA (XCAR (dlls
)))))
8109 char name
[MAX_PATH
];
8112 len
= GetModuleFileNameA (library_dll
, name
, sizeof (name
));
8113 found
= Fcons (XCAR (dlls
),
8115 /* Possibly truncated */
8116 ? make_specified_string (name
, -1, len
, 1)
8122 Fput (library_id
, QCloaded_from
, found
);
8130 check_windows_init_file (void)
8132 /* A common indication that Emacs is not installed properly is when
8133 it cannot find the Windows installation file. If this file does
8134 not exist in the expected place, tell the user. */
8136 if (!noninteractive
&& !inhibit_window_system
8137 /* Vload_path is not yet initialized when we are loading
8139 && NILP (Vpurify_flag
))
8141 Lisp_Object init_file
;
8144 init_file
= build_string ("term/w32-win");
8145 fd
= openp (Vload_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
8148 Lisp_Object load_path_print
= Fprin1_to_string (Vload_path
, Qnil
);
8149 char *init_file_name
= SDATA (init_file
);
8150 char *load_path
= SDATA (load_path_print
);
8151 char *buffer
= alloca (1024
8152 + strlen (init_file_name
)
8153 + strlen (load_path
));
8156 "The Emacs Windows initialization file \"%s.el\" "
8157 "could not be found in your Emacs installation. "
8158 "Emacs checked the following directories for this file:\n"
8160 "When Emacs cannot find this file, it usually means that it "
8161 "was not installed properly, or its distribution file was "
8162 "not unpacked properly.\nSee the README.W32 file in the "
8163 "top-level Emacs directory for more information.",
8164 init_file_name
, load_path
);
8167 "Emacs Abort Dialog",
8168 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
8169 /* Use the low-level system abort. */
8180 term_ntproc (int ignored
)
8186 /* shutdown the socket interface if necessary */
8193 init_ntproc (int dumping
)
8195 sigset_t initial_mask
= 0;
8197 /* Initialize the socket interface now if available and requested by
8198 the user by defining PRELOAD_WINSOCK; otherwise loading will be
8199 delayed until open-network-stream is called (w32-has-winsock can
8200 also be used to dynamically load or reload winsock).
8202 Conveniently, init_environment is called before us, so
8203 PRELOAD_WINSOCK can be set in the registry. */
8205 /* Always initialize this correctly. */
8208 if (getenv ("PRELOAD_WINSOCK") != NULL
)
8209 init_winsock (TRUE
);
8211 /* Initial preparation for subprocess support: replace our standard
8212 handles with non-inheritable versions. */
8215 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
8216 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
8217 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
8219 parent
= GetCurrentProcess ();
8221 /* ignore errors when duplicating and closing; typically the
8222 handles will be invalid when running as a gui program. */
8223 DuplicateHandle (parent
,
8224 GetStdHandle (STD_INPUT_HANDLE
),
8229 DUPLICATE_SAME_ACCESS
);
8231 DuplicateHandle (parent
,
8232 GetStdHandle (STD_OUTPUT_HANDLE
),
8237 DUPLICATE_SAME_ACCESS
);
8239 DuplicateHandle (parent
,
8240 GetStdHandle (STD_ERROR_HANDLE
),
8245 DUPLICATE_SAME_ACCESS
);
8251 if (stdin_save
!= INVALID_HANDLE_VALUE
)
8252 _open_osfhandle ((intptr_t) stdin_save
, O_TEXT
);
8254 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
8257 if (stdout_save
!= INVALID_HANDLE_VALUE
)
8258 _open_osfhandle ((intptr_t) stdout_save
, O_TEXT
);
8260 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
8263 if (stderr_save
!= INVALID_HANDLE_VALUE
)
8264 _open_osfhandle ((intptr_t) stderr_save
, O_TEXT
);
8266 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
8270 /* unfortunately, atexit depends on implementation of malloc */
8271 /* atexit (term_ntproc); */
8274 /* Make sure we start with all signals unblocked. */
8275 sigprocmask (SIG_SETMASK
, &initial_mask
, NULL
);
8276 signal (SIGABRT
, term_ntproc
);
8280 /* determine which drives are fixed, for GetCachedVolumeInformation */
8282 /* GetDriveType must have trailing backslash. */
8283 char drive
[] = "A:\\";
8285 /* Loop over all possible drive letters */
8286 while (*drive
<= 'Z')
8288 /* Record if this drive letter refers to a fixed drive. */
8289 fixed_drives
[DRIVE_INDEX (*drive
)] =
8290 (GetDriveType (drive
) == DRIVE_FIXED
);
8295 /* Reset the volume info cache. */
8296 volume_cache
= NULL
;
8301 shutdown_handler ensures that buffers' autosave files are
8302 up to date when the user logs off, or the system shuts down.
8305 shutdown_handler (DWORD type
)
8307 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
8308 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
8309 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
8310 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
8312 /* Shut down cleanly, making sure autosave files are up to date. */
8313 shut_down_emacs (0, Qnil
);
8316 /* Allow other handlers to handle this signal. */
8321 globals_of_w32 is used to initialize those global variables that
8322 must always be initialized on startup even when the global variable
8323 initialized is non zero (see the function main in emacs.c).
8326 globals_of_w32 (void)
8328 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
8330 get_process_times_fn
= (GetProcessTimes_Proc
)
8331 GetProcAddress (kernel32
, "GetProcessTimes");
8333 DEFSYM (QCloaded_from
, ":loaded-from");
8335 g_b_init_is_windows_9x
= 0;
8336 g_b_init_open_process_token
= 0;
8337 g_b_init_get_token_information
= 0;
8338 g_b_init_lookup_account_sid
= 0;
8339 g_b_init_get_sid_sub_authority
= 0;
8340 g_b_init_get_sid_sub_authority_count
= 0;
8341 g_b_init_get_security_info
= 0;
8342 g_b_init_get_file_security
= 0;
8343 g_b_init_get_security_descriptor_owner
= 0;
8344 g_b_init_get_security_descriptor_group
= 0;
8345 g_b_init_is_valid_sid
= 0;
8346 g_b_init_create_toolhelp32_snapshot
= 0;
8347 g_b_init_process32_first
= 0;
8348 g_b_init_process32_next
= 0;
8349 g_b_init_open_thread_token
= 0;
8350 g_b_init_impersonate_self
= 0;
8351 g_b_init_revert_to_self
= 0;
8352 g_b_init_get_process_memory_info
= 0;
8353 g_b_init_get_process_working_set_size
= 0;
8354 g_b_init_global_memory_status
= 0;
8355 g_b_init_global_memory_status_ex
= 0;
8356 g_b_init_equal_sid
= 0;
8357 g_b_init_copy_sid
= 0;
8358 g_b_init_get_length_sid
= 0;
8359 g_b_init_get_native_system_info
= 0;
8360 g_b_init_get_system_times
= 0;
8361 g_b_init_create_symbolic_link
= 0;
8362 g_b_init_get_security_descriptor_dacl
= 0;
8363 g_b_init_convert_sd_to_sddl
= 0;
8364 g_b_init_convert_sddl_to_sd
= 0;
8365 g_b_init_is_valid_security_descriptor
= 0;
8366 g_b_init_set_file_security
= 0;
8367 g_b_init_get_adapters_info
= 0;
8368 num_of_processors
= 0;
8369 /* The following sets a handler for shutdown notifications for
8370 console apps. This actually applies to Emacs in both console and
8371 GUI modes, since we had to fool windows into thinking emacs is a
8372 console application to get console mode to work. */
8373 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
8375 /* "None" is the default group name on standalone workstations. */
8376 strcpy (dflt_group_name
, "None");
8378 /* Reset, in case it has some value inherited from dump time. */
8379 w32_stat_get_owner_group
= 0;
8381 /* If w32_unicode_filenames is non-zero, we will be using Unicode
8382 (a.k.a. "wide") APIs to invoke functions that accept file
8384 if (is_windows_9x ())
8385 w32_unicode_filenames
= 0;
8387 w32_unicode_filenames
= 1;
8390 /* For make-serial-process */
8392 serial_open (Lisp_Object port_obj
)
8394 char *port
= SSDATA (port_obj
);
8399 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
8400 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
8401 if (hnd
== INVALID_HANDLE_VALUE
)
8402 error ("Could not open %s", port
);
8403 fd
= (int) _open_osfhandle ((intptr_t) hnd
, 0);
8405 error ("Could not open %s", port
);
8409 error ("Could not create child process");
8411 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
8412 fd_info
[ fd
].hnd
= hnd
;
8413 fd_info
[ fd
].flags
|=
8414 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
8415 if (fd_info
[ fd
].cp
!= NULL
)
8417 error ("fd_info[fd = %d] is already in use", fd
);
8419 fd_info
[ fd
].cp
= cp
;
8420 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
8421 if (cp
->ovl_read
.hEvent
== NULL
)
8422 error ("Could not create read event");
8423 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
8424 if (cp
->ovl_write
.hEvent
== NULL
)
8425 error ("Could not create write event");
8430 /* For serial-process-configure */
8432 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
8434 Lisp_Object childp2
= Qnil
;
8435 Lisp_Object tem
= Qnil
;
8439 char summary
[4] = "???"; /* This usually becomes "8N1". */
8441 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
8442 error ("Not a serial process");
8443 hnd
= fd_info
[ p
->outfd
].hnd
;
8445 childp2
= Fcopy_sequence (p
->childp
);
8447 /* Initialize timeouts for blocking read and blocking write. */
8448 if (!GetCommTimeouts (hnd
, &ct
))
8449 error ("GetCommTimeouts() failed");
8450 ct
.ReadIntervalTimeout
= 0;
8451 ct
.ReadTotalTimeoutMultiplier
= 0;
8452 ct
.ReadTotalTimeoutConstant
= 0;
8453 ct
.WriteTotalTimeoutMultiplier
= 0;
8454 ct
.WriteTotalTimeoutConstant
= 0;
8455 if (!SetCommTimeouts (hnd
, &ct
))
8456 error ("SetCommTimeouts() failed");
8457 /* Read port attributes and prepare default configuration. */
8458 memset (&dcb
, 0, sizeof (dcb
));
8459 dcb
.DCBlength
= sizeof (DCB
);
8460 if (!GetCommState (hnd
, &dcb
))
8461 error ("GetCommState() failed");
8464 dcb
.fAbortOnError
= FALSE
;
8465 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
8470 /* Configure speed. */
8471 if (!NILP (Fplist_member (contact
, QCspeed
)))
8472 tem
= Fplist_get (contact
, QCspeed
);
8474 tem
= Fplist_get (p
->childp
, QCspeed
);
8476 dcb
.BaudRate
= XINT (tem
);
8477 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
8479 /* Configure bytesize. */
8480 if (!NILP (Fplist_member (contact
, QCbytesize
)))
8481 tem
= Fplist_get (contact
, QCbytesize
);
8483 tem
= Fplist_get (p
->childp
, QCbytesize
);
8485 tem
= make_number (8);
8487 if (XINT (tem
) != 7 && XINT (tem
) != 8)
8488 error (":bytesize must be nil (8), 7, or 8");
8489 dcb
.ByteSize
= XINT (tem
);
8490 summary
[0] = XINT (tem
) + '0';
8491 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
8493 /* Configure parity. */
8494 if (!NILP (Fplist_member (contact
, QCparity
)))
8495 tem
= Fplist_get (contact
, QCparity
);
8497 tem
= Fplist_get (p
->childp
, QCparity
);
8498 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
8499 error (":parity must be nil (no parity), `even', or `odd'");
8500 dcb
.fParity
= FALSE
;
8501 dcb
.Parity
= NOPARITY
;
8502 dcb
.fErrorChar
= FALSE
;
8507 else if (EQ (tem
, Qeven
))
8511 dcb
.Parity
= EVENPARITY
;
8512 dcb
.fErrorChar
= TRUE
;
8514 else if (EQ (tem
, Qodd
))
8518 dcb
.Parity
= ODDPARITY
;
8519 dcb
.fErrorChar
= TRUE
;
8521 childp2
= Fplist_put (childp2
, QCparity
, tem
);
8523 /* Configure stopbits. */
8524 if (!NILP (Fplist_member (contact
, QCstopbits
)))
8525 tem
= Fplist_get (contact
, QCstopbits
);
8527 tem
= Fplist_get (p
->childp
, QCstopbits
);
8529 tem
= make_number (1);
8531 if (XINT (tem
) != 1 && XINT (tem
) != 2)
8532 error (":stopbits must be nil (1 stopbit), 1, or 2");
8533 summary
[2] = XINT (tem
) + '0';
8534 if (XINT (tem
) == 1)
8535 dcb
.StopBits
= ONESTOPBIT
;
8536 else if (XINT (tem
) == 2)
8537 dcb
.StopBits
= TWOSTOPBITS
;
8538 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
8540 /* Configure flowcontrol. */
8541 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
8542 tem
= Fplist_get (contact
, QCflowcontrol
);
8544 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
8545 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
8546 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
8547 dcb
.fOutxCtsFlow
= FALSE
;
8548 dcb
.fOutxDsrFlow
= FALSE
;
8549 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
8550 dcb
.fDsrSensitivity
= FALSE
;
8551 dcb
.fTXContinueOnXoff
= FALSE
;
8554 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
8555 dcb
.XonChar
= 17; /* Control-Q */
8556 dcb
.XoffChar
= 19; /* Control-S */
8559 /* Already configured. */
8561 else if (EQ (tem
, Qhw
))
8563 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
8564 dcb
.fOutxCtsFlow
= TRUE
;
8566 else if (EQ (tem
, Qsw
))
8571 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
8573 /* Activate configuration. */
8574 if (!SetCommState (hnd
, &dcb
))
8575 error ("SetCommState() failed");
8577 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
8578 pset_childp (p
, childp2
);
8584 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
8588 struct timespec timeout
;
8589 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
8590 int fd
= process
->infd
;
8592 n
= sys_read (fd
, (char*)buf
, sz
);
8599 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8600 if (err
== EWOULDBLOCK
)
8603 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
8609 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
8611 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
8612 int fd
= process
->outfd
;
8613 ssize_t n
= sys_write (fd
, buf
, sz
);
8615 /* 0 or more bytes written means everything went fine. */
8619 /* Negative bytes written means we got an error in errno.
8620 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8621 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
8622 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
8626 #endif /* HAVE_GNUTLS */