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 ((attributes
= GetFileAttributes (path
)) == -1)
3370 DWORD w32err
= GetLastError ();
3374 case ERROR_INVALID_NAME
:
3375 case ERROR_BAD_PATHNAME
:
3376 if (is_unc_volume (path
))
3378 attributes
= unc_volume_file_attributes (path
);
3379 if (attributes
== -1)
3387 case ERROR_FILE_NOT_FOUND
:
3388 case ERROR_BAD_NETPATH
:
3397 if ((mode
& X_OK
) != 0
3398 && !(is_exec (path
) || (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0))
3403 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
3408 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
3416 /* A version of 'access' to be used locally with file names in
3417 locale-specific encoding. Does not resolve symlinks and does not
3418 support file names on FAT12 and FAT16 volumes, but that's OK, since
3419 we only invoke this function for files inside the Emacs source or
3420 installation tree, on directories (so any symlinks should have the
3421 directory bit set), and on short file names such as "C:/.emacs". */
3423 sys_access (const char *fname
, int mode
)
3425 char fname_copy
[MAX_PATH
], *p
;
3428 strcpy (fname_copy
, fname
);
3429 /* Do the equivalent of unixtodos_filename. */
3430 for (p
= fname_copy
; *p
; p
= CharNext (p
))
3434 if ((attributes
= GetFileAttributesA (fname_copy
)) == -1)
3436 DWORD w32err
= GetLastError ();
3440 case ERROR_INVALID_NAME
:
3441 case ERROR_BAD_PATHNAME
:
3442 case ERROR_FILE_NOT_FOUND
:
3443 case ERROR_BAD_NETPATH
:
3452 if ((mode
& X_OK
) != 0
3453 && !(is_exec (fname_copy
)
3454 || (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0))
3459 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
3464 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
3472 /* Shadow some MSVC runtime functions to map requests for long filenames
3473 to reasonable short names if necessary. This was originally added to
3474 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3478 sys_chdir (const char * path
)
3480 /* FIXME: Temporary. Also, figure out what to do with
3481 map_w32_filename, as the original code did this:
3482 _chdir(map_w32_filename (path, NULL)). */
3483 if (w32_unicode_filenames
)
3485 wchar_t newdir
[MAXPATHLEN
];
3487 if (filename_to_utf16 (path
, newdir
) == 0)
3488 return _wchdir (newdir
);
3493 char newdir
[MAXPATHLEN
];
3495 if (filename_to_ansi (path
, newdir
) == 0)
3496 return _chdir (path
);
3502 sys_chmod (const char * path
, int mode
)
3504 path
= chase_symlinks (map_w32_filename (path
, NULL
));
3505 return _chmod (path
, mode
);
3509 sys_creat (const char * path
, int mode
)
3511 return _creat (map_w32_filename (path
, NULL
), mode
);
3515 sys_fopen (const char * path
, const char * mode
)
3519 const char * mode_save
= mode
;
3521 /* Force all file handles to be non-inheritable. This is necessary to
3522 ensure child processes don't unwittingly inherit handles that might
3523 prevent future file access. */
3527 else if (mode
[0] == 'w' || mode
[0] == 'a')
3528 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
3532 /* Only do simplistic option parsing. */
3536 oflag
&= ~(O_RDONLY
| O_WRONLY
);
3539 else if (mode
[0] == 'b')
3544 else if (mode
[0] == 't')
3551 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
3555 return _fdopen (fd
, mode_save
);
3558 /* This only works on NTFS volumes, but is useful to have. */
3560 sys_link (const char * old
, const char * new)
3564 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
3566 if (old
== NULL
|| new == NULL
)
3572 strcpy (oldname
, map_w32_filename (old
, NULL
));
3573 strcpy (newname
, map_w32_filename (new, NULL
));
3575 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
3576 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
3577 if (fileh
!= INVALID_HANDLE_VALUE
)
3581 /* Confusingly, the "alternate" stream name field does not apply
3582 when restoring a hard link, and instead contains the actual
3583 stream data for the link (ie. the name of the link to create).
3584 The WIN32_STREAM_ID structure before the cStreamName field is
3585 the stream header, which is then immediately followed by the
3589 WIN32_STREAM_ID wid
;
3590 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
3593 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
3594 data
.wid
.cStreamName
, MAX_PATH
);
3597 LPVOID context
= NULL
;
3600 data
.wid
.dwStreamId
= BACKUP_LINK
;
3601 data
.wid
.dwStreamAttributes
= 0;
3602 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
3603 data
.wid
.Size
.HighPart
= 0;
3604 data
.wid
.dwStreamNameSize
= 0;
3606 if (BackupWrite (fileh
, (LPBYTE
)&data
,
3607 offsetof (WIN32_STREAM_ID
, cStreamName
)
3608 + data
.wid
.Size
.LowPart
,
3609 &wbytes
, FALSE
, FALSE
, &context
)
3610 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
3617 /* Should try mapping GetLastError to errno; for now just
3618 indicate a general error (eg. links not supported). */
3619 errno
= EINVAL
; // perhaps EMLINK?
3623 CloseHandle (fileh
);
3632 sys_mkdir (const char * path
)
3634 return _mkdir (map_w32_filename (path
, NULL
));
3638 sys_open (const char * path
, int oflag
, int mode
)
3640 const char* mpath
= map_w32_filename (path
, NULL
);
3643 /* If possible, try to open file without _O_CREAT, to be able to
3644 write to existing hidden and system files. Force all file
3645 handles to be non-inheritable. */
3646 if ((oflag
& (_O_CREAT
| _O_EXCL
)) != (_O_CREAT
| _O_EXCL
))
3647 res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3649 res
= _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
3654 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
3657 Standard algorithm for generating a temporary file name seems to be
3658 use pid or tid with a letter on the front (in place of the 6 X's)
3659 and cycle through the letters to find a unique name. We extend
3660 that to allow any reasonable character as the first of the 6 X's,
3661 so that the number of simultaneously used temporary files will be
3665 mkostemp (char * template, int flags
)
3669 unsigned uid
= GetCurrentThreadId ();
3670 int save_errno
= errno
;
3671 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3674 if (template == NULL
)
3677 p
= template + strlen (template);
3679 /* replace up to the last 5 X's with uid in decimal */
3680 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
3682 p
[0] = '0' + uid
% 10;
3686 if (i
< 0 && p
[0] == 'X')
3691 p
[0] = first_char
[i
];
3692 if ((fd
= sys_open (template,
3693 flags
| _O_CREAT
| _O_EXCL
| _O_RDWR
,
3694 S_IRUSR
| S_IWUSR
)) >= 0
3702 while (++i
< sizeof (first_char
));
3705 /* Template is badly formed or else we can't generate a unique name. */
3710 fchmod (int fd
, mode_t mode
)
3716 sys_rename_replace (const char *oldname
, const char *newname
, BOOL force
)
3719 char temp
[MAX_PATH
];
3723 /* MoveFile on Windows 95 doesn't correctly change the short file name
3724 alias in a number of circumstances (it is not easy to predict when
3725 just by looking at oldname and newname, unfortunately). In these
3726 cases, renaming through a temporary name avoids the problem.
3728 A second problem on Windows 95 is that renaming through a temp name when
3729 newname is uppercase fails (the final long name ends up in
3730 lowercase, although the short alias might be uppercase) UNLESS the
3731 long temp name is not 8.3.
3733 So, on Windows 95 we always rename through a temp name, and we make sure
3734 the temp name has a long extension to ensure correct renaming. */
3736 strcpy (temp
, map_w32_filename (oldname
, NULL
));
3738 /* volume_info is set indirectly by map_w32_filename. */
3739 oldname_dev
= volume_info
.serialnum
;
3741 if (os_subtype
== OS_9X
)
3747 oldname
= map_w32_filename (oldname
, NULL
);
3748 if ((o
= strrchr (oldname
, '\\')))
3751 o
= (char *) oldname
;
3753 if ((p
= strrchr (temp
, '\\')))
3760 /* Force temp name to require a manufactured 8.3 alias - this
3761 seems to make the second rename work properly. */
3762 sprintf (p
, "_.%s.%u", o
, i
);
3764 result
= rename (oldname
, temp
);
3766 /* This loop must surely terminate! */
3767 while (result
< 0 && errno
== EEXIST
);
3772 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
3773 (at least if it is a file; don't do this for directories).
3775 Since we mustn't do this if we are just changing the case of the
3776 file name (we would end up deleting the file we are trying to
3777 rename!), we let rename detect if the destination file already
3778 exists - that way we avoid the possible pitfalls of trying to
3779 determine ourselves whether two names really refer to the same
3780 file, which is not always possible in the general case. (Consider
3781 all the permutations of shared or subst'd drives, etc.) */
3783 newname
= map_w32_filename (newname
, NULL
);
3785 /* volume_info is set indirectly by map_w32_filename. */
3786 newname_dev
= volume_info
.serialnum
;
3788 result
= rename (temp
, newname
);
3790 if (result
< 0 && force
)
3792 DWORD w32err
= GetLastError ();
3795 && newname_dev
!= oldname_dev
)
3797 /* The implementation of `rename' on Windows does not return
3798 errno = EXDEV when you are moving a directory to a
3799 different storage device (ex. logical disk). It returns
3800 EACCES instead. So here we handle such situations and
3804 if ((attributes
= GetFileAttributes (temp
)) != -1
3805 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3808 else if (errno
== EEXIST
)
3810 if (_chmod (newname
, 0666) != 0)
3812 if (_unlink (newname
) != 0)
3814 result
= rename (temp
, newname
);
3816 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
3817 && is_symlink (temp
))
3819 /* This is Windows prohibiting the user from creating a
3820 symlink in another place, since that requires
3830 sys_rename (char const *old
, char const *new)
3832 return sys_rename_replace (old
, new, TRUE
);
3836 sys_rmdir (const char * path
)
3838 return _rmdir (map_w32_filename (path
, NULL
));
3842 sys_unlink (const char * path
)
3844 path
= map_w32_filename (path
, NULL
);
3846 /* On Unix, unlink works without write permission. */
3847 _chmod (path
, 0666);
3848 return _unlink (path
);
3851 static FILETIME utc_base_ft
;
3852 static ULONGLONG utc_base
; /* In 100ns units */
3853 static int init
= 0;
3855 #define FILETIME_TO_U64(result, ft) \
3857 ULARGE_INTEGER uiTemp; \
3858 uiTemp.LowPart = (ft).dwLowDateTime; \
3859 uiTemp.HighPart = (ft).dwHighDateTime; \
3860 result = uiTemp.QuadPart; \
3864 initialize_utc_base (void)
3866 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3875 st
.wMilliseconds
= 0;
3877 SystemTimeToFileTime (&st
, &utc_base_ft
);
3878 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
3882 convert_time (FILETIME ft
)
3888 initialize_utc_base ();
3892 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3895 FILETIME_TO_U64 (tmp
, ft
);
3896 return (time_t) ((tmp
- utc_base
) / 10000000L);
3900 convert_from_time_t (time_t time
, FILETIME
* pft
)
3906 initialize_utc_base ();
3910 /* time in 100ns units since 1-Jan-1601 */
3911 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3912 pft
->dwHighDateTime
= tmp
.HighPart
;
3913 pft
->dwLowDateTime
= tmp
.LowPart
;
3916 static PSECURITY_DESCRIPTOR
3917 get_file_security_desc_by_handle (HANDLE h
)
3919 PSECURITY_DESCRIPTOR psd
= NULL
;
3921 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3922 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3924 err
= get_security_info (h
, SE_FILE_OBJECT
, si
,
3925 NULL
, NULL
, NULL
, NULL
, &psd
);
3926 if (err
!= ERROR_SUCCESS
)
3932 static PSECURITY_DESCRIPTOR
3933 get_file_security_desc_by_name (const char *fname
)
3935 PSECURITY_DESCRIPTOR psd
= NULL
;
3937 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3938 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3940 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3942 err
= GetLastError ();
3943 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3947 psd
= xmalloc (sd_len
);
3948 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3960 unsigned n_subauthorities
;
3962 /* Use the last sub-authority value of the RID, the relative
3963 portion of the SID, as user/group ID. */
3964 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3965 if (n_subauthorities
< 1)
3966 return 0; /* the "World" RID */
3967 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3970 /* Caching SID and account values for faster lokup. */
3974 struct w32_id
*next
;
3976 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3979 static struct w32_id
*w32_idlist
;
3982 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3984 struct w32_id
*tail
, *found
;
3986 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3988 if (equal_sid ((PSID
)tail
->sid
, sid
))
3997 strcpy (name
, found
->name
);
4005 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
4008 struct w32_id
*new_entry
;
4010 /* We don't want to leave behind stale cache from when Emacs was
4014 sid_len
= get_length_sid (sid
);
4015 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
4018 new_entry
->rid
= id
;
4019 strcpy (new_entry
->name
, name
);
4020 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
4021 new_entry
->next
= w32_idlist
;
4022 w32_idlist
= new_entry
;
4031 get_name_and_id (PSECURITY_DESCRIPTOR psd
, unsigned *id
, char *nm
, int what
)
4035 SID_NAME_USE ignore
;
4037 DWORD name_len
= sizeof (name
);
4039 DWORD domain_len
= sizeof (domain
);
4044 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
4045 else if (what
== GID
)
4046 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
4050 if (!result
|| !is_valid_sid (sid
))
4052 else if (!w32_cached_id (sid
, id
, nm
))
4054 if (!lookup_account_sid (NULL
, sid
, name
, &name_len
,
4055 domain
, &domain_len
, &ignore
)
4056 || name_len
> UNLEN
+1)
4060 *id
= get_rid (sid
);
4062 w32_add_to_cache (sid
, *id
, name
);
4069 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
, struct stat
*st
)
4071 int dflt_usr
= 0, dflt_grp
= 0;
4080 if (get_name_and_id (psd
, &st
->st_uid
, st
->st_uname
, UID
))
4082 if (get_name_and_id (psd
, &st
->st_gid
, st
->st_gname
, GID
))
4085 /* Consider files to belong to current user/group, if we cannot get
4086 more accurate information. */
4089 st
->st_uid
= dflt_passwd
.pw_uid
;
4090 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
4094 st
->st_gid
= dflt_passwd
.pw_gid
;
4095 strcpy (st
->st_gname
, dflt_group
.gr_name
);
4099 /* Return non-zero if NAME is a potentially slow filesystem. */
4101 is_slow_fs (const char *name
)
4106 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
4107 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
4108 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
4109 devtype
= GetDriveType (NULL
); /* use root of current drive */
4112 /* GetDriveType needs the root directory of the drive. */
4113 strncpy (drive_root
, name
, 2);
4114 drive_root
[2] = '\\';
4115 drive_root
[3] = '\0';
4116 devtype
= GetDriveType (drive_root
);
4118 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
4121 /* If this is non-zero, the caller wants accurate information about
4122 file's owner and group, which could be expensive to get. */
4123 int w32_stat_get_owner_group
;
4125 /* MSVC stat function can't cope with UNC names and has other bugs, so
4126 replace it with our own. This also allows us to calculate consistent
4127 inode values and owner/group without hacks in the main Emacs code. */
4130 stat_worker (const char * path
, struct stat
* buf
, int follow_symlinks
)
4132 char *name
, *save_name
, *r
;
4133 WIN32_FIND_DATA wfd
;
4135 unsigned __int64 fake_inode
= 0;
4138 int rootdir
= FALSE
;
4139 PSECURITY_DESCRIPTOR psd
= NULL
;
4140 int is_a_symlink
= 0;
4141 DWORD file_flags
= FILE_FLAG_BACKUP_SEMANTICS
;
4142 DWORD access_rights
= 0;
4143 DWORD fattrs
= 0, serialnum
= 0, fs_high
= 0, fs_low
= 0, nlinks
= 1;
4144 FILETIME ctime
, atime
, wtime
;
4147 if (path
== NULL
|| buf
== NULL
)
4153 save_name
= name
= (char *) map_w32_filename (path
, &path
);
4154 /* Must be valid filename, no wild cards or other invalid
4155 characters. We use _mbspbrk to support multibyte strings that
4156 might look to strpbrk as if they included literal *, ?, and other
4157 characters mentioned below that are disallowed by Windows
4159 if (_mbspbrk (name
, "*?|<>\""))
4165 /* Remove trailing directory separator, unless name is the root
4166 directory of a drive or UNC volume in which case ensure there
4167 is a trailing separator. */
4168 len
= strlen (name
);
4169 name
= strcpy (alloca (len
+ 2), name
);
4171 /* Avoid a somewhat costly call to is_symlink if the filesystem
4172 doesn't support symlinks. */
4173 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
4174 is_a_symlink
= is_symlink (name
);
4176 /* Plan A: Open the file and get all the necessary information via
4177 the resulting handle. This solves several issues in one blow:
4179 . retrieves attributes for the target of a symlink, if needed
4180 . gets attributes of root directories and symlinks pointing to
4181 root directories, thus avoiding the need for special-casing
4182 these and detecting them by examining the file-name format
4183 . retrieves more accurate attributes (e.g., non-zero size for
4184 some directories, esp. directories that are junction points)
4185 . correctly resolves "c:/..", "/.." and similar file names
4186 . avoids run-time penalties for 99% of use cases
4188 Plan A is always tried first, unless the user asked not to (but
4189 if the file is a symlink and we need to follow links, we try Plan
4190 A even if the user asked not to).
4192 If Plan A fails, we go to Plan B (below), where various
4193 potentially expensive techniques must be used to handle "special"
4194 files such as UNC volumes etc. */
4195 if (!(NILP (Vw32_get_true_file_attributes
)
4196 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
4197 /* Following symlinks requires getting the info by handle. */
4198 || (is_a_symlink
&& follow_symlinks
))
4200 BY_HANDLE_FILE_INFORMATION info
;
4202 if (is_a_symlink
&& !follow_symlinks
)
4203 file_flags
|= FILE_FLAG_OPEN_REPARSE_POINT
;
4204 /* READ_CONTROL access rights are required to get security info
4205 by handle. But if the OS doesn't support security in the
4206 first place, we don't need to try. */
4207 if (is_windows_9x () != TRUE
)
4208 access_rights
|= READ_CONTROL
;
4210 fh
= CreateFile (name
, access_rights
, 0, NULL
, OPEN_EXISTING
,
4212 /* If CreateFile fails with READ_CONTROL, try again with zero as
4214 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
4215 fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
4217 if (fh
== INVALID_HANDLE_VALUE
)
4218 goto no_true_file_attributes
;
4220 /* This is more accurate in terms of getting the correct number
4221 of links, but is quite slow (it is noticeable when Emacs is
4222 making a list of file name completions). */
4223 if (GetFileInformationByHandle (fh
, &info
))
4225 nlinks
= info
.nNumberOfLinks
;
4226 /* Might as well use file index to fake inode values, but this
4227 is not guaranteed to be unique unless we keep a handle open
4228 all the time (even then there are situations where it is
4229 not unique). Reputedly, there are at most 48 bits of info
4230 (on NTFS, presumably less on FAT). */
4231 fake_inode
= info
.nFileIndexHigh
;
4233 fake_inode
+= info
.nFileIndexLow
;
4234 serialnum
= info
.dwVolumeSerialNumber
;
4235 fs_high
= info
.nFileSizeHigh
;
4236 fs_low
= info
.nFileSizeLow
;
4237 ctime
= info
.ftCreationTime
;
4238 atime
= info
.ftLastAccessTime
;
4239 wtime
= info
.ftLastWriteTime
;
4240 fattrs
= info
.dwFileAttributes
;
4244 /* We don't go to Plan B here, because it's not clear that
4245 it's a good idea. The only known use case where
4246 CreateFile succeeds, but GetFileInformationByHandle fails
4247 (with ERROR_INVALID_FUNCTION) is for character devices
4248 such as NUL, PRN, etc. For these, switching to Plan B is
4249 a net loss, because we lose the character device
4250 attribute returned by GetFileType below (FindFirstFile
4251 doesn't set that bit in the attributes), and the other
4252 fields don't make sense for character devices anyway.
4253 Emacs doesn't really care for non-file entities in the
4254 context of l?stat, so neither do we. */
4256 /* w32err is assigned so one could put a breakpoint here and
4257 examine its value, when GetFileInformationByHandle
4259 DWORD w32err
= GetLastError ();
4263 case ERROR_FILE_NOT_FOUND
: /* can this ever happen? */
4269 /* Test for a symlink before testing for a directory, since
4270 symlinks to directories have the directory bit set, but we
4271 don't want them to appear as directories. */
4272 if (is_a_symlink
&& !follow_symlinks
)
4273 buf
->st_mode
= S_IFLNK
;
4274 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4275 buf
->st_mode
= S_IFDIR
;
4278 DWORD ftype
= GetFileType (fh
);
4282 case FILE_TYPE_DISK
:
4283 buf
->st_mode
= S_IFREG
;
4285 case FILE_TYPE_PIPE
:
4286 buf
->st_mode
= S_IFIFO
;
4288 case FILE_TYPE_CHAR
:
4289 case FILE_TYPE_UNKNOWN
:
4291 buf
->st_mode
= S_IFCHR
;
4294 /* We produce the fallback owner and group data, based on the
4295 current user that runs Emacs, in the following cases:
4297 . caller didn't request owner and group info
4298 . this is Windows 9X
4299 . getting security by handle failed, and we need to produce
4300 information for the target of a symlink (this is better
4301 than producing a potentially misleading info about the
4304 If getting security by handle fails, and we don't need to
4305 resolve symlinks, we try getting security by name. */
4306 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4307 get_file_owner_and_group (NULL
, buf
);
4310 psd
= get_file_security_desc_by_handle (fh
);
4313 get_file_owner_and_group (psd
, buf
);
4316 else if (!(is_a_symlink
&& follow_symlinks
))
4318 psd
= get_file_security_desc_by_name (name
);
4319 get_file_owner_and_group (psd
, buf
);
4323 get_file_owner_and_group (NULL
, buf
);
4329 no_true_file_attributes
:
4330 /* Plan B: Either getting a handle on the file failed, or the
4331 caller explicitly asked us to not bother making this
4332 information more accurate.
4334 Implementation note: In Plan B, we never bother to resolve
4335 symlinks, even if we got here because we tried Plan A and
4336 failed. That's because, even if the caller asked for extra
4337 precision by setting Vw32_get_true_file_attributes to t,
4338 resolving symlinks requires acquiring a file handle to the
4339 symlink, which we already know will fail. And if the user
4340 did not ask for extra precision, resolving symlinks will fly
4341 in the face of that request, since the user then wants the
4342 lightweight version of the code. */
4343 dbcs_p
= max_filename_mbslen () > 1;
4344 rootdir
= (path
>= save_name
+ len
- 1
4345 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
4347 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4348 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
4349 if (IS_DIRECTORY_SEP (r
[0])
4350 && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
4353 /* Note: If NAME is a symlink to the root of a UNC volume
4354 (i.e. "\\SERVER"), we will not detect that here, and we will
4355 return data about the symlink as result of FindFirst below.
4356 This is unfortunate, but that marginal use case does not
4357 justify a call to chase_symlinks which would impose a penalty
4358 on all the other use cases. (We get here for symlinks to
4359 roots of UNC volumes because CreateFile above fails for them,
4360 unlike with symlinks to root directories X:\ of drives.) */
4361 if (is_unc_volume (name
))
4363 fattrs
= unc_volume_file_attributes (name
);
4367 ctime
= atime
= wtime
= utc_base_ft
;
4373 if (!IS_DIRECTORY_SEP (name
[len
-1]))
4374 strcat (name
, "\\");
4378 char *end
= name
+ len
;
4379 char *n
= CharPrevExA (file_name_codepage
, name
, end
, 0);
4381 if (!IS_DIRECTORY_SEP (*n
))
4382 strcat (name
, "\\");
4384 if (GetDriveType (name
) < 2)
4390 fattrs
= FILE_ATTRIBUTE_DIRECTORY
;
4391 ctime
= atime
= wtime
= utc_base_ft
;
4397 if (IS_DIRECTORY_SEP (name
[len
-1]))
4402 char *end
= name
+ len
;
4403 char *n
= CharPrevExA (file_name_codepage
, name
, end
, 0);
4405 if (IS_DIRECTORY_SEP (*n
))
4409 /* (This is hacky, but helps when doing file completions on
4410 network drives.) Optimize by using information available from
4411 active readdir if possible. */
4412 len
= strlen (dir_pathname
);
4415 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
4420 char *end
= dir_pathname
+ len
;
4421 char *n
= CharPrevExA (file_name_codepage
, dir_pathname
, end
, 0);
4423 if (IS_DIRECTORY_SEP (*n
))
4426 if (dir_find_handle
!= INVALID_HANDLE_VALUE
4427 && !(is_a_symlink
&& follow_symlinks
)
4428 && strnicmp (save_name
, dir_pathname
, len
) == 0
4429 && IS_DIRECTORY_SEP (name
[len
])
4430 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
4432 /* This was the last entry returned by readdir. */
4433 wfd
= dir_find_data_a
; /* FIXME!!! */
4437 logon_network_drive (name
);
4439 fh
= FindFirstFile (name
, &wfd
);
4440 if (fh
== INVALID_HANDLE_VALUE
)
4447 /* Note: if NAME is a symlink, the information we get from
4448 FindFirstFile is for the symlink, not its target. */
4449 fattrs
= wfd
.dwFileAttributes
;
4450 ctime
= wfd
.ftCreationTime
;
4451 atime
= wfd
.ftLastAccessTime
;
4452 wtime
= wfd
.ftLastWriteTime
;
4453 fs_high
= wfd
.nFileSizeHigh
;
4454 fs_low
= wfd
.nFileSizeLow
;
4457 serialnum
= volume_info
.serialnum
;
4459 if (is_a_symlink
&& !follow_symlinks
)
4460 buf
->st_mode
= S_IFLNK
;
4461 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4462 buf
->st_mode
= S_IFDIR
;
4464 buf
->st_mode
= S_IFREG
;
4466 get_file_owner_and_group (NULL
, buf
);
4470 /* Not sure if there is any point in this. */
4471 if (!NILP (Vw32_generate_fake_inodes
))
4472 fake_inode
= generate_inode_val (name
);
4473 else if (fake_inode
== 0)
4475 /* For want of something better, try to make everything unique. */
4476 static DWORD gen_num
= 0;
4477 fake_inode
= ++gen_num
;
4481 buf
->st_ino
= fake_inode
;
4483 buf
->st_dev
= serialnum
;
4484 buf
->st_rdev
= serialnum
;
4486 buf
->st_size
= fs_high
;
4487 buf
->st_size
<<= 32;
4488 buf
->st_size
+= fs_low
;
4489 buf
->st_nlink
= nlinks
;
4491 /* Convert timestamps to Unix format. */
4492 buf
->st_mtime
= convert_time (wtime
);
4493 buf
->st_atime
= convert_time (atime
);
4494 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4495 buf
->st_ctime
= convert_time (ctime
);
4496 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4498 /* determine rwx permissions */
4499 if (is_a_symlink
&& !follow_symlinks
)
4500 permission
= S_IREAD
| S_IWRITE
| S_IEXEC
; /* Posix expectations */
4503 if (fattrs
& FILE_ATTRIBUTE_READONLY
)
4504 permission
= S_IREAD
;
4506 permission
= S_IREAD
| S_IWRITE
;
4508 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4509 permission
|= S_IEXEC
;
4510 else if (is_exec (name
))
4511 permission
|= S_IEXEC
;
4514 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4520 stat (const char * path
, struct stat
* buf
)
4522 return stat_worker (path
, buf
, 1);
4526 lstat (const char * path
, struct stat
* buf
)
4528 return stat_worker (path
, buf
, 0);
4532 fstatat (int fd
, char const *name
, struct stat
*st
, int flags
)
4534 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4535 This is good enough for the current usage in Emacs, but is fragile.
4537 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4538 Gnulib does this and can serve as a model. */
4539 char fullname
[MAX_PATH
];
4543 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
4546 errno
= ENAMETOOLONG
;
4552 return stat_worker (name
, st
, ! (flags
& AT_SYMLINK_NOFOLLOW
));
4555 /* Provide fstat and utime as well as stat for consistent handling of
4558 fstat (int desc
, struct stat
* buf
)
4560 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
4561 BY_HANDLE_FILE_INFORMATION info
;
4562 unsigned __int64 fake_inode
;
4565 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
4567 case FILE_TYPE_DISK
:
4568 buf
->st_mode
= S_IFREG
;
4569 if (!GetFileInformationByHandle (fh
, &info
))
4575 case FILE_TYPE_PIPE
:
4576 buf
->st_mode
= S_IFIFO
;
4578 case FILE_TYPE_CHAR
:
4579 case FILE_TYPE_UNKNOWN
:
4581 buf
->st_mode
= S_IFCHR
;
4583 memset (&info
, 0, sizeof (info
));
4584 info
.dwFileAttributes
= 0;
4585 info
.ftCreationTime
= utc_base_ft
;
4586 info
.ftLastAccessTime
= utc_base_ft
;
4587 info
.ftLastWriteTime
= utc_base_ft
;
4590 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4591 buf
->st_mode
= S_IFDIR
;
4593 buf
->st_nlink
= info
.nNumberOfLinks
;
4594 /* Might as well use file index to fake inode values, but this
4595 is not guaranteed to be unique unless we keep a handle open
4596 all the time (even then there are situations where it is
4597 not unique). Reputedly, there are at most 48 bits of info
4598 (on NTFS, presumably less on FAT). */
4599 fake_inode
= info
.nFileIndexHigh
;
4601 fake_inode
+= info
.nFileIndexLow
;
4603 /* MSVC defines _ino_t to be short; other libc's might not. */
4604 if (sizeof (buf
->st_ino
) == 2)
4605 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
4607 buf
->st_ino
= fake_inode
;
4609 /* If the caller so requested, get the true file owner and group.
4610 Otherwise, consider the file to belong to the current user. */
4611 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4612 get_file_owner_and_group (NULL
, buf
);
4615 PSECURITY_DESCRIPTOR psd
= NULL
;
4617 psd
= get_file_security_desc_by_handle (fh
);
4620 get_file_owner_and_group (psd
, buf
);
4624 get_file_owner_and_group (NULL
, buf
);
4627 buf
->st_dev
= info
.dwVolumeSerialNumber
;
4628 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
4630 buf
->st_size
= info
.nFileSizeHigh
;
4631 buf
->st_size
<<= 32;
4632 buf
->st_size
+= info
.nFileSizeLow
;
4634 /* Convert timestamps to Unix format. */
4635 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
4636 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
4637 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4638 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
4639 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4641 /* determine rwx permissions */
4642 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
4643 permission
= S_IREAD
;
4645 permission
= S_IREAD
| S_IWRITE
;
4647 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4648 permission
|= S_IEXEC
;
4651 #if 0 /* no way of knowing the filename */
4652 char * p
= strrchr (name
, '.');
4654 (xstrcasecmp (p
, ".exe") == 0 ||
4655 xstrcasecmp (p
, ".com") == 0 ||
4656 xstrcasecmp (p
, ".bat") == 0 ||
4657 xstrcasecmp (p
, ".cmd") == 0))
4658 permission
|= S_IEXEC
;
4662 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4667 /* A version of 'utime' which handles directories as well as
4671 utime (const char *name
, struct utimbuf
*times
)
4673 struct utimbuf deftime
;
4680 deftime
.modtime
= deftime
.actime
= time (NULL
);
4684 if (w32_unicode_filenames
)
4686 wchar_t name_utf16
[MAX_PATH
];
4688 if (filename_to_utf16 (name
, name_utf16
) != 0)
4689 return -1; /* errno set by filename_to_utf16 */
4691 /* Need write access to set times. */
4692 fh
= CreateFileW (name_utf16
, FILE_WRITE_ATTRIBUTES
,
4693 /* If NAME specifies a directory, FILE_SHARE_DELETE
4694 allows other processes to delete files inside it,
4695 while we have the directory open. */
4696 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
4697 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
4701 char name_ansi
[MAX_PATH
];
4703 if (filename_to_ansi (name
, name_ansi
) != 0)
4704 return -1; /* errno set by filename_to_ansi */
4706 fh
= CreateFileA (name_ansi
, FILE_WRITE_ATTRIBUTES
,
4707 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
4708 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
4710 if (fh
!= INVALID_HANDLE_VALUE
)
4712 convert_from_time_t (times
->actime
, &atime
);
4713 convert_from_time_t (times
->modtime
, &mtime
);
4714 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
4724 DWORD err
= GetLastError ();
4728 case ERROR_FILE_NOT_FOUND
:
4729 case ERROR_PATH_NOT_FOUND
:
4730 case ERROR_INVALID_DRIVE
:
4731 case ERROR_BAD_NETPATH
:
4732 case ERROR_DEV_NOT_EXIST
:
4733 /* ERROR_INVALID_NAME is the error CreateFile sets when the
4734 file name includes ?s, i.e. translation to ANSI failed. */
4735 case ERROR_INVALID_NAME
:
4738 case ERROR_TOO_MANY_OPEN_FILES
:
4741 case ERROR_ACCESS_DENIED
:
4742 case ERROR_SHARING_VIOLATION
:
4755 /* Symlink-related functions. */
4756 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4757 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4761 symlink (char const *filename
, char const *linkname
)
4763 char linkfn
[MAX_PATH
], *tgtfn
;
4765 int dir_access
, filename_ends_in_slash
;
4768 /* Diagnostics follows Posix as much as possible. */
4769 if (filename
== NULL
|| linkname
== NULL
)
4779 if (strlen (filename
) > MAX_PATH
|| strlen (linkname
) > MAX_PATH
)
4781 errno
= ENAMETOOLONG
;
4785 strcpy (linkfn
, map_w32_filename (linkname
, NULL
));
4786 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0)
4792 dbcs_p
= max_filename_mbslen () > 1;
4794 /* Note: since empty FILENAME was already rejected, we can safely
4795 refer to FILENAME[1]. */
4796 if (!(IS_DIRECTORY_SEP (filename
[0]) || IS_DEVICE_SEP (filename
[1])))
4798 /* Non-absolute FILENAME is understood as being relative to
4799 LINKNAME's directory. We need to prepend that directory to
4800 FILENAME to get correct results from faccessat below, since
4801 otherwise it will interpret FILENAME relative to the
4802 directory where the Emacs process runs. Note that
4803 make-symbolic-link always makes sure LINKNAME is a fully
4804 expanded file name. */
4806 char *p
= linkfn
+ strlen (linkfn
);
4810 while (p
> linkfn
&& !IS_ANY_SEP (p
[-1]))
4815 char *p1
= CharPrevExA (file_name_codepage
, linkfn
, p
, 0);
4817 while (p
> linkfn
&& !IS_ANY_SEP (*p1
))
4820 p1
= CharPrevExA (file_name_codepage
, linkfn
, p1
, 0);
4824 strncpy (tem
, linkfn
, p
- linkfn
);
4825 tem
[p
- linkfn
] = '\0';
4826 strcat (tem
, filename
);
4827 dir_access
= faccessat (AT_FDCWD
, tem
, D_OK
, AT_EACCESS
);
4830 dir_access
= faccessat (AT_FDCWD
, filename
, D_OK
, AT_EACCESS
);
4832 /* Since Windows distinguishes between symlinks to directories and
4833 to files, we provide a kludgy feature: if FILENAME doesn't
4834 exist, but ends in a slash, we create a symlink to directory. If
4835 FILENAME exists and is a directory, we always create a symlink to
4838 filename_ends_in_slash
= IS_DIRECTORY_SEP (filename
[strlen (filename
) - 1]);
4841 const char *end
= filename
+ strlen (filename
);
4842 const char *n
= CharPrevExA (file_name_codepage
, filename
, end
, 0);
4844 filename_ends_in_slash
= IS_DIRECTORY_SEP (*n
);
4846 if (dir_access
== 0 || filename_ends_in_slash
)
4847 flags
= SYMBOLIC_LINK_FLAG_DIRECTORY
;
4849 tgtfn
= (char *)map_w32_filename (filename
, NULL
);
4850 if (filename_ends_in_slash
)
4851 tgtfn
[strlen (tgtfn
) - 1] = '\0';
4854 if (!create_symbolic_link (linkfn
, tgtfn
, flags
))
4856 /* ENOSYS is set by create_symbolic_link, when it detects that
4857 the OS doesn't support the CreateSymbolicLink API. */
4858 if (errno
!= ENOSYS
)
4860 DWORD w32err
= GetLastError ();
4864 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4865 TGTFN point to the same file name, go figure. */
4867 case ERROR_FILE_EXISTS
:
4870 case ERROR_ACCESS_DENIED
:
4873 case ERROR_FILE_NOT_FOUND
:
4874 case ERROR_PATH_NOT_FOUND
:
4875 case ERROR_BAD_NETPATH
:
4876 case ERROR_INVALID_REPARSE_DATA
:
4879 case ERROR_DIRECTORY
:
4882 case ERROR_PRIVILEGE_NOT_HELD
:
4883 case ERROR_NOT_ALL_ASSIGNED
:
4886 case ERROR_DISK_FULL
:
4899 /* A quick inexpensive test of whether FILENAME identifies a file that
4900 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4901 must already be in the normalized form returned by
4904 Note: for repeated operations on many files, it is best to test
4905 whether the underlying volume actually supports symlinks, by
4906 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4907 avoid the call to this function if it doesn't. That's because the
4908 call to GetFileAttributes takes a non-negligible time, especially
4909 on non-local or removable filesystems. See stat_worker for an
4910 example of how to do that. */
4912 is_symlink (const char *filename
)
4915 WIN32_FIND_DATA wfd
;
4918 attrs
= GetFileAttributes (filename
);
4921 DWORD w32err
= GetLastError ();
4925 case ERROR_BAD_NETPATH
: /* network share, can't be a symlink */
4927 case ERROR_ACCESS_DENIED
:
4930 case ERROR_FILE_NOT_FOUND
:
4931 case ERROR_PATH_NOT_FOUND
:
4938 if ((attrs
& FILE_ATTRIBUTE_REPARSE_POINT
) == 0)
4940 logon_network_drive (filename
);
4941 fh
= FindFirstFile (filename
, &wfd
);
4942 if (fh
== INVALID_HANDLE_VALUE
)
4945 return (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
4946 && (wfd
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
4949 /* If NAME identifies a symbolic link, copy into BUF the file name of
4950 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4951 null-terminate the target name, even if it fits. Return the number
4952 of bytes copied, or -1 if NAME is not a symlink or any error was
4953 encountered while resolving it. The file name copied into BUF is
4954 encoded in the current ANSI codepage. */
4956 readlink (const char *name
, char *buf
, size_t buf_size
)
4959 TOKEN_PRIVILEGES privs
;
4960 int restore_privs
= 0;
4975 path
= map_w32_filename (name
, NULL
);
4977 if (strlen (path
) > MAX_PATH
)
4979 errno
= ENAMETOOLONG
;
4984 if (is_windows_9x () == TRUE
4985 || (volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0
4986 || !is_symlink (path
))
4989 errno
= EINVAL
; /* not a symlink */
4993 /* Done with simple tests, now we're in for some _real_ work. */
4994 if (enable_privilege (SE_BACKUP_NAME
, TRUE
, &privs
))
4996 /* Implementation note: From here and onward, don't return early,
4997 since that will fail to restore the original set of privileges of
4998 the calling thread. */
5000 retval
= -1; /* not too optimistic, are we? */
5002 /* Note: In the next call to CreateFile, we use zero as the 2nd
5003 argument because, when the symlink is a hidden/system file,
5004 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5005 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5006 and directory symlinks. */
5007 sh
= CreateFile (path
, 0, 0, NULL
, OPEN_EXISTING
,
5008 FILE_FLAG_OPEN_REPARSE_POINT
| FILE_FLAG_BACKUP_SEMANTICS
,
5010 if (sh
!= INVALID_HANDLE_VALUE
)
5012 BYTE reparse_buf
[MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
5013 REPARSE_DATA_BUFFER
*reparse_data
= (REPARSE_DATA_BUFFER
*)&reparse_buf
[0];
5016 if (!DeviceIoControl (sh
, FSCTL_GET_REPARSE_POINT
, NULL
, 0,
5017 reparse_buf
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
5020 else if (reparse_data
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
5024 /* Copy the link target name, in wide characters, from
5025 reparse_data, then convert it to multibyte encoding in
5026 the current locale's codepage. */
5028 BYTE lname
[MAX_PATH
];
5031 reparse_data
->SymbolicLinkReparseBuffer
.PrintNameLength
;
5033 reparse_data
->SymbolicLinkReparseBuffer
.PathBuffer
5034 + reparse_data
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
);
5035 /* This updates file_name_codepage which we need below. */
5036 int dbcs_p
= max_filename_mbslen () > 1;
5038 /* According to MSDN, PrintNameLength does not include the
5039 terminating null character. */
5040 lwname
= alloca ((lwname_len
+ 1) * sizeof(WCHAR
));
5041 memcpy (lwname
, lwname_src
, lwname_len
);
5042 lwname
[lwname_len
/sizeof(WCHAR
)] = 0; /* null-terminate */
5044 lname_len
= WideCharToMultiByte (file_name_codepage
, 0, lwname
, -1,
5045 lname
, MAX_PATH
, NULL
, NULL
);
5048 /* WideCharToMultiByte failed. */
5049 DWORD w32err1
= GetLastError ();
5053 case ERROR_INSUFFICIENT_BUFFER
:
5054 errno
= ENAMETOOLONG
;
5056 case ERROR_INVALID_PARAMETER
:
5059 case ERROR_NO_UNICODE_TRANSLATION
:
5069 size_t size_to_copy
= buf_size
;
5070 BYTE
*p
= lname
, *p2
;
5071 BYTE
*pend
= p
+ lname_len
;
5073 /* Normalize like dostounix_filename does, but we don't
5074 want to assume that lname is null-terminated. */
5076 p2
= CharNextExA (file_name_codepage
, p
, 0);
5079 if (*p
&& *p2
== ':' && *p
>= 'A' && *p
<= 'Z')
5090 p
= CharNextExA (file_name_codepage
, p
, 0);
5091 /* CharNextExA doesn't advance at null character. */
5098 /* Testing for null-terminated LNAME is paranoia:
5099 WideCharToMultiByte should always return a
5100 null-terminated string when its 4th argument is -1
5101 and its 3rd argument is null-terminated (which they
5103 if (lname
[lname_len
- 1] == '\0')
5105 if (lname_len
<= buf_size
)
5106 size_to_copy
= lname_len
;
5107 strncpy (buf
, lname
, size_to_copy
);
5109 retval
= size_to_copy
;
5116 /* CreateFile failed. */
5117 DWORD w32err2
= GetLastError ();
5121 case ERROR_FILE_NOT_FOUND
:
5122 case ERROR_PATH_NOT_FOUND
:
5125 case ERROR_ACCESS_DENIED
:
5126 case ERROR_TOO_MANY_OPEN_FILES
:
5136 restore_privilege (&privs
);
5144 readlinkat (int fd
, char const *name
, char *buffer
,
5147 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5148 as in fstatat. FIXME: Add proper support for readlinkat. */
5149 char fullname
[MAX_PATH
];
5153 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
5156 errno
= ENAMETOOLONG
;
5162 return readlink (name
, buffer
, buffer_size
);
5165 /* If FILE is a symlink, return its target (stored in a static
5166 buffer); otherwise return FILE.
5168 This function repeatedly resolves symlinks in the last component of
5169 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5170 until it arrives at a file whose last component is not a symlink,
5171 or some error occurs. It returns the target of the last
5172 successfully resolved symlink in the chain. If it succeeds to
5173 resolve even a single symlink, the value returned is an absolute
5174 file name with backslashes (result of GetFullPathName). By
5175 contrast, if the original FILE is returned, it is unaltered.
5177 Note: This function can set errno even if it succeeds.
5179 Implementation note: we only resolve the last portion ("basename")
5180 of the argument FILE and of each following file in the chain,
5181 disregarding any possible symlinks in its leading directories.
5182 This is because Windows system calls and library functions
5183 transparently resolve symlinks in leading directories and return
5184 correct information, as long as the basename is not a symlink. */
5186 chase_symlinks (const char *file
)
5188 static char target
[MAX_PATH
];
5189 char link
[MAX_PATH
];
5190 ssize_t res
, link_len
;
5194 if (is_windows_9x () == TRUE
|| !is_symlink (file
))
5195 return (char *)file
;
5197 if ((link_len
= GetFullPathName (file
, MAX_PATH
, link
, NULL
)) == 0)
5198 return (char *)file
;
5200 dbcs_p
= max_filename_mbslen () > 1;
5204 /* Remove trailing slashes, as we want to resolve the last
5205 non-trivial part of the link name. */
5208 while (link_len
> 3 && IS_DIRECTORY_SEP (link
[link_len
-1]))
5209 link
[link_len
--] = '\0';
5211 else if (link_len
> 3)
5213 char *n
= CharPrevExA (file_name_codepage
, link
, link
+ link_len
, 0);
5215 while (n
>= link
+ 2 && IS_DIRECTORY_SEP (*n
))
5218 n
= CharPrevExA (file_name_codepage
, link
, n
, 0);
5222 res
= readlink (link
, target
, MAX_PATH
);
5226 if (!(IS_DEVICE_SEP (target
[1])
5227 || (IS_DIRECTORY_SEP (target
[0]) && IS_DIRECTORY_SEP (target
[1]))))
5229 /* Target is relative. Append it to the directory part of
5230 the symlink, then copy the result back to target. */
5231 char *p
= link
+ link_len
;
5235 while (p
> link
&& !IS_ANY_SEP (p
[-1]))
5240 char *p1
= CharPrevExA (file_name_codepage
, link
, p
, 0);
5242 while (p
> link
&& !IS_ANY_SEP (*p1
))
5245 p1
= CharPrevExA (file_name_codepage
, link
, p1
, 0);
5249 strcpy (target
, link
);
5251 /* Resolve any "." and ".." to get a fully-qualified file name
5253 link_len
= GetFullPathName (target
, MAX_PATH
, link
, NULL
);
5255 } while (res
> 0 && link_len
> 0 && ++loop_count
<= 100);
5257 if (loop_count
> 100)
5260 if (target
[0] == '\0') /* not a single call to readlink succeeded */
5261 return (char *)file
;
5266 /* Posix ACL emulation. */
5269 acl_valid (acl_t acl
)
5271 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR
)acl
) ? 0 : -1;
5275 acl_to_text (acl_t acl
, ssize_t
*size
)
5278 SECURITY_INFORMATION flags
=
5279 OWNER_SECURITY_INFORMATION
|
5280 GROUP_SECURITY_INFORMATION
|
5281 DACL_SECURITY_INFORMATION
;
5282 char *retval
= NULL
;
5288 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR
)acl
, SDDL_REVISION_1
, flags
, &str_acl
, &local_size
))
5291 /* We don't want to mix heaps, so we duplicate the string in our
5292 heap and free the one allocated by the API. */
5293 retval
= xstrdup (str_acl
);
5296 LocalFree (str_acl
);
5298 else if (errno
!= ENOTSUP
)
5305 acl_from_text (const char *acl_str
)
5307 PSECURITY_DESCRIPTOR psd
, retval
= NULL
;
5313 if (convert_sddl_to_sd (acl_str
, SDDL_REVISION_1
, &psd
, &sd_size
))
5316 retval
= xmalloc (sd_size
);
5317 memcpy (retval
, psd
, sd_size
);
5320 else if (errno
!= ENOTSUP
)
5327 acl_free (void *ptr
)
5334 acl_get_file (const char *fname
, acl_type_t type
)
5336 PSECURITY_DESCRIPTOR psd
= NULL
;
5337 const char *filename
;
5339 if (type
== ACL_TYPE_ACCESS
)
5342 SECURITY_INFORMATION si
=
5343 OWNER_SECURITY_INFORMATION
|
5344 GROUP_SECURITY_INFORMATION
|
5345 DACL_SECURITY_INFORMATION
;
5348 filename
= map_w32_filename (fname
, NULL
);
5349 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5350 fname
= chase_symlinks (filename
);
5355 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
)
5356 && errno
!= ENOTSUP
)
5358 err
= GetLastError ();
5359 if (err
== ERROR_INSUFFICIENT_BUFFER
)
5361 psd
= xmalloc (sd_len
);
5362 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
5369 else if (err
== ERROR_FILE_NOT_FOUND
5370 || err
== ERROR_PATH_NOT_FOUND
)
5378 else if (type
!= ACL_TYPE_DEFAULT
)
5385 acl_set_file (const char *fname
, acl_type_t type
, acl_t acl
)
5387 TOKEN_PRIVILEGES old1
, old2
;
5389 int st
= 0, retval
= -1;
5390 SECURITY_INFORMATION flags
= 0;
5396 const char *filename
;
5398 if (acl_valid (acl
) != 0
5399 || (type
!= ACL_TYPE_DEFAULT
&& type
!= ACL_TYPE_ACCESS
))
5405 if (type
== ACL_TYPE_DEFAULT
)
5411 filename
= map_w32_filename (fname
, NULL
);
5412 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5413 fname
= chase_symlinks (filename
);
5417 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5419 flags
|= OWNER_SECURITY_INFORMATION
;
5420 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5422 flags
|= GROUP_SECURITY_INFORMATION
;
5423 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR
)acl
, &dacl_present
,
5426 flags
|= DACL_SECURITY_INFORMATION
;
5430 /* According to KB-245153, setting the owner will succeed if either:
5431 (1) the caller is the user who will be the new owner, and has the
5432 SE_TAKE_OWNERSHIP privilege, or
5433 (2) the caller has the SE_RESTORE privilege, in which case she can
5434 set any valid user or group as the owner
5436 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5437 privileges, and disregard any failures in obtaining them. If
5438 these privileges cannot be obtained, and do not already exist in
5439 the calling thread's security token, this function could fail
5441 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME
, TRUE
, &old1
))
5443 if (enable_privilege (SE_RESTORE_NAME
, TRUE
, &old2
))
5448 if (!set_file_security ((char *)fname
, flags
, (PSECURITY_DESCRIPTOR
)acl
))
5450 err
= GetLastError ();
5452 if (errno
== ENOTSUP
)
5454 else if (err
== ERROR_INVALID_OWNER
5455 || err
== ERROR_NOT_ALL_ASSIGNED
5456 || err
== ERROR_ACCESS_DENIED
)
5458 /* Maybe the requested ACL and the one the file already has
5459 are identical, in which case we can silently ignore the
5460 failure. (And no, Windows doesn't.) */
5461 acl_t current_acl
= acl_get_file (fname
, ACL_TYPE_ACCESS
);
5466 char *acl_from
= acl_to_text (current_acl
, NULL
);
5467 char *acl_to
= acl_to_text (acl
, NULL
);
5469 if (acl_from
&& acl_to
&& xstrcasecmp (acl_from
, acl_to
) == 0)
5475 acl_free (acl_from
);
5478 acl_free (current_acl
);
5481 else if (err
== ERROR_FILE_NOT_FOUND
|| err
== ERROR_PATH_NOT_FOUND
)
5495 restore_privilege (&old2
);
5496 restore_privilege (&old1
);
5504 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5505 have a fixed max size for file names, so we don't need the kind of
5506 alloc/malloc/realloc dance the gnulib version does. We also don't
5507 support FD-relative symlinks. */
5509 careadlinkat (int fd
, char const *filename
,
5510 char *buffer
, size_t buffer_size
,
5511 struct allocator
const *alloc
,
5512 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
5514 char linkname
[MAX_PATH
];
5517 link_size
= preadlinkat (fd
, filename
, linkname
, sizeof(linkname
));
5521 char *retval
= buffer
;
5523 linkname
[link_size
++] = '\0';
5524 if (link_size
> buffer_size
)
5525 retval
= (char *)(alloc
? alloc
->allocate
: xmalloc
) (link_size
);
5527 memcpy (retval
, linkname
, link_size
);
5535 /* Support for browsing other processes and their attributes. See
5536 process.c for the Lisp bindings. */
5538 /* Helper wrapper functions. */
5540 static HANDLE WINAPI
5541 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
5543 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
5545 if (g_b_init_create_toolhelp32_snapshot
== 0)
5547 g_b_init_create_toolhelp32_snapshot
= 1;
5548 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
5549 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5550 "CreateToolhelp32Snapshot");
5552 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
5554 return INVALID_HANDLE_VALUE
;
5556 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
5560 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5562 static Process32First_Proc s_pfn_Process32_First
= NULL
;
5564 if (g_b_init_process32_first
== 0)
5566 g_b_init_process32_first
= 1;
5567 s_pfn_Process32_First
= (Process32First_Proc
)
5568 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5571 if (s_pfn_Process32_First
== NULL
)
5575 return (s_pfn_Process32_First (hSnapshot
, lppe
));
5579 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5581 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
5583 if (g_b_init_process32_next
== 0)
5585 g_b_init_process32_next
= 1;
5586 s_pfn_Process32_Next
= (Process32Next_Proc
)
5587 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5590 if (s_pfn_Process32_Next
== NULL
)
5594 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
5598 open_thread_token (HANDLE ThreadHandle
,
5599 DWORD DesiredAccess
,
5601 PHANDLE TokenHandle
)
5603 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
5604 HMODULE hm_advapi32
= NULL
;
5605 if (is_windows_9x () == TRUE
)
5607 SetLastError (ERROR_NOT_SUPPORTED
);
5610 if (g_b_init_open_thread_token
== 0)
5612 g_b_init_open_thread_token
= 1;
5613 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5614 s_pfn_Open_Thread_Token
=
5615 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
5617 if (s_pfn_Open_Thread_Token
== NULL
)
5619 SetLastError (ERROR_NOT_SUPPORTED
);
5623 s_pfn_Open_Thread_Token (
5632 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
5634 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
5635 HMODULE hm_advapi32
= NULL
;
5636 if (is_windows_9x () == TRUE
)
5640 if (g_b_init_impersonate_self
== 0)
5642 g_b_init_impersonate_self
= 1;
5643 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5644 s_pfn_Impersonate_Self
=
5645 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
5647 if (s_pfn_Impersonate_Self
== NULL
)
5651 return s_pfn_Impersonate_Self (ImpersonationLevel
);
5655 revert_to_self (void)
5657 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
5658 HMODULE hm_advapi32
= NULL
;
5659 if (is_windows_9x () == TRUE
)
5663 if (g_b_init_revert_to_self
== 0)
5665 g_b_init_revert_to_self
= 1;
5666 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5667 s_pfn_Revert_To_Self
=
5668 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
5670 if (s_pfn_Revert_To_Self
== NULL
)
5674 return s_pfn_Revert_To_Self ();
5678 get_process_memory_info (HANDLE h_proc
,
5679 PPROCESS_MEMORY_COUNTERS mem_counters
,
5682 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
5683 HMODULE hm_psapi
= NULL
;
5684 if (is_windows_9x () == TRUE
)
5688 if (g_b_init_get_process_memory_info
== 0)
5690 g_b_init_get_process_memory_info
= 1;
5691 hm_psapi
= LoadLibrary ("Psapi.dll");
5693 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
5694 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
5696 if (s_pfn_Get_Process_Memory_Info
== NULL
)
5700 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
5704 get_process_working_set_size (HANDLE h_proc
,
5708 static GetProcessWorkingSetSize_Proc
5709 s_pfn_Get_Process_Working_Set_Size
= NULL
;
5711 if (is_windows_9x () == TRUE
)
5715 if (g_b_init_get_process_working_set_size
== 0)
5717 g_b_init_get_process_working_set_size
= 1;
5718 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
5719 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5720 "GetProcessWorkingSetSize");
5722 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
5726 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
5730 global_memory_status (MEMORYSTATUS
*buf
)
5732 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
5734 if (is_windows_9x () == TRUE
)
5738 if (g_b_init_global_memory_status
== 0)
5740 g_b_init_global_memory_status
= 1;
5741 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
5742 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5743 "GlobalMemoryStatus");
5745 if (s_pfn_Global_Memory_Status
== NULL
)
5749 return s_pfn_Global_Memory_Status (buf
);
5753 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
5755 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
5757 if (is_windows_9x () == TRUE
)
5761 if (g_b_init_global_memory_status_ex
== 0)
5763 g_b_init_global_memory_status_ex
= 1;
5764 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
5765 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5766 "GlobalMemoryStatusEx");
5768 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
5772 return s_pfn_Global_Memory_Status_Ex (buf
);
5776 list_system_processes (void)
5778 struct gcpro gcpro1
;
5779 Lisp_Object proclist
= Qnil
;
5782 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
5784 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
5786 PROCESSENTRY32 proc_entry
;
5792 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
5793 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
5794 res
= process32_next (h_snapshot
, &proc_entry
))
5796 proc_id
= proc_entry
.th32ProcessID
;
5797 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
5800 CloseHandle (h_snapshot
);
5802 proclist
= Fnreverse (proclist
);
5809 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
5811 TOKEN_PRIVILEGES priv
;
5812 DWORD priv_size
= sizeof (priv
);
5813 DWORD opriv_size
= sizeof (*old_priv
);
5814 HANDLE h_token
= NULL
;
5815 HANDLE h_thread
= GetCurrentThread ();
5819 res
= open_thread_token (h_thread
,
5820 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5822 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
5824 if (impersonate_self (SecurityImpersonation
))
5825 res
= open_thread_token (h_thread
,
5826 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5831 priv
.PrivilegeCount
= 1;
5832 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
5833 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
5834 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
5835 old_priv
, &opriv_size
)
5836 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
5840 CloseHandle (h_token
);
5846 restore_privilege (TOKEN_PRIVILEGES
*priv
)
5848 DWORD priv_size
= sizeof (*priv
);
5849 HANDLE h_token
= NULL
;
5852 if (open_thread_token (GetCurrentThread (),
5853 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5856 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
5857 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
5861 CloseHandle (h_token
);
5867 ltime (ULONGLONG time_100ns
)
5869 ULONGLONG time_sec
= time_100ns
/ 10000000;
5870 int subsec
= time_100ns
% 10000000;
5871 return list4i (time_sec
>> 16, time_sec
& 0xffff,
5872 subsec
/ 10, subsec
% 10 * 100000);
5875 #define U64_TO_LISP_TIME(time) ltime (time)
5878 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
5879 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
5882 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
5883 ULONGLONG tem1
, tem2
, tem3
, tem
;
5886 || !get_process_times_fn
5887 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
5888 &ft_kernel
, &ft_user
))
5891 GetSystemTimeAsFileTime (&ft_current
);
5893 FILETIME_TO_U64 (tem1
, ft_kernel
);
5894 *stime
= U64_TO_LISP_TIME (tem1
);
5896 FILETIME_TO_U64 (tem2
, ft_user
);
5897 *utime
= U64_TO_LISP_TIME (tem2
);
5900 *ttime
= U64_TO_LISP_TIME (tem3
);
5902 FILETIME_TO_U64 (tem
, ft_creation
);
5903 /* Process no 4 (System) returns zero creation time. */
5906 *ctime
= U64_TO_LISP_TIME (tem
);
5910 FILETIME_TO_U64 (tem3
, ft_current
);
5911 tem
= (tem3
- utc_base
) - tem
;
5913 *etime
= U64_TO_LISP_TIME (tem
);
5917 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
5928 system_process_attributes (Lisp_Object pid
)
5930 struct gcpro gcpro1
, gcpro2
, gcpro3
;
5931 Lisp_Object attrs
= Qnil
;
5932 Lisp_Object cmd_str
, decoded_cmd
, tem
;
5933 HANDLE h_snapshot
, h_proc
;
5936 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
5937 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
5938 DWORD glength
= sizeof (gname
);
5939 HANDLE token
= NULL
;
5940 SID_NAME_USE user_type
;
5941 unsigned char *buf
= NULL
;
5943 TOKEN_USER user_token
;
5944 TOKEN_PRIMARY_GROUP group_token
;
5947 PROCESS_MEMORY_COUNTERS mem
;
5948 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
5949 SIZE_T minrss
, maxrss
;
5951 MEMORY_STATUS_EX memstex
;
5952 double totphys
= 0.0;
5953 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
5955 BOOL result
= FALSE
;
5957 CHECK_NUMBER_OR_FLOAT (pid
);
5958 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
5960 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
5962 GCPRO3 (attrs
, decoded_cmd
, tem
);
5964 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
5969 pe
.dwSize
= sizeof (PROCESSENTRY32
);
5970 for (res
= process32_first (h_snapshot
, &pe
); res
;
5971 res
= process32_next (h_snapshot
, &pe
))
5973 if (proc_id
== pe
.th32ProcessID
)
5976 decoded_cmd
= build_string ("Idle");
5979 /* Decode the command name from locale-specific
5981 cmd_str
= build_unibyte_string (pe
.szExeFile
);
5984 code_convert_string_norecord (cmd_str
,
5985 Vlocale_coding_system
, 0);
5987 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
5988 attrs
= Fcons (Fcons (Qppid
,
5989 make_fixnum_or_float (pe
.th32ParentProcessID
)),
5991 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
5993 attrs
= Fcons (Fcons (Qthcount
,
5994 make_fixnum_or_float (pe
.cntThreads
)),
6001 CloseHandle (h_snapshot
);
6010 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
6012 /* If we were denied a handle to the process, try again after
6013 enabling the SeDebugPrivilege in our process. */
6016 TOKEN_PRIVILEGES priv_current
;
6018 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
6020 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
6022 restore_privilege (&priv_current
);
6028 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
6031 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
6032 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
6034 buf
= xmalloc (blen
);
6035 result
= get_token_information (token
, TokenUser
,
6036 (LPVOID
)buf
, blen
, &needed
);
6039 memcpy (&user_token
, buf
, sizeof (user_token
));
6040 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
6042 euid
= get_rid (user_token
.User
.Sid
);
6043 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
6048 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
6051 strcpy (uname
, "unknown");
6055 ulength
= strlen (uname
);
6061 /* Determine a reasonable euid and gid values. */
6062 if (xstrcasecmp ("administrator", uname
) == 0)
6064 euid
= 500; /* well-known Administrator uid */
6065 egid
= 513; /* well-known None gid */
6069 /* Get group id and name. */
6070 result
= get_token_information (token
, TokenPrimaryGroup
,
6071 (LPVOID
)buf
, blen
, &needed
);
6072 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
6074 buf
= xrealloc (buf
, blen
= needed
);
6075 result
= get_token_information (token
, TokenPrimaryGroup
,
6076 (LPVOID
)buf
, blen
, &needed
);
6080 memcpy (&group_token
, buf
, sizeof (group_token
));
6081 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
6083 egid
= get_rid (group_token
.PrimaryGroup
);
6084 dlength
= sizeof (domain
);
6086 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
6087 gname
, &glength
, NULL
, &dlength
,
6090 w32_add_to_cache (group_token
.PrimaryGroup
,
6094 strcpy (gname
, "None");
6098 glength
= strlen (gname
);
6106 if (!is_windows_9x ())
6108 /* We couldn't open the process token, presumably because of
6109 insufficient access rights. Assume this process is run
6111 strcpy (uname
, "SYSTEM");
6112 strcpy (gname
, "None");
6113 euid
= 18; /* SYSTEM */
6114 egid
= 513; /* None */
6115 glength
= strlen (gname
);
6116 ulength
= strlen (uname
);
6118 /* If we are running under Windows 9X, where security calls are
6119 not supported, we assume all processes are run by the current
6121 else if (GetUserName (uname
, &ulength
))
6123 if (xstrcasecmp ("administrator", uname
) == 0)
6128 strcpy (gname
, "None");
6129 glength
= strlen (gname
);
6130 ulength
= strlen (uname
);
6136 strcpy (uname
, "administrator");
6137 ulength
= strlen (uname
);
6138 strcpy (gname
, "None");
6139 glength
= strlen (gname
);
6142 CloseHandle (token
);
6145 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
6146 tem
= make_unibyte_string (uname
, ulength
);
6147 attrs
= Fcons (Fcons (Quser
,
6148 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
6150 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
6151 tem
= make_unibyte_string (gname
, glength
);
6152 attrs
= Fcons (Fcons (Qgroup
,
6153 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
6156 if (global_memory_status_ex (&memstex
))
6157 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
6158 totphys
= memstex
.ullTotalPhys
/ 1024.0;
6160 /* Visual Studio 6 cannot convert an unsigned __int64 type to
6161 double, so we need to do this for it... */
6163 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
6164 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
6165 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
6167 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
6169 #endif /* __GNUC__ || _MSC_VER >= 1300 */
6170 else if (global_memory_status (&memst
))
6171 totphys
= memst
.dwTotalPhys
/ 1024.0;
6174 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
6177 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
6179 attrs
= Fcons (Fcons (Qmajflt
,
6180 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
6182 attrs
= Fcons (Fcons (Qvsize
,
6183 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
6185 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
6187 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6190 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
6192 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
6194 attrs
= Fcons (Fcons (Qmajflt
,
6195 make_fixnum_or_float (mem
.PageFaultCount
)),
6197 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
6199 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6202 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
6204 DWORD rss
= maxrss
/ 1024;
6206 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
6208 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6211 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
6213 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
6214 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
6215 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
6216 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
6217 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
6218 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
6221 /* FIXME: Retrieve command line by walking the PEB of the process. */
6224 CloseHandle (h_proc
);
6230 /* Wrappers for winsock functions to map between our file descriptors
6231 and winsock's handles; also set h_errno for convenience.
6233 To allow Emacs to run on systems which don't have winsock support
6234 installed, we dynamically link to winsock on startup if present, and
6235 otherwise provide the minimum necessary functionality
6236 (eg. gethostname). */
6238 /* function pointers for relevant socket functions */
6239 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
6240 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
6241 int (PASCAL
*pfn_WSAGetLastError
) (void);
6242 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
6243 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
6244 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
6245 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
6246 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6247 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6248 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
6249 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
6250 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
6251 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
6252 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
6253 int (PASCAL
*pfn_WSACleanup
) (void);
6255 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
6256 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
6257 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
6258 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
6259 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
6260 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
6261 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
6262 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
6263 const char * optval
, int optlen
);
6264 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
6265 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
6267 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
6268 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
6269 struct sockaddr
* from
, int * fromlen
);
6270 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
6271 const struct sockaddr
* to
, int tolen
);
6273 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6274 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
6275 #ifndef HANDLE_FLAG_INHERIT
6276 #define HANDLE_FLAG_INHERIT 1
6280 static int winsock_inuse
;
6285 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
6287 release_listen_threads ();
6288 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6289 after WSAStartup returns successfully, but it seems reasonable
6290 to allow unloading winsock anyway in that case. */
6291 if (pfn_WSACleanup () == 0 ||
6292 pfn_WSAGetLastError () == WSAENETDOWN
)
6294 if (FreeLibrary (winsock_lib
))
6303 init_winsock (int load_now
)
6305 WSADATA winsockData
;
6307 if (winsock_lib
!= NULL
)
6310 pfn_SetHandleInformation
6311 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6312 "SetHandleInformation");
6314 winsock_lib
= LoadLibrary ("Ws2_32.dll");
6316 if (winsock_lib
!= NULL
)
6318 /* dynamically link to socket functions */
6320 #define LOAD_PROC(fn) \
6321 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6324 LOAD_PROC (WSAStartup
);
6325 LOAD_PROC (WSASetLastError
);
6326 LOAD_PROC (WSAGetLastError
);
6327 LOAD_PROC (WSAEventSelect
);
6328 LOAD_PROC (WSACreateEvent
);
6329 LOAD_PROC (WSACloseEvent
);
6332 LOAD_PROC (connect
);
6333 LOAD_PROC (ioctlsocket
);
6336 LOAD_PROC (closesocket
);
6337 LOAD_PROC (shutdown
);
6340 LOAD_PROC (inet_addr
);
6341 LOAD_PROC (gethostname
);
6342 LOAD_PROC (gethostbyname
);
6343 LOAD_PROC (getservbyname
);
6344 LOAD_PROC (getpeername
);
6345 LOAD_PROC (WSACleanup
);
6346 LOAD_PROC (setsockopt
);
6348 LOAD_PROC (getsockname
);
6350 LOAD_PROC (recvfrom
);
6354 /* specify version 1.1 of winsock */
6355 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
6357 if (winsockData
.wVersion
!= 0x101)
6362 /* Report that winsock exists and is usable, but leave
6363 socket functions disabled. I am assuming that calling
6364 WSAStartup does not require any network interaction,
6365 and in particular does not cause or require a dial-up
6366 connection to be established. */
6369 FreeLibrary (winsock_lib
);
6377 FreeLibrary (winsock_lib
);
6387 /* Function to map winsock error codes to errno codes for those errno
6388 code defined in errno.h (errno values not defined by errno.h are
6389 already in nt/inc/sys/socket.h). */
6396 if (winsock_lib
== NULL
)
6399 wsa_err
= pfn_WSAGetLastError ();
6403 case WSAEACCES
: errno
= EACCES
; break;
6404 case WSAEBADF
: errno
= EBADF
; break;
6405 case WSAEFAULT
: errno
= EFAULT
; break;
6406 case WSAEINTR
: errno
= EINTR
; break;
6407 case WSAEINVAL
: errno
= EINVAL
; break;
6408 case WSAEMFILE
: errno
= EMFILE
; break;
6409 case WSAENAMETOOLONG
: errno
= ENAMETOOLONG
; break;
6410 case WSAENOTEMPTY
: errno
= ENOTEMPTY
; break;
6411 default: errno
= wsa_err
; break;
6419 if (winsock_lib
!= NULL
)
6420 pfn_WSASetLastError (0);
6423 /* Extend strerror to handle the winsock-specific error codes. */
6427 } _wsa_errlist
[] = {
6428 {WSAEINTR
, "Interrupted function call"},
6429 {WSAEBADF
, "Bad file descriptor"},
6430 {WSAEACCES
, "Permission denied"},
6431 {WSAEFAULT
, "Bad address"},
6432 {WSAEINVAL
, "Invalid argument"},
6433 {WSAEMFILE
, "Too many open files"},
6435 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
6436 {WSAEINPROGRESS
, "Operation now in progress"},
6437 {WSAEALREADY
, "Operation already in progress"},
6438 {WSAENOTSOCK
, "Socket operation on non-socket"},
6439 {WSAEDESTADDRREQ
, "Destination address required"},
6440 {WSAEMSGSIZE
, "Message too long"},
6441 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
6442 {WSAENOPROTOOPT
, "Bad protocol option"},
6443 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
6444 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
6445 {WSAEOPNOTSUPP
, "Operation not supported"},
6446 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
6447 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
6448 {WSAEADDRINUSE
, "Address already in use"},
6449 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
6450 {WSAENETDOWN
, "Network is down"},
6451 {WSAENETUNREACH
, "Network is unreachable"},
6452 {WSAENETRESET
, "Network dropped connection on reset"},
6453 {WSAECONNABORTED
, "Software caused connection abort"},
6454 {WSAECONNRESET
, "Connection reset by peer"},
6455 {WSAENOBUFS
, "No buffer space available"},
6456 {WSAEISCONN
, "Socket is already connected"},
6457 {WSAENOTCONN
, "Socket is not connected"},
6458 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
6459 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
6460 {WSAETIMEDOUT
, "Connection timed out"},
6461 {WSAECONNREFUSED
, "Connection refused"},
6462 {WSAELOOP
, "Network loop"}, /* not sure */
6463 {WSAENAMETOOLONG
, "Name is too long"},
6464 {WSAEHOSTDOWN
, "Host is down"},
6465 {WSAEHOSTUNREACH
, "No route to host"},
6466 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
6467 {WSAEPROCLIM
, "Too many processes"},
6468 {WSAEUSERS
, "Too many users"}, /* not sure */
6469 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
6470 {WSAESTALE
, "Data is stale"}, /* not sure */
6471 {WSAEREMOTE
, "Remote error"}, /* not sure */
6473 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
6474 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
6475 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
6476 {WSAEDISCON
, "Graceful shutdown in progress"},
6478 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
6479 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
6480 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
6481 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
6482 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
6483 {WSASYSCALLFAILURE
, "System call failure"},
6484 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
6485 {WSATYPE_NOT_FOUND
, "Class type not found"},
6486 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
6487 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
6488 {WSAEREFUSED
, "Operation refused"}, /* not sure */
6491 {WSAHOST_NOT_FOUND
, "Host not found"},
6492 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
6493 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
6494 {WSANO_DATA
, "Valid name, no data record of requested type"},
6500 sys_strerror (int error_no
)
6503 static char unknown_msg
[40];
6505 if (error_no
>= 0 && error_no
< sys_nerr
)
6506 return sys_errlist
[error_no
];
6508 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
6509 if (_wsa_errlist
[i
].errnum
== error_no
)
6510 return _wsa_errlist
[i
].msg
;
6512 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
6516 /* [andrewi 3-May-96] I've had conflicting results using both methods,
6517 but I believe the method of keeping the socket handle separate (and
6518 insuring it is not inheritable) is the correct one. */
6520 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
6522 static int socket_to_fd (SOCKET s
);
6525 sys_socket (int af
, int type
, int protocol
)
6529 if (winsock_lib
== NULL
)
6532 return INVALID_SOCKET
;
6537 /* call the real socket function */
6538 s
= pfn_socket (af
, type
, protocol
);
6540 if (s
!= INVALID_SOCKET
)
6541 return socket_to_fd (s
);
6547 /* Convert a SOCKET to a file descriptor. */
6549 socket_to_fd (SOCKET s
)
6554 /* Although under NT 3.5 _open_osfhandle will accept a socket
6555 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
6556 that does not work under NT 3.1. However, we can get the same
6557 effect by using a backdoor function to replace an existing
6558 descriptor handle with the one we want. */
6560 /* allocate a file descriptor (with appropriate flags) */
6561 fd
= _open ("NUL:", _O_RDWR
);
6564 /* Make a non-inheritable copy of the socket handle. Note
6565 that it is possible that sockets aren't actually kernel
6566 handles, which appears to be the case on Windows 9x when
6567 the MS Proxy winsock client is installed. */
6569 /* Apparently there is a bug in NT 3.51 with some service
6570 packs, which prevents using DuplicateHandle to make a
6571 socket handle non-inheritable (causes WSACleanup to
6572 hang). The work-around is to use SetHandleInformation
6573 instead if it is available and implemented. */
6574 if (pfn_SetHandleInformation
)
6576 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
6580 HANDLE parent
= GetCurrentProcess ();
6581 HANDLE new_s
= INVALID_HANDLE_VALUE
;
6583 if (DuplicateHandle (parent
,
6589 DUPLICATE_SAME_ACCESS
))
6591 /* It is possible that DuplicateHandle succeeds even
6592 though the socket wasn't really a kernel handle,
6593 because a real handle has the same value. So
6594 test whether the new handle really is a socket. */
6595 long nonblocking
= 0;
6596 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
6598 pfn_closesocket (s
);
6603 CloseHandle (new_s
);
6608 eassert (fd
< MAXDESC
);
6609 fd_info
[fd
].hnd
= (HANDLE
) s
;
6611 /* set our own internal flags */
6612 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
6618 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6620 /* attach child_process to fd_info */
6621 if (fd_info
[ fd
].cp
!= NULL
)
6623 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
6627 fd_info
[ fd
].cp
= cp
;
6630 winsock_inuse
++; /* count open sockets */
6638 pfn_closesocket (s
);
6644 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
6646 if (winsock_lib
== NULL
)
6649 return SOCKET_ERROR
;
6653 if (fd_info
[s
].flags
& FILE_SOCKET
)
6655 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
6656 if (rc
== SOCKET_ERROR
)
6661 return SOCKET_ERROR
;
6665 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
6667 if (winsock_lib
== NULL
)
6670 return SOCKET_ERROR
;
6674 if (fd_info
[s
].flags
& FILE_SOCKET
)
6676 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
6677 if (rc
== SOCKET_ERROR
)
6682 return SOCKET_ERROR
;
6686 sys_htons (u_short hostshort
)
6688 return (winsock_lib
!= NULL
) ?
6689 pfn_htons (hostshort
) : hostshort
;
6693 sys_ntohs (u_short netshort
)
6695 return (winsock_lib
!= NULL
) ?
6696 pfn_ntohs (netshort
) : netshort
;
6700 sys_inet_addr (const char * cp
)
6702 return (winsock_lib
!= NULL
) ?
6703 pfn_inet_addr (cp
) : INADDR_NONE
;
6707 sys_gethostname (char * name
, int namelen
)
6709 if (winsock_lib
!= NULL
)
6714 retval
= pfn_gethostname (name
, namelen
);
6715 if (retval
== SOCKET_ERROR
)
6720 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
6721 return !GetComputerName (name
, (DWORD
*)&namelen
);
6724 return SOCKET_ERROR
;
6728 sys_gethostbyname (const char * name
)
6730 struct hostent
* host
;
6731 int h_err
= h_errno
;
6733 if (winsock_lib
== NULL
)
6735 h_errno
= NO_RECOVERY
;
6741 host
= pfn_gethostbyname (name
);
6753 sys_getservbyname (const char * name
, const char * proto
)
6755 struct servent
* serv
;
6757 if (winsock_lib
== NULL
)
6764 serv
= pfn_getservbyname (name
, proto
);
6771 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
6773 if (winsock_lib
== NULL
)
6776 return SOCKET_ERROR
;
6780 if (fd_info
[s
].flags
& FILE_SOCKET
)
6782 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
6783 if (rc
== SOCKET_ERROR
)
6788 return SOCKET_ERROR
;
6792 sys_shutdown (int s
, int how
)
6794 if (winsock_lib
== NULL
)
6797 return SOCKET_ERROR
;
6801 if (fd_info
[s
].flags
& FILE_SOCKET
)
6803 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
6804 if (rc
== SOCKET_ERROR
)
6809 return SOCKET_ERROR
;
6813 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
6815 if (winsock_lib
== NULL
)
6818 return SOCKET_ERROR
;
6822 if (fd_info
[s
].flags
& FILE_SOCKET
)
6824 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
6825 (const char *)optval
, optlen
);
6826 if (rc
== SOCKET_ERROR
)
6831 return SOCKET_ERROR
;
6835 sys_listen (int s
, int backlog
)
6837 if (winsock_lib
== NULL
)
6840 return SOCKET_ERROR
;
6844 if (fd_info
[s
].flags
& FILE_SOCKET
)
6846 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
6847 if (rc
== SOCKET_ERROR
)
6850 fd_info
[s
].flags
|= FILE_LISTEN
;
6854 return SOCKET_ERROR
;
6858 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
6860 if (winsock_lib
== NULL
)
6863 return SOCKET_ERROR
;
6867 if (fd_info
[s
].flags
& FILE_SOCKET
)
6869 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
6870 if (rc
== SOCKET_ERROR
)
6875 return SOCKET_ERROR
;
6879 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
6881 if (winsock_lib
== NULL
)
6888 if (fd_info
[s
].flags
& FILE_LISTEN
)
6890 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
6892 if (t
== INVALID_SOCKET
)
6895 fd
= socket_to_fd (t
);
6899 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6900 ResetEvent (fd_info
[s
].cp
->char_avail
);
6909 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
6910 struct sockaddr
* from
, int * fromlen
)
6912 if (winsock_lib
== NULL
)
6915 return SOCKET_ERROR
;
6919 if (fd_info
[s
].flags
& FILE_SOCKET
)
6921 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
6922 if (rc
== SOCKET_ERROR
)
6927 return SOCKET_ERROR
;
6931 sys_sendto (int s
, const char * buf
, int len
, int flags
,
6932 const struct sockaddr
* to
, int tolen
)
6934 if (winsock_lib
== NULL
)
6937 return SOCKET_ERROR
;
6941 if (fd_info
[s
].flags
& FILE_SOCKET
)
6943 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
6944 if (rc
== SOCKET_ERROR
)
6949 return SOCKET_ERROR
;
6952 /* Windows does not have an fcntl function. Provide an implementation
6953 good enough for Emacs. */
6955 fcntl (int s
, int cmd
, int options
)
6957 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
6958 invoked in a context where fd1 is closed and all descriptors less
6959 than fd1 are open, so sys_dup is an adequate implementation. */
6960 if (cmd
== F_DUPFD_CLOEXEC
)
6963 if (winsock_lib
== NULL
)
6970 if (fd_info
[s
].flags
& FILE_SOCKET
)
6972 if (cmd
== F_SETFL
&& options
== O_NONBLOCK
)
6974 unsigned long nblock
= 1;
6975 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
6976 if (rc
== SOCKET_ERROR
)
6978 /* Keep track of the fact that we set this to non-blocking. */
6979 fd_info
[s
].flags
|= FILE_NDELAY
;
6985 return SOCKET_ERROR
;
6989 return SOCKET_ERROR
;
6993 /* Shadow main io functions: we need to handle pipes and sockets more
6994 intelligently, and implement non-blocking mode as well. */
7007 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
7009 child_process
* cp
= fd_info
[fd
].cp
;
7011 fd_info
[fd
].cp
= NULL
;
7013 if (CHILD_ACTIVE (cp
))
7015 /* if last descriptor to active child_process then cleanup */
7017 for (i
= 0; i
< MAXDESC
; i
++)
7021 if (fd_info
[i
].cp
== cp
)
7026 if (fd_info
[fd
].flags
& FILE_SOCKET
)
7028 if (winsock_lib
== NULL
) emacs_abort ();
7030 pfn_shutdown (SOCK_HANDLE (fd
), 2);
7031 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
7033 winsock_inuse
--; /* count open sockets */
7035 /* If the process handle is NULL, it's either a socket
7036 or serial connection, or a subprocess that was
7037 already reaped by reap_subprocess, but whose
7038 resources were not yet freed, because its output was
7039 not fully read yet by the time it was reaped. (This
7040 usually happens with async subprocesses whose output
7041 is being read by Emacs.) Otherwise, this process was
7042 not reaped yet, so we set its FD to a negative value
7043 to make sure sys_select will eventually get to
7044 calling the SIGCHLD handler for it, which will then
7045 invoke waitpid and reap_subprocess. */
7046 if (cp
->procinfo
.hProcess
== NULL
)
7054 if (fd
>= 0 && fd
< MAXDESC
)
7055 fd_info
[fd
].flags
= 0;
7057 /* Note that sockets do not need special treatment here (at least on
7058 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
7059 closesocket is equivalent to CloseHandle, which is to be expected
7060 because socket handles are fully fledged kernel handles. */
7072 if (new_fd
>= 0 && new_fd
< MAXDESC
)
7074 /* duplicate our internal info as well */
7075 fd_info
[new_fd
] = fd_info
[fd
];
7081 sys_dup2 (int src
, int dst
)
7085 if (dst
< 0 || dst
>= MAXDESC
)
7091 /* make sure we close the destination first if it's a pipe or socket */
7092 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
7095 rc
= _dup2 (src
, dst
);
7098 /* duplicate our internal info as well */
7099 fd_info
[dst
] = fd_info
[src
];
7105 pipe2 (int * phandles
, int pipe2_flags
)
7110 eassert (pipe2_flags
== O_CLOEXEC
);
7112 /* make pipe handles non-inheritable; when we spawn a child, we
7113 replace the relevant handle with an inheritable one. Also put
7114 pipes into binary mode; we will do text mode translation ourselves
7116 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
7120 /* Protect against overflow, since Windows can open more handles than
7121 our fd_info array has room for. */
7122 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
7124 _close (phandles
[0]);
7125 _close (phandles
[1]);
7131 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
7132 fd_info
[phandles
[0]].flags
= flags
;
7134 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
7135 fd_info
[phandles
[1]].flags
= flags
;
7142 /* Function to do blocking read of one byte, needed to implement
7143 select. It is only allowed on communication ports, sockets, or
7146 _sys_read_ahead (int fd
)
7151 if (fd
< 0 || fd
>= MAXDESC
)
7152 return STATUS_READ_ERROR
;
7154 cp
= fd_info
[fd
].cp
;
7156 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
7157 return STATUS_READ_ERROR
;
7159 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
7160 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
7162 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
7166 cp
->status
= STATUS_READ_IN_PROGRESS
;
7168 if (fd_info
[fd
].flags
& FILE_PIPE
)
7170 rc
= _read (fd
, &cp
->chr
, sizeof (char));
7172 /* Give subprocess time to buffer some more output for us before
7173 reporting that input is available; we need this because Windows 95
7174 connects DOS programs to pipes by making the pipe appear to be
7175 the normal console stdout - as a result most DOS programs will
7176 write to stdout without buffering, ie. one character at a
7177 time. Even some W32 programs do this - "dir" in a command
7178 shell on NT is very slow if we don't do this. */
7181 int wait
= w32_pipe_read_delay
;
7187 /* Yield remainder of our time slice, effectively giving a
7188 temporary priority boost to the child process. */
7192 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7194 HANDLE hnd
= fd_info
[fd
].hnd
;
7195 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7198 /* Configure timeouts for blocking read. */
7199 if (!GetCommTimeouts (hnd
, &ct
))
7201 cp
->status
= STATUS_READ_ERROR
;
7202 return STATUS_READ_ERROR
;
7204 ct
.ReadIntervalTimeout
= 0;
7205 ct
.ReadTotalTimeoutMultiplier
= 0;
7206 ct
.ReadTotalTimeoutConstant
= 0;
7207 if (!SetCommTimeouts (hnd
, &ct
))
7209 cp
->status
= STATUS_READ_ERROR
;
7210 return STATUS_READ_ERROR
;
7213 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
7215 if (GetLastError () != ERROR_IO_PENDING
)
7217 cp
->status
= STATUS_READ_ERROR
;
7218 return STATUS_READ_ERROR
;
7220 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7222 cp
->status
= STATUS_READ_ERROR
;
7223 return STATUS_READ_ERROR
;
7227 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
7229 unsigned long nblock
= 0;
7230 /* We always want this to block, so temporarily disable NDELAY. */
7231 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7232 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7234 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
7236 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7239 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7243 if (rc
== sizeof (char))
7244 cp
->status
= STATUS_READ_SUCCEEDED
;
7246 cp
->status
= STATUS_READ_FAILED
;
7252 _sys_wait_accept (int fd
)
7258 if (fd
< 0 || fd
>= MAXDESC
)
7259 return STATUS_READ_ERROR
;
7261 cp
= fd_info
[fd
].cp
;
7263 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
7264 return STATUS_READ_ERROR
;
7266 cp
->status
= STATUS_READ_FAILED
;
7268 hEv
= pfn_WSACreateEvent ();
7269 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
7270 if (rc
!= SOCKET_ERROR
)
7273 rc
= WaitForSingleObject (hEv
, 500);
7275 } while (rc
== WAIT_TIMEOUT
7276 && cp
->status
!= STATUS_READ_ERROR
7278 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
7279 if (rc
== WAIT_OBJECT_0
)
7280 cp
->status
= STATUS_READ_SUCCEEDED
;
7282 pfn_WSACloseEvent (hEv
);
7288 sys_read (int fd
, char * buffer
, unsigned int count
)
7293 char * orig_buffer
= buffer
;
7301 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7303 child_process
*cp
= fd_info
[fd
].cp
;
7305 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
7313 /* re-read CR carried over from last read */
7314 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
7316 if (fd_info
[fd
].flags
& FILE_BINARY
) emacs_abort ();
7320 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
7323 /* presence of a child_process structure means we are operating in
7324 non-blocking mode - otherwise we just call _read directly.
7325 Note that the child_process structure might be missing because
7326 reap_subprocess has been called; in this case the pipe is
7327 already broken, so calling _read on it is okay. */
7330 int current_status
= cp
->status
;
7332 switch (current_status
)
7334 case STATUS_READ_FAILED
:
7335 case STATUS_READ_ERROR
:
7336 /* report normal EOF if nothing in buffer */
7338 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7341 case STATUS_READ_READY
:
7342 case STATUS_READ_IN_PROGRESS
:
7343 DebPrint (("sys_read called when read is in progress\n"));
7344 errno
= EWOULDBLOCK
;
7347 case STATUS_READ_SUCCEEDED
:
7348 /* consume read-ahead char */
7349 *buffer
++ = cp
->chr
;
7352 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7353 ResetEvent (cp
->char_avail
);
7355 case STATUS_READ_ACKNOWLEDGED
:
7359 DebPrint (("sys_read: bad status %d\n", current_status
));
7364 if (fd_info
[fd
].flags
& FILE_PIPE
)
7366 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
7367 to_read
= min (waiting
, (DWORD
) count
);
7370 nchars
+= _read (fd
, buffer
, to_read
);
7372 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7374 HANDLE hnd
= fd_info
[fd
].hnd
;
7375 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7381 /* Configure timeouts for non-blocking read. */
7382 if (!GetCommTimeouts (hnd
, &ct
))
7387 ct
.ReadIntervalTimeout
= MAXDWORD
;
7388 ct
.ReadTotalTimeoutMultiplier
= 0;
7389 ct
.ReadTotalTimeoutConstant
= 0;
7390 if (!SetCommTimeouts (hnd
, &ct
))
7396 if (!ResetEvent (ovl
->hEvent
))
7401 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
7403 if (GetLastError () != ERROR_IO_PENDING
)
7408 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7417 else /* FILE_SOCKET */
7419 if (winsock_lib
== NULL
) emacs_abort ();
7421 /* do the equivalent of a non-blocking read */
7422 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
7423 if (waiting
== 0 && nchars
== 0)
7425 errno
= EWOULDBLOCK
;
7431 /* always use binary mode for sockets */
7432 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
7433 if (res
== SOCKET_ERROR
)
7435 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
7436 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7446 int nread
= _read (fd
, buffer
, count
);
7449 else if (nchars
== 0)
7454 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7455 /* Perform text mode translation if required. */
7456 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7458 nchars
= crlf_to_lf (nchars
, orig_buffer
);
7459 /* If buffer contains only CR, return that. To be absolutely
7460 sure we should attempt to read the next char, but in
7461 practice a CR to be followed by LF would not appear by
7462 itself in the buffer. */
7463 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
7465 fd_info
[fd
].flags
|= FILE_LAST_CR
;
7471 nchars
= _read (fd
, buffer
, count
);
7476 /* From w32xfns.c */
7477 extern HANDLE interrupt_handle
;
7479 /* For now, don't bother with a non-blocking mode */
7481 sys_write (int fd
, const void * buffer
, unsigned int count
)
7491 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7493 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
7499 /* Perform text mode translation if required. */
7500 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7502 char * tmpbuf
= alloca (count
* 2);
7503 unsigned char * src
= (void *)buffer
;
7504 unsigned char * dst
= tmpbuf
;
7509 unsigned char *next
;
7510 /* copy next line or remaining bytes */
7511 next
= _memccpy (dst
, src
, '\n', nbytes
);
7514 /* copied one line ending with '\n' */
7515 int copied
= next
- dst
;
7518 /* insert '\r' before '\n' */
7525 /* copied remaining partial line -> now finished */
7532 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
7534 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
7535 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
7536 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
7539 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
7541 if (GetLastError () != ERROR_IO_PENDING
)
7546 if (detect_input_pending ())
7547 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
7550 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
7551 if (active
== WAIT_OBJECT_0
)
7552 { /* User pressed C-g, cancel write, then leave. Don't bother
7553 cleaning up as we may only get stuck in buggy drivers. */
7554 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
7559 if (active
== WAIT_OBJECT_0
+ 1
7560 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
7567 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
7569 unsigned long nblock
= 0;
7570 if (winsock_lib
== NULL
) emacs_abort ();
7572 /* TODO: implement select() properly so non-blocking I/O works. */
7573 /* For now, make sure the write blocks. */
7574 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7575 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7577 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
7579 /* Set the socket back to non-blocking if it was before,
7580 for other operations that support it. */
7581 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7584 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7587 if (nchars
== SOCKET_ERROR
)
7589 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
7590 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7596 /* Some networked filesystems don't like too large writes, so
7597 break them into smaller chunks. See the Comments section of
7598 the MSDN documentation of WriteFile for details behind the
7599 choice of the value of CHUNK below. See also the thread
7600 http://thread.gmane.org/gmane.comp.version-control.git/145294
7601 in the git mailing list. */
7602 const unsigned char *p
= buffer
;
7603 const unsigned chunk
= 30 * 1024 * 1024;
7608 unsigned this_chunk
= count
< chunk
? count
: chunk
;
7609 int n
= _write (fd
, p
, this_chunk
);
7617 else if (n
< this_chunk
)
7628 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
7630 extern Lisp_Object
conv_sockaddr_to_lisp (struct sockaddr
*, int);
7632 /* Return information about network interface IFNAME, or about all
7633 interfaces (if IFNAME is nil). */
7635 network_interface_get_info (Lisp_Object ifname
)
7637 ULONG ainfo_len
= sizeof (IP_ADAPTER_INFO
);
7638 IP_ADAPTER_INFO
*adapter
, *ainfo
= xmalloc (ainfo_len
);
7639 DWORD retval
= get_adapters_info (ainfo
, &ainfo_len
);
7640 Lisp_Object res
= Qnil
;
7642 if (retval
== ERROR_BUFFER_OVERFLOW
)
7644 ainfo
= xrealloc (ainfo
, ainfo_len
);
7645 retval
= get_adapters_info (ainfo
, &ainfo_len
);
7648 if (retval
== ERROR_SUCCESS
)
7650 int eth_count
= 0, tr_count
= 0, fddi_count
= 0, ppp_count
= 0;
7651 int sl_count
= 0, wlan_count
= 0, lo_count
= 0, ifx_count
= 0;
7653 struct sockaddr_in sa
;
7655 /* For the below, we need some winsock functions, so make sure
7656 the winsock DLL is loaded. If we cannot successfully load
7657 it, they will have no use of the information we provide,
7659 if (!winsock_lib
&& !init_winsock (1))
7662 for (adapter
= ainfo
; adapter
; adapter
= adapter
->Next
)
7664 char namebuf
[MAX_ADAPTER_NAME_LENGTH
+ 4];
7666 /* Present Unix-compatible interface names, instead of the
7667 Windows names, which are really GUIDs not readable by
7669 static const char *ifmt
[] = {
7670 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
7685 switch (adapter
->Type
)
7687 case MIB_IF_TYPE_ETHERNET
:
7688 /* Windows before Vista reports wireless adapters as
7689 Ethernet. Work around by looking at the Description
7691 if (strstr (adapter
->Description
, "Wireless "))
7694 if_num
= wlan_count
++;
7698 ifmt_idx
= ETHERNET
;
7699 if_num
= eth_count
++;
7702 case MIB_IF_TYPE_TOKENRING
:
7703 ifmt_idx
= TOKENRING
;
7704 if_num
= tr_count
++;
7706 case MIB_IF_TYPE_FDDI
:
7708 if_num
= fddi_count
++;
7710 case MIB_IF_TYPE_PPP
:
7712 if_num
= ppp_count
++;
7714 case MIB_IF_TYPE_SLIP
:
7716 if_num
= sl_count
++;
7718 case IF_TYPE_IEEE80211
:
7720 if_num
= wlan_count
++;
7722 case MIB_IF_TYPE_LOOPBACK
:
7725 ifmt_idx
= LOOPBACK
;
7726 if_num
= lo_count
++;
7732 ifmt_idx
= OTHER_IF
;
7733 if_num
= ifx_count
++;
7736 if (ifmt_idx
== NONE
)
7738 sprintf (namebuf
, ifmt
[ifmt_idx
], if_num
);
7740 sa
.sin_family
= AF_INET
;
7741 ip_addr
= sys_inet_addr (adapter
->IpAddressList
.IpAddress
.String
);
7742 if (ip_addr
== INADDR_NONE
)
7744 /* Bogus address, skip this interface. */
7747 sa
.sin_addr
.s_addr
= ip_addr
;
7750 res
= Fcons (Fcons (build_string (namebuf
),
7751 conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7752 sizeof (struct sockaddr
))),
7754 else if (strcmp (namebuf
, SSDATA (ifname
)) == 0)
7756 Lisp_Object hwaddr
= Fmake_vector (make_number (6), Qnil
);
7757 register struct Lisp_Vector
*p
= XVECTOR (hwaddr
);
7758 Lisp_Object flags
= Qnil
;
7762 /* Flags. We guess most of them by type, since the
7763 Windows flags are different and hard to get by. */
7764 flags
= Fcons (intern ("up"), flags
);
7765 if (ifmt_idx
== ETHERNET
|| ifmt_idx
== WLAN
)
7767 flags
= Fcons (intern ("broadcast"), flags
);
7768 flags
= Fcons (intern ("multicast"), flags
);
7770 flags
= Fcons (intern ("running"), flags
);
7771 if (ifmt_idx
== PPP
)
7773 flags
= Fcons (intern ("pointopoint"), flags
);
7774 flags
= Fcons (intern ("noarp"), flags
);
7776 if (adapter
->HaveWins
)
7777 flags
= Fcons (intern ("WINS"), flags
);
7778 if (adapter
->DhcpEnabled
)
7779 flags
= Fcons (intern ("dynamic"), flags
);
7781 res
= Fcons (flags
, res
);
7783 /* Hardware address and its family. */
7784 for (n
= 0; n
< adapter
->AddressLength
; n
++)
7785 p
->u
.contents
[n
] = make_number ((int) adapter
->Address
[n
]);
7786 /* Windows does not support AF_LINK or AF_PACKET family
7787 of addresses. Use an arbitrary family number that is
7788 identical to what GNU/Linux returns. */
7789 res
= Fcons (Fcons (make_number (1), hwaddr
), res
);
7792 sa
.sin_family
= AF_INET
;
7793 net_mask
= sys_inet_addr (adapter
->IpAddressList
.IpMask
.String
);
7794 if (net_mask
!= INADDR_NONE
)
7796 sa
.sin_addr
.s_addr
= net_mask
;
7798 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7799 sizeof (struct sockaddr
)),
7803 res
= Fcons (Qnil
, res
);
7805 sa
.sin_family
= AF_INET
;
7806 if (ip_addr
!= INADDR_NONE
)
7808 /* Broadcast address is only reported by
7809 GetAdaptersAddresses, which is of limited
7810 availability. Generate it on our own. */
7811 u_long bcast_addr
= (ip_addr
& net_mask
) | ~net_mask
;
7813 sa
.sin_addr
.s_addr
= bcast_addr
;
7815 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7816 sizeof (struct sockaddr
)),
7820 sa
.sin_addr
.s_addr
= ip_addr
;
7822 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7823 sizeof (struct sockaddr
)),
7827 res
= Fcons (Qnil
, Fcons (Qnil
, res
));
7830 /* GetAdaptersInfo is documented to not report loopback
7831 interfaces, so we generate one out of thin air. */
7834 sa
.sin_family
= AF_INET
;
7838 sa
.sin_addr
.s_addr
= sys_inet_addr ("127.0.0.1");
7839 res
= Fcons (Fcons (build_string ("lo"),
7840 conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7841 sizeof (struct sockaddr
))),
7844 else if (strcmp (SSDATA (ifname
), "lo") == 0)
7846 res
= Fcons (Fcons (intern ("running"),
7847 Fcons (intern ("loopback"),
7848 Fcons (intern ("up"), Qnil
))), Qnil
);
7849 /* 772 is what 3 different GNU/Linux systems report for
7850 the loopback interface. */
7851 res
= Fcons (Fcons (make_number (772),
7852 Fmake_vector (make_number (6),
7855 sa
.sin_addr
.s_addr
= sys_inet_addr ("255.0.0.0");
7856 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7857 sizeof (struct sockaddr
)),
7859 sa
.sin_addr
.s_addr
= sys_inet_addr ("0.0.0.0");
7860 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7861 sizeof (struct sockaddr
)),
7863 sa
.sin_addr
.s_addr
= sys_inet_addr ("127.0.0.1");
7864 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7865 sizeof (struct sockaddr
)),
7878 network_interface_list (void)
7880 return network_interface_get_info (Qnil
);
7884 network_interface_info (Lisp_Object ifname
)
7886 return network_interface_get_info (ifname
);
7890 /* The Windows CRT functions are "optimized for speed", so they don't
7891 check for timezone and DST changes if they were last called less
7892 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
7893 all Emacs features that repeatedly call time functions (e.g.,
7894 display-time) are in real danger of missing timezone and DST
7895 changes. Calling tzset before each localtime call fixes that. */
7897 sys_localtime (const time_t *t
)
7900 return localtime (t
);
7905 /* Try loading LIBRARY_ID from the file(s) specified in
7906 Vdynamic_library_alist. If the library is loaded successfully,
7907 return the handle of the DLL, and record the filename in the
7908 property :loaded-from of LIBRARY_ID. If the library could not be
7909 found, or when it was already loaded (because the handle is not
7910 recorded anywhere, and so is lost after use), return NULL.
7912 We could also save the handle in :loaded-from, but currently
7913 there's no use case for it. */
7915 w32_delayed_load (Lisp_Object library_id
)
7917 HMODULE library_dll
= NULL
;
7919 CHECK_SYMBOL (library_id
);
7921 if (CONSP (Vdynamic_library_alist
)
7922 && NILP (Fassq (library_id
, Vlibrary_cache
)))
7924 Lisp_Object found
= Qnil
;
7925 Lisp_Object dlls
= Fassq (library_id
, Vdynamic_library_alist
);
7928 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
7930 CHECK_STRING_CAR (dlls
);
7931 if ((library_dll
= LoadLibrary (SDATA (XCAR (dlls
)))))
7933 char name
[MAX_PATH
];
7936 len
= GetModuleFileNameA (library_dll
, name
, sizeof (name
));
7937 found
= Fcons (XCAR (dlls
),
7939 /* Possibly truncated */
7940 ? make_specified_string (name
, -1, len
, 1)
7946 Fput (library_id
, QCloaded_from
, found
);
7954 check_windows_init_file (void)
7956 /* A common indication that Emacs is not installed properly is when
7957 it cannot find the Windows installation file. If this file does
7958 not exist in the expected place, tell the user. */
7960 if (!noninteractive
&& !inhibit_window_system
7961 /* Vload_path is not yet initialized when we are loading
7963 && NILP (Vpurify_flag
))
7965 Lisp_Object init_file
;
7968 init_file
= build_string ("term/w32-win");
7969 fd
= openp (Vload_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
7972 Lisp_Object load_path_print
= Fprin1_to_string (Vload_path
, Qnil
);
7973 char *init_file_name
= SDATA (init_file
);
7974 char *load_path
= SDATA (load_path_print
);
7975 char *buffer
= alloca (1024
7976 + strlen (init_file_name
)
7977 + strlen (load_path
));
7980 "The Emacs Windows initialization file \"%s.el\" "
7981 "could not be found in your Emacs installation. "
7982 "Emacs checked the following directories for this file:\n"
7984 "When Emacs cannot find this file, it usually means that it "
7985 "was not installed properly, or its distribution file was "
7986 "not unpacked properly.\nSee the README.W32 file in the "
7987 "top-level Emacs directory for more information.",
7988 init_file_name
, load_path
);
7991 "Emacs Abort Dialog",
7992 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
7993 /* Use the low-level system abort. */
8004 term_ntproc (int ignored
)
8010 /* shutdown the socket interface if necessary */
8017 init_ntproc (int dumping
)
8019 sigset_t initial_mask
= 0;
8021 /* Initialize the socket interface now if available and requested by
8022 the user by defining PRELOAD_WINSOCK; otherwise loading will be
8023 delayed until open-network-stream is called (w32-has-winsock can
8024 also be used to dynamically load or reload winsock).
8026 Conveniently, init_environment is called before us, so
8027 PRELOAD_WINSOCK can be set in the registry. */
8029 /* Always initialize this correctly. */
8032 if (getenv ("PRELOAD_WINSOCK") != NULL
)
8033 init_winsock (TRUE
);
8035 /* Initial preparation for subprocess support: replace our standard
8036 handles with non-inheritable versions. */
8039 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
8040 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
8041 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
8043 parent
= GetCurrentProcess ();
8045 /* ignore errors when duplicating and closing; typically the
8046 handles will be invalid when running as a gui program. */
8047 DuplicateHandle (parent
,
8048 GetStdHandle (STD_INPUT_HANDLE
),
8053 DUPLICATE_SAME_ACCESS
);
8055 DuplicateHandle (parent
,
8056 GetStdHandle (STD_OUTPUT_HANDLE
),
8061 DUPLICATE_SAME_ACCESS
);
8063 DuplicateHandle (parent
,
8064 GetStdHandle (STD_ERROR_HANDLE
),
8069 DUPLICATE_SAME_ACCESS
);
8075 if (stdin_save
!= INVALID_HANDLE_VALUE
)
8076 _open_osfhandle ((intptr_t) stdin_save
, O_TEXT
);
8078 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
8081 if (stdout_save
!= INVALID_HANDLE_VALUE
)
8082 _open_osfhandle ((intptr_t) stdout_save
, O_TEXT
);
8084 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
8087 if (stderr_save
!= INVALID_HANDLE_VALUE
)
8088 _open_osfhandle ((intptr_t) stderr_save
, O_TEXT
);
8090 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
8094 /* unfortunately, atexit depends on implementation of malloc */
8095 /* atexit (term_ntproc); */
8098 /* Make sure we start with all signals unblocked. */
8099 sigprocmask (SIG_SETMASK
, &initial_mask
, NULL
);
8100 signal (SIGABRT
, term_ntproc
);
8104 /* determine which drives are fixed, for GetCachedVolumeInformation */
8106 /* GetDriveType must have trailing backslash. */
8107 char drive
[] = "A:\\";
8109 /* Loop over all possible drive letters */
8110 while (*drive
<= 'Z')
8112 /* Record if this drive letter refers to a fixed drive. */
8113 fixed_drives
[DRIVE_INDEX (*drive
)] =
8114 (GetDriveType (drive
) == DRIVE_FIXED
);
8119 /* Reset the volume info cache. */
8120 volume_cache
= NULL
;
8125 shutdown_handler ensures that buffers' autosave files are
8126 up to date when the user logs off, or the system shuts down.
8129 shutdown_handler (DWORD type
)
8131 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
8132 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
8133 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
8134 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
8136 /* Shut down cleanly, making sure autosave files are up to date. */
8137 shut_down_emacs (0, Qnil
);
8140 /* Allow other handlers to handle this signal. */
8145 globals_of_w32 is used to initialize those global variables that
8146 must always be initialized on startup even when the global variable
8147 initialized is non zero (see the function main in emacs.c).
8150 globals_of_w32 (void)
8152 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
8154 get_process_times_fn
= (GetProcessTimes_Proc
)
8155 GetProcAddress (kernel32
, "GetProcessTimes");
8157 DEFSYM (QCloaded_from
, ":loaded-from");
8159 g_b_init_is_windows_9x
= 0;
8160 g_b_init_open_process_token
= 0;
8161 g_b_init_get_token_information
= 0;
8162 g_b_init_lookup_account_sid
= 0;
8163 g_b_init_get_sid_sub_authority
= 0;
8164 g_b_init_get_sid_sub_authority_count
= 0;
8165 g_b_init_get_security_info
= 0;
8166 g_b_init_get_file_security
= 0;
8167 g_b_init_get_security_descriptor_owner
= 0;
8168 g_b_init_get_security_descriptor_group
= 0;
8169 g_b_init_is_valid_sid
= 0;
8170 g_b_init_create_toolhelp32_snapshot
= 0;
8171 g_b_init_process32_first
= 0;
8172 g_b_init_process32_next
= 0;
8173 g_b_init_open_thread_token
= 0;
8174 g_b_init_impersonate_self
= 0;
8175 g_b_init_revert_to_self
= 0;
8176 g_b_init_get_process_memory_info
= 0;
8177 g_b_init_get_process_working_set_size
= 0;
8178 g_b_init_global_memory_status
= 0;
8179 g_b_init_global_memory_status_ex
= 0;
8180 g_b_init_equal_sid
= 0;
8181 g_b_init_copy_sid
= 0;
8182 g_b_init_get_length_sid
= 0;
8183 g_b_init_get_native_system_info
= 0;
8184 g_b_init_get_system_times
= 0;
8185 g_b_init_create_symbolic_link
= 0;
8186 g_b_init_get_security_descriptor_dacl
= 0;
8187 g_b_init_convert_sd_to_sddl
= 0;
8188 g_b_init_convert_sddl_to_sd
= 0;
8189 g_b_init_is_valid_security_descriptor
= 0;
8190 g_b_init_set_file_security
= 0;
8191 g_b_init_get_adapters_info
= 0;
8192 num_of_processors
= 0;
8193 /* The following sets a handler for shutdown notifications for
8194 console apps. This actually applies to Emacs in both console and
8195 GUI modes, since we had to fool windows into thinking emacs is a
8196 console application to get console mode to work. */
8197 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
8199 /* "None" is the default group name on standalone workstations. */
8200 strcpy (dflt_group_name
, "None");
8202 /* Reset, in case it has some value inherited from dump time. */
8203 w32_stat_get_owner_group
= 0;
8205 /* If w32_unicode_filenames is non-zero, we will be using Unicode
8206 (a.k.a. "wide") APIs to invoke functions that accept file
8208 if (is_windows_9x ())
8209 w32_unicode_filenames
= 0;
8211 w32_unicode_filenames
= 1;
8214 /* For make-serial-process */
8216 serial_open (Lisp_Object port_obj
)
8218 char *port
= SSDATA (port_obj
);
8223 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
8224 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
8225 if (hnd
== INVALID_HANDLE_VALUE
)
8226 error ("Could not open %s", port
);
8227 fd
= (int) _open_osfhandle ((intptr_t) hnd
, 0);
8229 error ("Could not open %s", port
);
8233 error ("Could not create child process");
8235 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
8236 fd_info
[ fd
].hnd
= hnd
;
8237 fd_info
[ fd
].flags
|=
8238 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
8239 if (fd_info
[ fd
].cp
!= NULL
)
8241 error ("fd_info[fd = %d] is already in use", fd
);
8243 fd_info
[ fd
].cp
= cp
;
8244 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
8245 if (cp
->ovl_read
.hEvent
== NULL
)
8246 error ("Could not create read event");
8247 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
8248 if (cp
->ovl_write
.hEvent
== NULL
)
8249 error ("Could not create write event");
8254 /* For serial-process-configure */
8256 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
8258 Lisp_Object childp2
= Qnil
;
8259 Lisp_Object tem
= Qnil
;
8263 char summary
[4] = "???"; /* This usually becomes "8N1". */
8265 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
8266 error ("Not a serial process");
8267 hnd
= fd_info
[ p
->outfd
].hnd
;
8269 childp2
= Fcopy_sequence (p
->childp
);
8271 /* Initialize timeouts for blocking read and blocking write. */
8272 if (!GetCommTimeouts (hnd
, &ct
))
8273 error ("GetCommTimeouts() failed");
8274 ct
.ReadIntervalTimeout
= 0;
8275 ct
.ReadTotalTimeoutMultiplier
= 0;
8276 ct
.ReadTotalTimeoutConstant
= 0;
8277 ct
.WriteTotalTimeoutMultiplier
= 0;
8278 ct
.WriteTotalTimeoutConstant
= 0;
8279 if (!SetCommTimeouts (hnd
, &ct
))
8280 error ("SetCommTimeouts() failed");
8281 /* Read port attributes and prepare default configuration. */
8282 memset (&dcb
, 0, sizeof (dcb
));
8283 dcb
.DCBlength
= sizeof (DCB
);
8284 if (!GetCommState (hnd
, &dcb
))
8285 error ("GetCommState() failed");
8288 dcb
.fAbortOnError
= FALSE
;
8289 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
8294 /* Configure speed. */
8295 if (!NILP (Fplist_member (contact
, QCspeed
)))
8296 tem
= Fplist_get (contact
, QCspeed
);
8298 tem
= Fplist_get (p
->childp
, QCspeed
);
8300 dcb
.BaudRate
= XINT (tem
);
8301 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
8303 /* Configure bytesize. */
8304 if (!NILP (Fplist_member (contact
, QCbytesize
)))
8305 tem
= Fplist_get (contact
, QCbytesize
);
8307 tem
= Fplist_get (p
->childp
, QCbytesize
);
8309 tem
= make_number (8);
8311 if (XINT (tem
) != 7 && XINT (tem
) != 8)
8312 error (":bytesize must be nil (8), 7, or 8");
8313 dcb
.ByteSize
= XINT (tem
);
8314 summary
[0] = XINT (tem
) + '0';
8315 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
8317 /* Configure parity. */
8318 if (!NILP (Fplist_member (contact
, QCparity
)))
8319 tem
= Fplist_get (contact
, QCparity
);
8321 tem
= Fplist_get (p
->childp
, QCparity
);
8322 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
8323 error (":parity must be nil (no parity), `even', or `odd'");
8324 dcb
.fParity
= FALSE
;
8325 dcb
.Parity
= NOPARITY
;
8326 dcb
.fErrorChar
= FALSE
;
8331 else if (EQ (tem
, Qeven
))
8335 dcb
.Parity
= EVENPARITY
;
8336 dcb
.fErrorChar
= TRUE
;
8338 else if (EQ (tem
, Qodd
))
8342 dcb
.Parity
= ODDPARITY
;
8343 dcb
.fErrorChar
= TRUE
;
8345 childp2
= Fplist_put (childp2
, QCparity
, tem
);
8347 /* Configure stopbits. */
8348 if (!NILP (Fplist_member (contact
, QCstopbits
)))
8349 tem
= Fplist_get (contact
, QCstopbits
);
8351 tem
= Fplist_get (p
->childp
, QCstopbits
);
8353 tem
= make_number (1);
8355 if (XINT (tem
) != 1 && XINT (tem
) != 2)
8356 error (":stopbits must be nil (1 stopbit), 1, or 2");
8357 summary
[2] = XINT (tem
) + '0';
8358 if (XINT (tem
) == 1)
8359 dcb
.StopBits
= ONESTOPBIT
;
8360 else if (XINT (tem
) == 2)
8361 dcb
.StopBits
= TWOSTOPBITS
;
8362 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
8364 /* Configure flowcontrol. */
8365 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
8366 tem
= Fplist_get (contact
, QCflowcontrol
);
8368 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
8369 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
8370 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
8371 dcb
.fOutxCtsFlow
= FALSE
;
8372 dcb
.fOutxDsrFlow
= FALSE
;
8373 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
8374 dcb
.fDsrSensitivity
= FALSE
;
8375 dcb
.fTXContinueOnXoff
= FALSE
;
8378 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
8379 dcb
.XonChar
= 17; /* Control-Q */
8380 dcb
.XoffChar
= 19; /* Control-S */
8383 /* Already configured. */
8385 else if (EQ (tem
, Qhw
))
8387 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
8388 dcb
.fOutxCtsFlow
= TRUE
;
8390 else if (EQ (tem
, Qsw
))
8395 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
8397 /* Activate configuration. */
8398 if (!SetCommState (hnd
, &dcb
))
8399 error ("SetCommState() failed");
8401 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
8402 pset_childp (p
, childp2
);
8408 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
8412 struct timespec timeout
;
8413 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
8414 int fd
= process
->infd
;
8416 n
= sys_read (fd
, (char*)buf
, sz
);
8423 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8424 if (err
== EWOULDBLOCK
)
8427 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
8433 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
8435 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
8436 int fd
= process
->outfd
;
8437 ssize_t n
= sys_write (fd
, buf
, sz
);
8439 /* 0 or more bytes written means everything went fine. */
8443 /* Negative bytes written means we got an error in errno.
8444 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8445 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
8446 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
8450 #endif /* HAVE_GNUTLS */