* lisp/arc-mode.el (archive-extract-by-file): Check if directory exists
[emacs.git] / src / w32.c
blob159085e7f50df5ace82e5c1434efc493dd5386fa
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 */
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <float.h> /* for DBL_EPSILON */
28 #include <io.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <ctype.h>
32 #include <signal.h>
33 #include <sys/file.h>
34 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
35 #include <sys/time.h>
36 #include <sys/utime.h>
37 #include <math.h>
39 /* must include CRT headers *before* config.h */
41 #include <config.h>
42 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
44 #undef access
45 #undef chdir
46 #undef chmod
47 #undef creat
48 #undef ctime
49 #undef fopen
50 #undef link
51 #undef mkdir
52 #undef open
53 #undef rename
54 #undef rmdir
55 #undef unlink
57 #undef close
58 #undef dup
59 #undef dup2
60 #undef pipe
61 #undef read
62 #undef write
64 #undef strerror
66 #undef localtime
68 #include "lisp.h"
69 #include "epaths.h" /* for SHELL */
71 #include <pwd.h>
72 #include <grp.h>
74 /* MinGW64 (_W64) defines these in its _mingw.h. */
75 #if defined(__GNUC__) && !defined(_W64)
76 #define _ANONYMOUS_UNION
77 #define _ANONYMOUS_STRUCT
78 #endif
79 #include <windows.h>
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 {
83 DWORD dwLength;
84 DWORD dwMemoryLoad;
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;
107 PCONTEXT ctxrec;
109 #include <lmcons.h>
110 #include <shlobj.h>
112 #include <tlhelp32.h>
113 #include <psapi.h>
114 #ifndef _MSC_VER
115 #include <w32api.h>
116 #endif
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 {
123 DWORD cb;
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;
133 SIZE_T PrivateUsage;
134 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
135 #endif
136 #endif
138 #include <winioctl.h>
139 #include <aclapi.h>
140 #include <sddl.h>
142 #include <sys/acl.h>
143 #include <acl.h>
145 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
146 define them by hand if not already defined. */
147 #ifndef SDDL_REVISION_1
148 #define SDDL_REVISION_1 1
149 #endif /* SDDL_REVISION_1 */
151 #if defined(_MSC_VER) || defined(_W64)
152 /* MSVC and MinGW64 don't provide the definition of
153 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
154 which cannot be included because it triggers conflicts with other
155 Windows API headers. So we define it here by hand. */
157 typedef struct _REPARSE_DATA_BUFFER {
158 ULONG ReparseTag;
159 USHORT ReparseDataLength;
160 USHORT Reserved;
161 union {
162 struct {
163 USHORT SubstituteNameOffset;
164 USHORT SubstituteNameLength;
165 USHORT PrintNameOffset;
166 USHORT PrintNameLength;
167 ULONG Flags;
168 WCHAR PathBuffer[1];
169 } SymbolicLinkReparseBuffer;
170 struct {
171 USHORT SubstituteNameOffset;
172 USHORT SubstituteNameLength;
173 USHORT PrintNameOffset;
174 USHORT PrintNameLength;
175 WCHAR PathBuffer[1];
176 } MountPointReparseBuffer;
177 struct {
178 UCHAR DataBuffer[1];
179 } GenericReparseBuffer;
180 } DUMMYUNIONNAME;
181 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
183 #ifndef FILE_DEVICE_FILE_SYSTEM
184 #define FILE_DEVICE_FILE_SYSTEM 9
185 #endif
186 #ifndef METHOD_BUFFERED
187 #define METHOD_BUFFERED 0
188 #endif
189 #ifndef FILE_ANY_ACCESS
190 #define FILE_ANY_ACCESS 0x00000000
191 #endif
192 #ifndef CTL_CODE
193 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
194 #endif
195 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
196 #ifndef FSCTL_GET_REPARSE_POINT
197 #define FSCTL_GET_REPARSE_POINT \
198 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
199 #endif
200 #endif
202 /* TCP connection support. */
203 #include <sys/socket.h>
204 #undef socket
205 #undef bind
206 #undef connect
207 #undef htons
208 #undef ntohs
209 #undef inet_addr
210 #undef gethostname
211 #undef gethostbyname
212 #undef getservbyname
213 #undef getpeername
214 #undef shutdown
215 #undef setsockopt
216 #undef listen
217 #undef getsockname
218 #undef accept
219 #undef recvfrom
220 #undef sendto
222 #include <iphlpapi.h> /* should be after winsock2.h */
224 #include "w32.h"
225 #include <dirent.h>
226 #include "w32common.h"
227 #include "w32heap.h"
228 #include "w32select.h"
229 #include "systime.h"
230 #include "dispextern.h" /* for xstrcasecmp */
231 #include "coding.h" /* for Vlocale_coding_system */
233 #include "careadlinkat.h"
234 #include "allocator.h"
236 /* For serial_configure and serial_open. */
237 #include "process.h"
239 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
240 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
242 Lisp_Object QCloaded_from;
244 void globals_of_w32 (void);
245 static DWORD get_rid (PSID);
246 static int is_symlink (const char *);
247 static char * chase_symlinks (const char *);
248 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
249 static int restore_privilege (TOKEN_PRIVILEGES *);
250 static BOOL WINAPI revert_to_self (void);
252 static int sys_access (const char *, int);
253 extern void *e_malloc (size_t);
254 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
255 struct timespec *, void *);
256 extern int sys_dup (int);
261 /* Initialization states.
263 WARNING: If you add any more such variables for additional APIs,
264 you MUST add initialization for them to globals_of_w32
265 below. This is because these variables might get set
266 to non-NULL values during dumping, but the dumped Emacs
267 cannot reuse those values, because it could be run on a
268 different version of the OS, where API addresses are
269 different. */
270 static BOOL g_b_init_is_windows_9x;
271 static BOOL g_b_init_open_process_token;
272 static BOOL g_b_init_get_token_information;
273 static BOOL g_b_init_lookup_account_sid;
274 static BOOL g_b_init_get_sid_sub_authority;
275 static BOOL g_b_init_get_sid_sub_authority_count;
276 static BOOL g_b_init_get_security_info;
277 static BOOL g_b_init_get_file_security_w;
278 static BOOL g_b_init_get_file_security_a;
279 static BOOL g_b_init_get_security_descriptor_owner;
280 static BOOL g_b_init_get_security_descriptor_group;
281 static BOOL g_b_init_is_valid_sid;
282 static BOOL g_b_init_create_toolhelp32_snapshot;
283 static BOOL g_b_init_process32_first;
284 static BOOL g_b_init_process32_next;
285 static BOOL g_b_init_open_thread_token;
286 static BOOL g_b_init_impersonate_self;
287 static BOOL g_b_init_revert_to_self;
288 static BOOL g_b_init_get_process_memory_info;
289 static BOOL g_b_init_get_process_working_set_size;
290 static BOOL g_b_init_global_memory_status;
291 static BOOL g_b_init_global_memory_status_ex;
292 static BOOL g_b_init_get_length_sid;
293 static BOOL g_b_init_equal_sid;
294 static BOOL g_b_init_copy_sid;
295 static BOOL g_b_init_get_native_system_info;
296 static BOOL g_b_init_get_system_times;
297 static BOOL g_b_init_create_symbolic_link_w;
298 static BOOL g_b_init_create_symbolic_link_a;
299 static BOOL g_b_init_get_security_descriptor_dacl;
300 static BOOL g_b_init_convert_sd_to_sddl;
301 static BOOL g_b_init_convert_sddl_to_sd;
302 static BOOL g_b_init_is_valid_security_descriptor;
303 static BOOL g_b_init_set_file_security_w;
304 static BOOL g_b_init_set_file_security_a;
305 static BOOL g_b_init_get_adapters_info;
308 BEGIN: Wrapper functions around OpenProcessToken
309 and other functions in advapi32.dll that are only
310 supported in Windows NT / 2k / XP
312 /* ** Function pointer typedefs ** */
313 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
314 HANDLE ProcessHandle,
315 DWORD DesiredAccess,
316 PHANDLE TokenHandle);
317 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
318 HANDLE TokenHandle,
319 TOKEN_INFORMATION_CLASS TokenInformationClass,
320 LPVOID TokenInformation,
321 DWORD TokenInformationLength,
322 PDWORD ReturnLength);
323 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
324 HANDLE process_handle,
325 LPFILETIME creation_time,
326 LPFILETIME exit_time,
327 LPFILETIME kernel_time,
328 LPFILETIME user_time);
330 GetProcessTimes_Proc get_process_times_fn = NULL;
332 #ifdef _UNICODE
333 const char * const LookupAccountSid_Name = "LookupAccountSidW";
334 #else
335 const char * const LookupAccountSid_Name = "LookupAccountSidA";
336 #endif
337 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
338 LPCTSTR lpSystemName,
339 PSID Sid,
340 LPTSTR Name,
341 LPDWORD cbName,
342 LPTSTR DomainName,
343 LPDWORD cbDomainName,
344 PSID_NAME_USE peUse);
345 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
346 PSID pSid,
347 DWORD n);
348 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
349 PSID pSid);
350 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
351 HANDLE handle,
352 SE_OBJECT_TYPE ObjectType,
353 SECURITY_INFORMATION SecurityInfo,
354 PSID *ppsidOwner,
355 PSID *ppsidGroup,
356 PACL *ppDacl,
357 PACL *ppSacl,
358 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
359 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
360 LPCWSTR lpFileName,
361 SECURITY_INFORMATION RequestedInformation,
362 PSECURITY_DESCRIPTOR pSecurityDescriptor,
363 DWORD nLength,
364 LPDWORD lpnLengthNeeded);
365 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
366 LPCSTR lpFileName,
367 SECURITY_INFORMATION RequestedInformation,
368 PSECURITY_DESCRIPTOR pSecurityDescriptor,
369 DWORD nLength,
370 LPDWORD lpnLengthNeeded);
371 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
372 LPCWSTR lpFileName,
373 SECURITY_INFORMATION SecurityInformation,
374 PSECURITY_DESCRIPTOR pSecurityDescriptor);
375 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
376 LPCSTR lpFileName,
377 SECURITY_INFORMATION SecurityInformation,
378 PSECURITY_DESCRIPTOR pSecurityDescriptor);
379 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
380 PSECURITY_DESCRIPTOR pSecurityDescriptor,
381 PSID *pOwner,
382 LPBOOL lpbOwnerDefaulted);
383 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
384 PSECURITY_DESCRIPTOR pSecurityDescriptor,
385 PSID *pGroup,
386 LPBOOL lpbGroupDefaulted);
387 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
388 PSECURITY_DESCRIPTOR pSecurityDescriptor,
389 LPBOOL lpbDaclPresent,
390 PACL *pDacl,
391 LPBOOL lpbDaclDefaulted);
392 typedef BOOL (WINAPI * IsValidSid_Proc) (
393 PSID sid);
394 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
395 DWORD dwFlags,
396 DWORD th32ProcessID);
397 typedef BOOL (WINAPI * Process32First_Proc) (
398 HANDLE hSnapshot,
399 LPPROCESSENTRY32 lppe);
400 typedef BOOL (WINAPI * Process32Next_Proc) (
401 HANDLE hSnapshot,
402 LPPROCESSENTRY32 lppe);
403 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
404 HANDLE ThreadHandle,
405 DWORD DesiredAccess,
406 BOOL OpenAsSelf,
407 PHANDLE TokenHandle);
408 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
409 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
410 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
411 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
412 HANDLE Process,
413 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
414 DWORD cb);
415 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
416 HANDLE hProcess,
417 PSIZE_T lpMinimumWorkingSetSize,
418 PSIZE_T lpMaximumWorkingSetSize);
419 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
420 LPMEMORYSTATUS lpBuffer);
421 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
422 LPMEMORY_STATUS_EX lpBuffer);
423 typedef BOOL (WINAPI * CopySid_Proc) (
424 DWORD nDestinationSidLength,
425 PSID pDestinationSid,
426 PSID pSourceSid);
427 typedef BOOL (WINAPI * EqualSid_Proc) (
428 PSID pSid1,
429 PSID pSid2);
430 typedef DWORD (WINAPI * GetLengthSid_Proc) (
431 PSID pSid);
432 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
433 LPSYSTEM_INFO lpSystemInfo);
434 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
435 LPFILETIME lpIdleTime,
436 LPFILETIME lpKernelTime,
437 LPFILETIME lpUserTime);
438 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
439 LPCWSTR lpSymlinkFileName,
440 LPCWSTR lpTargetFileName,
441 DWORD dwFlags);
442 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
443 LPCSTR lpSymlinkFileName,
444 LPCSTR lpTargetFileName,
445 DWORD dwFlags);
446 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
447 LPCTSTR StringSecurityDescriptor,
448 DWORD StringSDRevision,
449 PSECURITY_DESCRIPTOR *SecurityDescriptor,
450 PULONG SecurityDescriptorSize);
451 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
452 PSECURITY_DESCRIPTOR SecurityDescriptor,
453 DWORD RequestedStringSDRevision,
454 SECURITY_INFORMATION SecurityInformation,
455 LPTSTR *StringSecurityDescriptor,
456 PULONG StringSecurityDescriptorLen);
457 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
458 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
459 PIP_ADAPTER_INFO pAdapterInfo,
460 PULONG pOutBufLen);
462 /* ** A utility function ** */
463 static BOOL
464 is_windows_9x (void)
466 static BOOL s_b_ret = 0;
467 OSVERSIONINFO os_ver;
468 if (g_b_init_is_windows_9x == 0)
470 g_b_init_is_windows_9x = 1;
471 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
472 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
473 if (GetVersionEx (&os_ver))
475 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
478 return s_b_ret;
481 static Lisp_Object ltime (ULONGLONG);
483 /* Get total user and system times for get-internal-run-time.
484 Returns a list of integers if the times are provided by the OS
485 (NT derivatives), otherwise it returns the result of current-time. */
486 Lisp_Object
487 w32_get_internal_run_time (void)
489 if (get_process_times_fn)
491 FILETIME create, exit, kernel, user;
492 HANDLE proc = GetCurrentProcess ();
493 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
495 LARGE_INTEGER user_int, kernel_int, total;
496 user_int.LowPart = user.dwLowDateTime;
497 user_int.HighPart = user.dwHighDateTime;
498 kernel_int.LowPart = kernel.dwLowDateTime;
499 kernel_int.HighPart = kernel.dwHighDateTime;
500 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
501 return ltime (total.QuadPart);
505 return Fcurrent_time ();
508 /* ** The wrapper functions ** */
510 static BOOL WINAPI
511 open_process_token (HANDLE ProcessHandle,
512 DWORD DesiredAccess,
513 PHANDLE TokenHandle)
515 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
516 HMODULE hm_advapi32 = NULL;
517 if (is_windows_9x () == TRUE)
519 return FALSE;
521 if (g_b_init_open_process_token == 0)
523 g_b_init_open_process_token = 1;
524 hm_advapi32 = LoadLibrary ("Advapi32.dll");
525 s_pfn_Open_Process_Token =
526 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
528 if (s_pfn_Open_Process_Token == NULL)
530 return FALSE;
532 return (
533 s_pfn_Open_Process_Token (
534 ProcessHandle,
535 DesiredAccess,
536 TokenHandle)
540 static BOOL WINAPI
541 get_token_information (HANDLE TokenHandle,
542 TOKEN_INFORMATION_CLASS TokenInformationClass,
543 LPVOID TokenInformation,
544 DWORD TokenInformationLength,
545 PDWORD ReturnLength)
547 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
548 HMODULE hm_advapi32 = NULL;
549 if (is_windows_9x () == TRUE)
551 return FALSE;
553 if (g_b_init_get_token_information == 0)
555 g_b_init_get_token_information = 1;
556 hm_advapi32 = LoadLibrary ("Advapi32.dll");
557 s_pfn_Get_Token_Information =
558 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
560 if (s_pfn_Get_Token_Information == NULL)
562 return FALSE;
564 return (
565 s_pfn_Get_Token_Information (
566 TokenHandle,
567 TokenInformationClass,
568 TokenInformation,
569 TokenInformationLength,
570 ReturnLength)
574 static BOOL WINAPI
575 lookup_account_sid (LPCTSTR lpSystemName,
576 PSID Sid,
577 LPTSTR Name,
578 LPDWORD cbName,
579 LPTSTR DomainName,
580 LPDWORD cbDomainName,
581 PSID_NAME_USE peUse)
583 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
584 HMODULE hm_advapi32 = NULL;
585 if (is_windows_9x () == TRUE)
587 return FALSE;
589 if (g_b_init_lookup_account_sid == 0)
591 g_b_init_lookup_account_sid = 1;
592 hm_advapi32 = LoadLibrary ("Advapi32.dll");
593 s_pfn_Lookup_Account_Sid =
594 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
596 if (s_pfn_Lookup_Account_Sid == NULL)
598 return FALSE;
600 return (
601 s_pfn_Lookup_Account_Sid (
602 lpSystemName,
603 Sid,
604 Name,
605 cbName,
606 DomainName,
607 cbDomainName,
608 peUse)
612 static PDWORD WINAPI
613 get_sid_sub_authority (PSID pSid, DWORD n)
615 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
616 static DWORD zero = 0U;
617 HMODULE hm_advapi32 = NULL;
618 if (is_windows_9x () == TRUE)
620 return &zero;
622 if (g_b_init_get_sid_sub_authority == 0)
624 g_b_init_get_sid_sub_authority = 1;
625 hm_advapi32 = LoadLibrary ("Advapi32.dll");
626 s_pfn_Get_Sid_Sub_Authority =
627 (GetSidSubAuthority_Proc) GetProcAddress (
628 hm_advapi32, "GetSidSubAuthority");
630 if (s_pfn_Get_Sid_Sub_Authority == NULL)
632 return &zero;
634 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
637 static PUCHAR WINAPI
638 get_sid_sub_authority_count (PSID pSid)
640 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
641 static UCHAR zero = 0U;
642 HMODULE hm_advapi32 = NULL;
643 if (is_windows_9x () == TRUE)
645 return &zero;
647 if (g_b_init_get_sid_sub_authority_count == 0)
649 g_b_init_get_sid_sub_authority_count = 1;
650 hm_advapi32 = LoadLibrary ("Advapi32.dll");
651 s_pfn_Get_Sid_Sub_Authority_Count =
652 (GetSidSubAuthorityCount_Proc) GetProcAddress (
653 hm_advapi32, "GetSidSubAuthorityCount");
655 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
657 return &zero;
659 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
662 static DWORD WINAPI
663 get_security_info (HANDLE handle,
664 SE_OBJECT_TYPE ObjectType,
665 SECURITY_INFORMATION SecurityInfo,
666 PSID *ppsidOwner,
667 PSID *ppsidGroup,
668 PACL *ppDacl,
669 PACL *ppSacl,
670 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
672 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
673 HMODULE hm_advapi32 = NULL;
674 if (is_windows_9x () == TRUE)
676 return FALSE;
678 if (g_b_init_get_security_info == 0)
680 g_b_init_get_security_info = 1;
681 hm_advapi32 = LoadLibrary ("Advapi32.dll");
682 s_pfn_Get_Security_Info =
683 (GetSecurityInfo_Proc) GetProcAddress (
684 hm_advapi32, "GetSecurityInfo");
686 if (s_pfn_Get_Security_Info == NULL)
688 return FALSE;
690 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
691 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
692 ppSecurityDescriptor));
695 static BOOL WINAPI
696 get_file_security (const char *lpFileName,
697 SECURITY_INFORMATION RequestedInformation,
698 PSECURITY_DESCRIPTOR pSecurityDescriptor,
699 DWORD nLength,
700 LPDWORD lpnLengthNeeded)
702 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
703 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
704 HMODULE hm_advapi32 = NULL;
705 if (is_windows_9x () == TRUE)
707 errno = ENOTSUP;
708 return FALSE;
710 if (w32_unicode_filenames)
712 wchar_t filename_w[MAX_PATH];
714 if (g_b_init_get_file_security_w == 0)
716 g_b_init_get_file_security_w = 1;
717 hm_advapi32 = LoadLibrary ("Advapi32.dll");
718 s_pfn_Get_File_SecurityW =
719 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
720 "GetFileSecurityW");
722 if (s_pfn_Get_File_SecurityW == NULL)
724 errno = ENOTSUP;
725 return FALSE;
727 filename_to_utf16 (lpFileName, filename_w);
728 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
729 pSecurityDescriptor, nLength,
730 lpnLengthNeeded));
732 else
734 char filename_a[MAX_PATH];
736 if (g_b_init_get_file_security_a == 0)
738 g_b_init_get_file_security_a = 1;
739 hm_advapi32 = LoadLibrary ("Advapi32.dll");
740 s_pfn_Get_File_SecurityA =
741 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
742 "GetFileSecurityA");
744 if (s_pfn_Get_File_SecurityA == NULL)
746 errno = ENOTSUP;
747 return FALSE;
749 filename_to_ansi (lpFileName, filename_a);
750 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
751 pSecurityDescriptor, nLength,
752 lpnLengthNeeded));
756 static BOOL WINAPI
757 set_file_security (const char *lpFileName,
758 SECURITY_INFORMATION SecurityInformation,
759 PSECURITY_DESCRIPTOR pSecurityDescriptor)
761 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
762 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
763 HMODULE hm_advapi32 = NULL;
764 if (is_windows_9x () == TRUE)
766 errno = ENOTSUP;
767 return FALSE;
769 if (w32_unicode_filenames)
771 wchar_t filename_w[MAX_PATH];
773 if (g_b_init_set_file_security_w == 0)
775 g_b_init_set_file_security_w = 1;
776 hm_advapi32 = LoadLibrary ("Advapi32.dll");
777 s_pfn_Set_File_SecurityW =
778 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
779 "SetFileSecurityW");
781 if (s_pfn_Set_File_SecurityW == NULL)
783 errno = ENOTSUP;
784 return FALSE;
786 filename_to_utf16 (lpFileName, filename_w);
787 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
788 pSecurityDescriptor));
790 else
792 char filename_a[MAX_PATH];
794 if (g_b_init_set_file_security_a == 0)
796 g_b_init_set_file_security_a = 1;
797 hm_advapi32 = LoadLibrary ("Advapi32.dll");
798 s_pfn_Set_File_SecurityA =
799 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
800 "SetFileSecurityA");
802 if (s_pfn_Set_File_SecurityA == NULL)
804 errno = ENOTSUP;
805 return FALSE;
807 filename_to_ansi (lpFileName, filename_a);
808 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
809 pSecurityDescriptor));
813 static BOOL WINAPI
814 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
815 PSID *pOwner,
816 LPBOOL lpbOwnerDefaulted)
818 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
819 HMODULE hm_advapi32 = NULL;
820 if (is_windows_9x () == TRUE)
822 errno = ENOTSUP;
823 return FALSE;
825 if (g_b_init_get_security_descriptor_owner == 0)
827 g_b_init_get_security_descriptor_owner = 1;
828 hm_advapi32 = LoadLibrary ("Advapi32.dll");
829 s_pfn_Get_Security_Descriptor_Owner =
830 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
831 hm_advapi32, "GetSecurityDescriptorOwner");
833 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
835 errno = ENOTSUP;
836 return FALSE;
838 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
839 lpbOwnerDefaulted));
842 static BOOL WINAPI
843 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
844 PSID *pGroup,
845 LPBOOL lpbGroupDefaulted)
847 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
848 HMODULE hm_advapi32 = NULL;
849 if (is_windows_9x () == TRUE)
851 errno = ENOTSUP;
852 return FALSE;
854 if (g_b_init_get_security_descriptor_group == 0)
856 g_b_init_get_security_descriptor_group = 1;
857 hm_advapi32 = LoadLibrary ("Advapi32.dll");
858 s_pfn_Get_Security_Descriptor_Group =
859 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
860 hm_advapi32, "GetSecurityDescriptorGroup");
862 if (s_pfn_Get_Security_Descriptor_Group == NULL)
864 errno = ENOTSUP;
865 return FALSE;
867 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
868 lpbGroupDefaulted));
871 static BOOL WINAPI
872 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
873 LPBOOL lpbDaclPresent,
874 PACL *pDacl,
875 LPBOOL lpbDaclDefaulted)
877 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
878 HMODULE hm_advapi32 = NULL;
879 if (is_windows_9x () == TRUE)
881 errno = ENOTSUP;
882 return FALSE;
884 if (g_b_init_get_security_descriptor_dacl == 0)
886 g_b_init_get_security_descriptor_dacl = 1;
887 hm_advapi32 = LoadLibrary ("Advapi32.dll");
888 s_pfn_Get_Security_Descriptor_Dacl =
889 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
890 hm_advapi32, "GetSecurityDescriptorDacl");
892 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
894 errno = ENOTSUP;
895 return FALSE;
897 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
898 lpbDaclPresent, pDacl,
899 lpbDaclDefaulted));
902 static BOOL WINAPI
903 is_valid_sid (PSID sid)
905 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
906 HMODULE hm_advapi32 = NULL;
907 if (is_windows_9x () == TRUE)
909 return FALSE;
911 if (g_b_init_is_valid_sid == 0)
913 g_b_init_is_valid_sid = 1;
914 hm_advapi32 = LoadLibrary ("Advapi32.dll");
915 s_pfn_Is_Valid_Sid =
916 (IsValidSid_Proc) GetProcAddress (
917 hm_advapi32, "IsValidSid");
919 if (s_pfn_Is_Valid_Sid == NULL)
921 return FALSE;
923 return (s_pfn_Is_Valid_Sid (sid));
926 static BOOL WINAPI
927 equal_sid (PSID sid1, PSID sid2)
929 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
930 HMODULE hm_advapi32 = NULL;
931 if (is_windows_9x () == TRUE)
933 return FALSE;
935 if (g_b_init_equal_sid == 0)
937 g_b_init_equal_sid = 1;
938 hm_advapi32 = LoadLibrary ("Advapi32.dll");
939 s_pfn_Equal_Sid =
940 (EqualSid_Proc) GetProcAddress (
941 hm_advapi32, "EqualSid");
943 if (s_pfn_Equal_Sid == NULL)
945 return FALSE;
947 return (s_pfn_Equal_Sid (sid1, sid2));
950 static DWORD WINAPI
951 get_length_sid (PSID sid)
953 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
954 HMODULE hm_advapi32 = NULL;
955 if (is_windows_9x () == TRUE)
957 return 0;
959 if (g_b_init_get_length_sid == 0)
961 g_b_init_get_length_sid = 1;
962 hm_advapi32 = LoadLibrary ("Advapi32.dll");
963 s_pfn_Get_Length_Sid =
964 (GetLengthSid_Proc) GetProcAddress (
965 hm_advapi32, "GetLengthSid");
967 if (s_pfn_Get_Length_Sid == NULL)
969 return 0;
971 return (s_pfn_Get_Length_Sid (sid));
974 static BOOL WINAPI
975 copy_sid (DWORD destlen, PSID dest, PSID src)
977 static CopySid_Proc s_pfn_Copy_Sid = NULL;
978 HMODULE hm_advapi32 = NULL;
979 if (is_windows_9x () == TRUE)
981 return FALSE;
983 if (g_b_init_copy_sid == 0)
985 g_b_init_copy_sid = 1;
986 hm_advapi32 = LoadLibrary ("Advapi32.dll");
987 s_pfn_Copy_Sid =
988 (CopySid_Proc) GetProcAddress (
989 hm_advapi32, "CopySid");
991 if (s_pfn_Copy_Sid == NULL)
993 return FALSE;
995 return (s_pfn_Copy_Sid (destlen, dest, src));
999 END: Wrapper functions around OpenProcessToken
1000 and other functions in advapi32.dll that are only
1001 supported in Windows NT / 2k / XP
1004 static void WINAPI
1005 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1007 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1008 if (is_windows_9x () != TRUE)
1010 if (g_b_init_get_native_system_info == 0)
1012 g_b_init_get_native_system_info = 1;
1013 s_pfn_Get_Native_System_Info =
1014 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1015 "GetNativeSystemInfo");
1017 if (s_pfn_Get_Native_System_Info != NULL)
1018 s_pfn_Get_Native_System_Info (lpSystemInfo);
1020 else
1021 lpSystemInfo->dwNumberOfProcessors = -1;
1024 static BOOL WINAPI
1025 get_system_times (LPFILETIME lpIdleTime,
1026 LPFILETIME lpKernelTime,
1027 LPFILETIME lpUserTime)
1029 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1030 if (is_windows_9x () == TRUE)
1032 return FALSE;
1034 if (g_b_init_get_system_times == 0)
1036 g_b_init_get_system_times = 1;
1037 s_pfn_Get_System_times =
1038 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1039 "GetSystemTimes");
1041 if (s_pfn_Get_System_times == NULL)
1042 return FALSE;
1043 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1046 static BOOLEAN WINAPI
1047 create_symbolic_link (LPCSTR lpSymlinkFilename,
1048 LPCSTR lpTargetFileName,
1049 DWORD dwFlags)
1051 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1052 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1053 BOOLEAN retval;
1055 if (is_windows_9x () == TRUE)
1057 errno = ENOSYS;
1058 return 0;
1060 if (w32_unicode_filenames)
1062 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1064 if (g_b_init_create_symbolic_link_w == 0)
1066 g_b_init_create_symbolic_link_w = 1;
1067 s_pfn_Create_Symbolic_LinkW =
1068 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1069 "CreateSymbolicLinkW");
1071 if (s_pfn_Create_Symbolic_LinkW == NULL)
1073 errno = ENOSYS;
1074 return 0;
1077 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1078 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1079 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1080 /* If we were denied creation of the symlink, try again after
1081 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1082 if (!retval)
1084 TOKEN_PRIVILEGES priv_current;
1086 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1087 &priv_current))
1089 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1090 restore_privilege (&priv_current);
1091 revert_to_self ();
1095 else
1097 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1099 if (g_b_init_create_symbolic_link_a == 0)
1101 g_b_init_create_symbolic_link_a = 1;
1102 s_pfn_Create_Symbolic_LinkA =
1103 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1104 "CreateSymbolicLinkA");
1106 if (s_pfn_Create_Symbolic_LinkA == NULL)
1108 errno = ENOSYS;
1109 return 0;
1112 filename_to_ansi (lpSymlinkFilename, symfn_a);
1113 filename_to_ansi (lpTargetFileName, tgtfn_a);
1114 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1115 /* If we were denied creation of the symlink, try again after
1116 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1117 if (!retval)
1119 TOKEN_PRIVILEGES priv_current;
1121 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1122 &priv_current))
1124 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1125 restore_privilege (&priv_current);
1126 revert_to_self ();
1130 return retval;
1133 static BOOL WINAPI
1134 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1136 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1138 if (is_windows_9x () == TRUE)
1140 errno = ENOTSUP;
1141 return FALSE;
1144 if (g_b_init_is_valid_security_descriptor == 0)
1146 g_b_init_is_valid_security_descriptor = 1;
1147 s_pfn_Is_Valid_Security_Descriptor_Proc =
1148 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1149 "IsValidSecurityDescriptor");
1151 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1153 errno = ENOTSUP;
1154 return FALSE;
1157 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1160 static BOOL WINAPI
1161 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1162 DWORD RequestedStringSDRevision,
1163 SECURITY_INFORMATION SecurityInformation,
1164 LPTSTR *StringSecurityDescriptor,
1165 PULONG StringSecurityDescriptorLen)
1167 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1168 BOOL retval;
1170 if (is_windows_9x () == TRUE)
1172 errno = ENOTSUP;
1173 return FALSE;
1176 if (g_b_init_convert_sd_to_sddl == 0)
1178 g_b_init_convert_sd_to_sddl = 1;
1179 #ifdef _UNICODE
1180 s_pfn_Convert_SD_To_SDDL =
1181 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1182 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1183 #else
1184 s_pfn_Convert_SD_To_SDDL =
1185 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1186 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1187 #endif
1189 if (s_pfn_Convert_SD_To_SDDL == NULL)
1191 errno = ENOTSUP;
1192 return FALSE;
1195 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1196 RequestedStringSDRevision,
1197 SecurityInformation,
1198 StringSecurityDescriptor,
1199 StringSecurityDescriptorLen);
1201 return retval;
1204 static BOOL WINAPI
1205 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1206 DWORD StringSDRevision,
1207 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1208 PULONG SecurityDescriptorSize)
1210 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1211 BOOL retval;
1213 if (is_windows_9x () == TRUE)
1215 errno = ENOTSUP;
1216 return FALSE;
1219 if (g_b_init_convert_sddl_to_sd == 0)
1221 g_b_init_convert_sddl_to_sd = 1;
1222 #ifdef _UNICODE
1223 s_pfn_Convert_SDDL_To_SD =
1224 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1225 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1226 #else
1227 s_pfn_Convert_SDDL_To_SD =
1228 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1229 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1230 #endif
1232 if (s_pfn_Convert_SDDL_To_SD == NULL)
1234 errno = ENOTSUP;
1235 return FALSE;
1238 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1239 StringSDRevision,
1240 SecurityDescriptor,
1241 SecurityDescriptorSize);
1243 return retval;
1246 static DWORD WINAPI
1247 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1249 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1250 HMODULE hm_iphlpapi = NULL;
1252 if (is_windows_9x () == TRUE)
1253 return ERROR_NOT_SUPPORTED;
1255 if (g_b_init_get_adapters_info == 0)
1257 g_b_init_get_adapters_info = 1;
1258 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1259 if (hm_iphlpapi)
1260 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1261 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1263 if (s_pfn_Get_Adapters_Info == NULL)
1264 return ERROR_NOT_SUPPORTED;
1265 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1270 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1271 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1273 This is called from alloc.c:valid_pointer_p. */
1275 w32_valid_pointer_p (void *p, int size)
1277 SIZE_T done;
1278 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1280 if (h)
1282 unsigned char *buf = alloca (size);
1283 int retval = ReadProcessMemory (h, p, buf, size, &done);
1285 CloseHandle (h);
1286 return retval;
1288 else
1289 return -1;
1294 /* Here's an overview of how the Windows build supports file names
1295 that cannot be encoded by the current system codepage.
1297 From the POV of Lisp and layers of C code above the functions here,
1298 Emacs on Windows pretends that its file names are encoded in UTF-8;
1299 see encode_file and decode_file on coding.c. Any file name that is
1300 passed as a unibyte string to C functions defined here is assumed
1301 to be in UTF-8 encoding. Any file name returned by functions
1302 defined here must be in UTF-8 encoding, with only a few exceptions
1303 reserved for a couple of special cases. (Be sure to use
1304 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1305 as they can be much longer than MAX_PATH!)
1307 The UTF-8 encoded file names cannot be passed to system APIs, as
1308 Windows does not support that. Therefore, they are converted
1309 either to UTF-16 or to the ANSI codepage, depending on the value of
1310 w32-unicode-filenames, before calling any system APIs or CRT library
1311 functions. The default value of that variable is determined by the
1312 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1313 user can change that default (although I don't see why would she
1314 want to).
1316 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1317 filename_from_utf16, and filename_from_ansi, are the workhorses of
1318 these conversions. They rely on Windows native APIs
1319 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1320 functions from coding.c here, because they allocate memory, which
1321 is a bad idea on the level of libc, which is what the functions
1322 here emulate. (If you worry about performance due to constant
1323 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1324 it was measured to take only a few microseconds on a not-so-fast
1325 machine, and second, that's exactly what the ANSI APIs we used
1326 before do anyway, because they are just thin wrappers around the
1327 Unicode APIs.)
1329 The variables file-name-coding-system and default-file-name-coding-system
1330 still exist, but are actually used only when a file name needs to
1331 be converted to the ANSI codepage. This happens all the time when
1332 w32-unicode-filenames is nil, but can also happen from time to time
1333 when it is t. Otherwise, these variables have no effect on file-name
1334 encoding when w32-unicode-filenames is t; this is similar to
1335 selection-coding-system.
1337 This arrangement works very well, but it has a few gotchas and
1338 limitations:
1340 . Lisp code that encodes or decodes file names manually should
1341 normally use 'utf-8' as the coding-system on Windows,
1342 disregarding file-name-coding-system. This is a somewhat
1343 unpleasant consequence, but it cannot be avoided. Fortunately,
1344 very few Lisp packages need to do that.
1346 More generally, passing to library functions (e.g., fopen or
1347 opendir) file names already encoded in the ANSI codepage is
1348 explicitly *verboten*, as all those functions, as shadowed and
1349 emulated here, assume they will receive UTF-8 encoded file names.
1351 For the same reasons, no CRT function or Win32 API can be called
1352 directly in Emacs sources, without either converting the file
1353 name sfrom UTF-8 to either UTF-16 or ANSI codepage, or going
1354 through some shadowing function defined here.
1356 . Environment variables stored in Vprocess_environment are encoded
1357 in the ANSI codepage, so if getenv/egetenv is used for a variable
1358 whose value is a file name or a list of directories, it needs to
1359 be converted to UTF-8, before it is used as argument to functions
1360 or decoded into a Lisp string.
1362 . File names passed to external libraries, like the image libraries
1363 and GnuTLS, need special handling. These libraries generally
1364 don't support UTF-16 or UTF-8 file names, so they must get file
1365 names encoded in the ANSI codepage. To facilitate using these
1366 libraries with file names that are not encodable in the ANSI
1367 codepage, use the function ansi_encode_filename, which will try
1368 to use the short 8+3 alias of a file name if that file name is
1369 not encodable in the ANSI codepage. See image.c and gnutls.c for
1370 examples of how this should be done.
1372 . Running subprocesses in non-ASCII directories and with non-ASCII
1373 file arguments is limited to the current codepage (even though
1374 Emacs is perfectly capable of finding an executable program file
1375 even in a directory whose name cannot be encoded in the current
1376 codepage). This is because the command-line arguments are
1377 encoded _before_ they get to the w32-specific level, and the
1378 encoding is not known in advance (it doesn't have to be the
1379 current ANSI codepage), so w32proc.c functions cannot re-encode
1380 them in UTF-16. This should be fixed, but will also require
1381 changes in cmdproxy. The current limitation is not terribly bad
1382 anyway, since very few, if any, Windows console programs that are
1383 likely to be invoked by Emacs support UTF-16 encoded command
1384 lines.
1386 . For similar reasons, server.el and emacsclient are also limited
1387 to the current ANSI codepage for now.
1389 . Emacs itself can only handle command-line arguments encoded in
1390 the current codepage.
1392 . Turning on w32-unicode-filename on Windows 9X (if it at all
1393 works) requires UNICOWS.DLL, which is currently loaded only in a
1394 GUI session. */
1398 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1399 codepage defined by file-name-coding-system. */
1401 /* Current codepage for encoding file names. */
1402 static int file_name_codepage;
1404 /* Produce a Windows ANSI codepage suitable for encoding file names.
1405 Return the information about that codepage in CP_INFO. */
1406 static int
1407 codepage_for_filenames (CPINFO *cp_info)
1409 /* A simple cache to avoid calling GetCPInfo every time we need to
1410 encode/decode a file name. The file-name encoding is not
1411 supposed to be changed too frequently, if ever. */
1412 static Lisp_Object last_file_name_encoding;
1413 static CPINFO cp;
1414 Lisp_Object current_encoding;
1416 current_encoding = Vfile_name_coding_system;
1417 if (NILP (current_encoding))
1418 current_encoding = Vdefault_file_name_coding_system;
1420 if (!EQ (last_file_name_encoding, current_encoding))
1422 /* Default to the current ANSI codepage. */
1423 file_name_codepage = w32_ansi_code_page;
1425 if (NILP (current_encoding))
1427 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1428 char *cp = NULL, *end;
1429 int cpnum;
1431 if (strncmp (cpname, "cp", 2) == 0)
1432 cp = cpname + 2;
1433 else if (strncmp (cpname, "windows-", 8) == 0)
1434 cp = cpname + 8;
1436 if (cp)
1438 end = cp;
1439 cpnum = strtol (cp, &end, 10);
1440 if (cpnum && *end == '\0' && end - cp >= 2)
1441 file_name_codepage = cpnum;
1445 if (!file_name_codepage)
1446 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1448 if (!GetCPInfo (file_name_codepage, &cp))
1450 file_name_codepage = CP_ACP;
1451 if (!GetCPInfo (file_name_codepage, &cp))
1452 emacs_abort ();
1455 if (cp_info)
1456 *cp_info = cp;
1458 return file_name_codepage;
1462 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1464 int result = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
1465 fn_out, MAX_PATH);
1467 if (!result)
1469 DWORD err = GetLastError ();
1471 switch (err)
1473 case ERROR_INVALID_FLAGS:
1474 case ERROR_INVALID_PARAMETER:
1475 errno = EINVAL;
1476 break;
1477 case ERROR_INSUFFICIENT_BUFFER:
1478 case ERROR_NO_UNICODE_TRANSLATION:
1479 default:
1480 errno = ENOENT;
1481 break;
1483 return -1;
1485 return 0;
1489 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1491 int result = WideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1492 fn_out, MAX_UTF8_PATH, NULL, NULL);
1494 if (!result)
1496 DWORD err = GetLastError ();
1498 switch (err)
1500 case ERROR_INVALID_FLAGS:
1501 case ERROR_INVALID_PARAMETER:
1502 errno = EINVAL;
1503 break;
1504 case ERROR_INSUFFICIENT_BUFFER:
1505 case ERROR_NO_UNICODE_TRANSLATION:
1506 default:
1507 errno = ENOENT;
1508 break;
1510 return -1;
1512 return 0;
1516 filename_to_ansi (const char *fn_in, char *fn_out)
1518 wchar_t fn_utf16[MAX_PATH];
1520 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1522 int result;
1523 int codepage = codepage_for_filenames (NULL);
1525 result = WideCharToMultiByte (codepage, 0, fn_utf16, -1,
1526 fn_out, MAX_PATH, NULL, NULL);
1527 if (!result)
1529 DWORD err = GetLastError ();
1531 switch (err)
1533 case ERROR_INVALID_FLAGS:
1534 case ERROR_INVALID_PARAMETER:
1535 errno = EINVAL;
1536 break;
1537 case ERROR_INSUFFICIENT_BUFFER:
1538 case ERROR_NO_UNICODE_TRANSLATION:
1539 default:
1540 errno = ENOENT;
1541 break;
1543 return -1;
1545 return 0;
1547 return -1;
1551 filename_from_ansi (const char *fn_in, char *fn_out)
1553 wchar_t fn_utf16[MAX_PATH];
1554 int codepage = codepage_for_filenames (NULL);
1555 int result = MultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
1556 fn_utf16, MAX_PATH);
1558 if (!result)
1560 DWORD err = GetLastError ();
1562 switch (err)
1564 case ERROR_INVALID_FLAGS:
1565 case ERROR_INVALID_PARAMETER:
1566 errno = EINVAL;
1567 break;
1568 case ERROR_INSUFFICIENT_BUFFER:
1569 case ERROR_NO_UNICODE_TRANSLATION:
1570 default:
1571 errno = ENOENT;
1572 break;
1574 return -1;
1576 return filename_from_utf16 (fn_utf16, fn_out);
1581 /* The directory where we started, in UTF-8. */
1582 static char startup_dir[MAX_UTF8_PATH];
1584 /* Get the current working directory. */
1585 char *
1586 getcwd (char *dir, int dirsize)
1588 if (!dirsize)
1590 errno = EINVAL;
1591 return NULL;
1593 if (dirsize <= strlen (startup_dir))
1595 errno = ERANGE;
1596 return NULL;
1598 #if 0
1599 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1600 return dir;
1601 return NULL;
1602 #else
1603 /* Emacs doesn't actually change directory itself, it stays in the
1604 same directory where it was started. */
1605 strcpy (dir, startup_dir);
1606 return dir;
1607 #endif
1610 /* Emulate getloadavg. */
1612 struct load_sample {
1613 time_t sample_time;
1614 ULONGLONG idle;
1615 ULONGLONG kernel;
1616 ULONGLONG user;
1619 /* Number of processors on this machine. */
1620 static unsigned num_of_processors;
1622 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1623 static struct load_sample samples[16*60];
1624 static int first_idx = -1, last_idx = -1;
1625 static int max_idx = sizeof (samples) / sizeof (samples[0]);
1627 static int
1628 buf_next (int from)
1630 int next_idx = from + 1;
1632 if (next_idx >= max_idx)
1633 next_idx = 0;
1635 return next_idx;
1638 static int
1639 buf_prev (int from)
1641 int prev_idx = from - 1;
1643 if (prev_idx < 0)
1644 prev_idx = max_idx - 1;
1646 return prev_idx;
1649 static void
1650 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1652 SYSTEM_INFO sysinfo;
1653 FILETIME ft_idle, ft_user, ft_kernel;
1655 /* Initialize the number of processors on this machine. */
1656 if (num_of_processors <= 0)
1658 get_native_system_info (&sysinfo);
1659 num_of_processors = sysinfo.dwNumberOfProcessors;
1660 if (num_of_processors <= 0)
1662 GetSystemInfo (&sysinfo);
1663 num_of_processors = sysinfo.dwNumberOfProcessors;
1665 if (num_of_processors <= 0)
1666 num_of_processors = 1;
1669 /* TODO: Take into account threads that are ready to run, by
1670 sampling the "\System\Processor Queue Length" performance
1671 counter. The code below accounts only for threads that are
1672 actually running. */
1674 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1676 ULARGE_INTEGER uidle, ukernel, uuser;
1678 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1679 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1680 memcpy (&uuser, &ft_user, sizeof (ft_user));
1681 *idle = uidle.QuadPart;
1682 *kernel = ukernel.QuadPart;
1683 *user = uuser.QuadPart;
1685 else
1687 *idle = 0;
1688 *kernel = 0;
1689 *user = 0;
1693 /* Produce the load average for a given time interval, using the
1694 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1695 1-minute, 5-minute, or 15-minute average, respectively. */
1696 static double
1697 getavg (int which)
1699 double retval = -1.0;
1700 double tdiff;
1701 int idx;
1702 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1703 time_t now = samples[last_idx].sample_time;
1705 if (first_idx != last_idx)
1707 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1709 tdiff = difftime (now, samples[idx].sample_time);
1710 if (tdiff >= span - 2*DBL_EPSILON*now)
1712 long double sys =
1713 samples[last_idx].kernel + samples[last_idx].user
1714 - (samples[idx].kernel + samples[idx].user);
1715 long double idl = samples[last_idx].idle - samples[idx].idle;
1717 retval = (1.0 - idl / sys) * num_of_processors;
1718 break;
1720 if (idx == first_idx)
1721 break;
1725 return retval;
1729 getloadavg (double loadavg[], int nelem)
1731 int elem;
1732 ULONGLONG idle, kernel, user;
1733 time_t now = time (NULL);
1735 /* If system time jumped back for some reason, delete all samples
1736 whose time is later than the current wall-clock time. This
1737 prevents load average figures from becoming frozen for prolonged
1738 periods of time, when system time is reset backwards. */
1739 if (last_idx >= 0)
1741 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1743 if (last_idx == first_idx)
1745 first_idx = last_idx = -1;
1746 break;
1748 last_idx = buf_prev (last_idx);
1752 /* Store another sample. We ignore samples that are less than 1 sec
1753 apart. */
1754 if (last_idx < 0
1755 || (difftime (now, samples[last_idx].sample_time)
1756 >= 1.0 - 2*DBL_EPSILON*now))
1758 sample_system_load (&idle, &kernel, &user);
1759 last_idx = buf_next (last_idx);
1760 samples[last_idx].sample_time = now;
1761 samples[last_idx].idle = idle;
1762 samples[last_idx].kernel = kernel;
1763 samples[last_idx].user = user;
1764 /* If the buffer has more that 15 min worth of samples, discard
1765 the old ones. */
1766 if (first_idx == -1)
1767 first_idx = last_idx;
1768 while (first_idx != last_idx
1769 && (difftime (now, samples[first_idx].sample_time)
1770 >= 15.0*60 + 2*DBL_EPSILON*now))
1771 first_idx = buf_next (first_idx);
1774 for (elem = 0; elem < nelem; elem++)
1776 double avg = getavg (elem);
1778 if (avg < 0)
1779 break;
1780 loadavg[elem] = avg;
1783 return elem;
1786 /* Emulate getpwuid, getpwnam and others. */
1788 #define PASSWD_FIELD_SIZE 256
1790 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1791 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1792 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1793 static char dflt_passwd_dir[MAX_UTF8_PATH];
1794 static char dflt_passwd_shell[MAX_UTF8_PATH];
1796 static struct passwd dflt_passwd =
1798 dflt_passwd_name,
1799 dflt_passwd_passwd,
1803 dflt_passwd_gecos,
1804 dflt_passwd_dir,
1805 dflt_passwd_shell,
1808 static char dflt_group_name[GNLEN+1];
1810 static struct group dflt_group =
1812 /* When group information is not available, we return this as the
1813 group for all files. */
1814 dflt_group_name,
1818 unsigned
1819 getuid (void)
1821 return dflt_passwd.pw_uid;
1824 unsigned
1825 geteuid (void)
1827 /* I could imagine arguing for checking to see whether the user is
1828 in the Administrators group and returning a UID of 0 for that
1829 case, but I don't know how wise that would be in the long run. */
1830 return getuid ();
1833 unsigned
1834 getgid (void)
1836 return dflt_passwd.pw_gid;
1839 unsigned
1840 getegid (void)
1842 return getgid ();
1845 struct passwd *
1846 getpwuid (unsigned uid)
1848 if (uid == dflt_passwd.pw_uid)
1849 return &dflt_passwd;
1850 return NULL;
1853 struct group *
1854 getgrgid (gid_t gid)
1856 return &dflt_group;
1859 struct passwd *
1860 getpwnam (char *name)
1862 struct passwd *pw;
1864 pw = getpwuid (getuid ());
1865 if (!pw)
1866 return pw;
1868 if (xstrcasecmp (name, pw->pw_name))
1869 return NULL;
1871 return pw;
1874 static void
1875 init_user_info (void)
1877 /* Find the user's real name by opening the process token and
1878 looking up the name associated with the user-sid in that token.
1880 Use the relative portion of the identifier authority value from
1881 the user-sid as the user id value (same for group id using the
1882 primary group sid from the process token). */
1884 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1885 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1886 DWORD glength = sizeof (gname);
1887 HANDLE token = NULL;
1888 SID_NAME_USE user_type;
1889 unsigned char *buf = NULL;
1890 DWORD blen = 0;
1891 TOKEN_USER user_token;
1892 TOKEN_PRIMARY_GROUP group_token;
1893 BOOL result;
1895 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1896 if (result)
1898 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1899 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1901 buf = xmalloc (blen);
1902 result = get_token_information (token, TokenUser,
1903 (LPVOID)buf, blen, &needed);
1904 if (result)
1906 memcpy (&user_token, buf, sizeof (user_token));
1907 result = lookup_account_sid (NULL, user_token.User.Sid,
1908 uname, &ulength,
1909 domain, &dlength, &user_type);
1912 else
1913 result = FALSE;
1915 if (result)
1917 strcpy (dflt_passwd.pw_name, uname);
1918 /* Determine a reasonable uid value. */
1919 if (xstrcasecmp ("administrator", uname) == 0)
1921 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1922 dflt_passwd.pw_gid = 513; /* well-known None gid */
1924 else
1926 /* Use the last sub-authority value of the RID, the relative
1927 portion of the SID, as user/group ID. */
1928 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1930 /* Get group id and name. */
1931 result = get_token_information (token, TokenPrimaryGroup,
1932 (LPVOID)buf, blen, &needed);
1933 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1935 buf = xrealloc (buf, blen = needed);
1936 result = get_token_information (token, TokenPrimaryGroup,
1937 (LPVOID)buf, blen, &needed);
1939 if (result)
1941 memcpy (&group_token, buf, sizeof (group_token));
1942 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1943 dlength = sizeof (domain);
1944 /* If we can get at the real Primary Group name, use that.
1945 Otherwise, the default group name was already set to
1946 "None" in globals_of_w32. */
1947 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1948 gname, &glength, NULL, &dlength,
1949 &user_type))
1950 strcpy (dflt_group_name, gname);
1952 else
1953 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1956 /* If security calls are not supported (presumably because we
1957 are running under Windows 9X), fallback to this: */
1958 else if (GetUserName (uname, &ulength))
1960 strcpy (dflt_passwd.pw_name, uname);
1961 if (xstrcasecmp ("administrator", uname) == 0)
1962 dflt_passwd.pw_uid = 0;
1963 else
1964 dflt_passwd.pw_uid = 123;
1965 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1967 else
1969 strcpy (dflt_passwd.pw_name, "unknown");
1970 dflt_passwd.pw_uid = 123;
1971 dflt_passwd.pw_gid = 123;
1973 dflt_group.gr_gid = dflt_passwd.pw_gid;
1975 /* Set dir and shell from environment variables. */
1976 if (w32_unicode_filenames)
1978 wchar_t *home = _wgetenv (L"HOME");
1979 wchar_t *shell = _wgetenv (L"SHELL");
1981 /* Ensure HOME and SHELL are defined. */
1982 if (home == NULL)
1983 emacs_abort ();
1984 if (shell == NULL)
1985 emacs_abort ();
1986 filename_from_utf16 (home, dflt_passwd.pw_dir);
1987 filename_from_utf16 (shell, dflt_passwd.pw_shell);
1989 else
1991 char *home = getenv ("HOME");
1992 char *shell = getenv ("SHELL");
1994 if (home == NULL)
1995 emacs_abort ();
1996 if (shell == NULL)
1997 emacs_abort ();
1998 filename_from_ansi (home, dflt_passwd.pw_dir);
1999 filename_from_ansi (shell, dflt_passwd.pw_shell);
2002 xfree (buf);
2003 if (token)
2004 CloseHandle (token);
2008 random (void)
2010 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
2011 return ((rand () << 15) | rand ());
2014 void
2015 srandom (int seed)
2017 srand (seed);
2020 /* Return the maximum length in bytes of a multibyte character
2021 sequence encoded in the current ANSI codepage. This is required to
2022 correctly walk the encoded file names one character at a time. */
2023 static int
2024 max_filename_mbslen (void)
2026 CPINFO cp_info;
2028 codepage_for_filenames (&cp_info);
2029 return cp_info.MaxCharSize;
2032 /* Normalize filename by converting in-place all of its path
2033 separators to the separator specified by PATH_SEP. */
2035 static void
2036 normalize_filename (register char *fp, char path_sep)
2038 char *p2;
2040 /* Always lower-case drive letters a-z, even if the filesystem
2041 preserves case in filenames.
2042 This is so filenames can be compared by string comparison
2043 functions that are case-sensitive. Even case-preserving filesystems
2044 do not distinguish case in drive letters. */
2045 p2 = fp + 1;
2047 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2049 *fp += 'a' - 'A';
2050 fp += 2;
2053 while (*fp)
2055 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2056 *fp = path_sep;
2057 fp++;
2061 /* Destructively turn backslashes into slashes. */
2062 void
2063 dostounix_filename (register char *p)
2065 normalize_filename (p, '/');
2068 /* Destructively turn slashes into backslashes. */
2069 void
2070 unixtodos_filename (register char *p)
2072 normalize_filename (p, '\\');
2075 /* Remove all CR's that are followed by a LF.
2076 (From msdos.c...probably should figure out a way to share it,
2077 although this code isn't going to ever change.) */
2078 static int
2079 crlf_to_lf (register int n, register unsigned char *buf)
2081 unsigned char *np = buf;
2082 unsigned char *startp = buf;
2083 unsigned char *endp = buf + n;
2085 if (n == 0)
2086 return n;
2087 while (buf < endp - 1)
2089 if (*buf == 0x0d)
2091 if (*(++buf) != 0x0a)
2092 *np++ = 0x0d;
2094 else
2095 *np++ = *buf++;
2097 if (buf < endp)
2098 *np++ = *buf++;
2099 return np - startp;
2102 /* Parse the root part of file name, if present. Return length and
2103 optionally store pointer to char after root. */
2104 static int
2105 parse_root (const char * name, const char ** pPath)
2107 const char * start = name;
2109 if (name == NULL)
2110 return 0;
2112 /* find the root name of the volume if given */
2113 if (isalpha (name[0]) && name[1] == ':')
2115 /* skip past drive specifier */
2116 name += 2;
2117 if (IS_DIRECTORY_SEP (name[0]))
2118 name++;
2120 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2122 int slashes = 2;
2124 name += 2;
2127 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2128 break;
2129 name++;
2131 while ( *name );
2132 if (IS_DIRECTORY_SEP (name[0]))
2133 name++;
2136 if (pPath)
2137 *pPath = name;
2139 return name - start;
2142 /* Get long base name for name; name is assumed to be absolute. */
2143 static int
2144 get_long_basename (char * name, char * buf, int size)
2146 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2147 char fname_utf8[MAX_UTF8_PATH];
2148 int len = 0;
2149 int cstatus = -1;
2151 /* Must be valid filename, no wild cards or other invalid characters. */
2152 if (strpbrk (name, "*?|<>\""))
2153 return 0;
2155 if (w32_unicode_filenames)
2157 wchar_t fname_utf16[MAX_PATH];
2158 WIN32_FIND_DATAW find_data_wide;
2160 filename_to_utf16 (name, fname_utf16);
2161 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2162 if (dir_handle != INVALID_HANDLE_VALUE)
2163 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2165 else
2167 char fname_ansi[MAX_PATH];
2168 WIN32_FIND_DATAA find_data_ansi;
2170 filename_to_ansi (name, fname_ansi);
2171 /* If the ANSI name includes ? characters, it is not encodable
2172 in the ANSI codepage. In that case, we deliver the question
2173 marks to the caller; calling FindFirstFileA in this case
2174 could return some unrelated file name in the same
2175 directory. */
2176 if (_mbspbrk (fname_ansi, "?"))
2178 /* Find the basename of fname_ansi. */
2179 char *p = strrchr (fname_ansi, '\\');
2181 if (!p)
2182 p = fname_ansi;
2183 else
2184 p++;
2185 cstatus = filename_from_ansi (p, fname_utf8);
2187 else
2189 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2190 if (dir_handle != INVALID_HANDLE_VALUE)
2191 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2195 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2196 memcpy (buf, fname_utf8, len + 1);
2197 else
2198 len = 0;
2200 if (dir_handle != INVALID_HANDLE_VALUE)
2201 FindClose (dir_handle);
2203 return len;
2206 /* Get long name for file, if possible (assumed to be absolute). */
2207 BOOL
2208 w32_get_long_filename (char * name, char * buf, int size)
2210 char * o = buf;
2211 char * p;
2212 const char * q;
2213 char full[ MAX_UTF8_PATH ];
2214 int len;
2216 len = strlen (name);
2217 if (len >= MAX_UTF8_PATH)
2218 return FALSE;
2220 /* Use local copy for destructive modification. */
2221 memcpy (full, name, len+1);
2222 unixtodos_filename (full);
2224 /* Copy root part verbatim. */
2225 len = parse_root (full, (const char **)&p);
2226 memcpy (o, full, len);
2227 o += len;
2228 *o = '\0';
2229 size -= len;
2231 while (p != NULL && *p)
2233 q = p;
2234 p = strchr (q, '\\');
2235 if (p) *p = '\0';
2236 len = get_long_basename (full, o, size);
2237 if (len > 0)
2239 o += len;
2240 size -= len;
2241 if (p != NULL)
2243 *p++ = '\\';
2244 if (size < 2)
2245 return FALSE;
2246 *o++ = '\\';
2247 size--;
2248 *o = '\0';
2251 else
2252 return FALSE;
2255 return TRUE;
2258 unsigned int
2259 w32_get_short_filename (char * name, char * buf, int size)
2261 if (w32_unicode_filenames)
2263 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2264 unsigned int retval;
2266 filename_to_utf16 (name, name_utf16);
2267 retval = GetShortPathNameW (name_utf16, short_name, size);
2268 if (retval && retval < size)
2269 filename_from_utf16 (short_name, buf);
2270 return retval;
2272 else
2274 char name_ansi[MAX_PATH];
2276 filename_to_ansi (name, name_ansi);
2277 return GetShortPathNameA (name_ansi, buf, size);
2281 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2282 MS-Windows ANSI codepage. If FILENAME includes characters not
2283 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2284 if it exists. This is needed because the w32 build wants to
2285 support file names outside of the system locale, but image
2286 libraries typically don't support wide (a.k.a. "Unicode") APIs
2287 required for that. */
2289 Lisp_Object
2290 ansi_encode_filename (Lisp_Object filename)
2292 Lisp_Object encoded_filename;
2293 char fname[MAX_PATH];
2295 filename_to_ansi (SSDATA (filename), fname);
2296 if (_mbspbrk (fname, "?"))
2298 char shortname[MAX_PATH];
2300 if (w32_get_short_filename (SDATA (filename), shortname, MAX_PATH))
2302 dostounix_filename (shortname);
2303 encoded_filename = build_string (shortname);
2306 else
2307 encoded_filename = build_unibyte_string (fname);
2308 return encoded_filename;
2311 static int
2312 is_unc_volume (const char *filename)
2314 const char *ptr = filename;
2316 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2317 return 0;
2319 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2320 return 0;
2322 return 1;
2325 /* Emulate the Posix unsetenv. */
2327 unsetenv (const char *name)
2329 char *var;
2330 size_t name_len;
2331 int retval;
2333 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2335 errno = EINVAL;
2336 return -1;
2338 name_len = strlen (name);
2339 /* MS docs says an environment variable cannot be longer than 32K. */
2340 if (name_len > 32767)
2342 errno = ENOMEM;
2343 return 0;
2345 /* It is safe to use 'alloca' with 32K size, since the stack is at
2346 least 2MB, and we set it to 8MB in the link command line. */
2347 var = alloca (name_len + 2);
2348 strncpy (var, name, name_len);
2349 var[name_len++] = '=';
2350 var[name_len] = '\0';
2351 return _putenv (var);
2354 /* MS _putenv doesn't support removing a variable when the argument
2355 does not include the '=' character, so we fix that here. */
2357 sys_putenv (char *str)
2359 const char *const name_end = strchr (str, '=');
2361 if (name_end == NULL)
2363 /* Remove the variable from the environment. */
2364 return unsetenv (str);
2367 return _putenv (str);
2370 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2372 LPBYTE
2373 w32_get_resource (char *key, LPDWORD lpdwtype)
2375 LPBYTE lpvalue;
2376 HKEY hrootkey = NULL;
2377 DWORD cbData;
2379 /* Check both the current user and the local machine to see if
2380 we have any resources. */
2382 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2384 lpvalue = NULL;
2386 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2387 && (lpvalue = xmalloc (cbData)) != NULL
2388 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2390 RegCloseKey (hrootkey);
2391 return (lpvalue);
2394 xfree (lpvalue);
2396 RegCloseKey (hrootkey);
2399 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2401 lpvalue = NULL;
2403 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2404 && (lpvalue = xmalloc (cbData)) != NULL
2405 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2407 RegCloseKey (hrootkey);
2408 return (lpvalue);
2411 xfree (lpvalue);
2413 RegCloseKey (hrootkey);
2416 return (NULL);
2419 /* The argv[] array holds ANSI-encoded strings, and so this function
2420 works with ANS_encoded strings. */
2421 void
2422 init_environment (char ** argv)
2424 static const char * const tempdirs[] = {
2425 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2428 int i;
2430 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
2432 /* Implementation note: This function explicitly works with ANSI
2433 file names, not with UTF-8 encoded file names. This is because
2434 this function pushes variables into the Emacs's environment, and
2435 the environment variables are always assumed to be in the
2436 locale-specific encoding. Do NOT call any functions that accept
2437 UTF-8 file names from this function! */
2439 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2440 temporary files and assume "/tmp" if $TMPDIR is unset, which
2441 will break on DOS/Windows. Refuse to work if we cannot find
2442 a directory, not even "c:/", usable for that purpose. */
2443 for (i = 0; i < imax ; i++)
2445 const char *tmp = tempdirs[i];
2447 if (*tmp == '$')
2448 tmp = getenv (tmp + 1);
2449 /* Note that `access' can lie to us if the directory resides on a
2450 read-only filesystem, like CD-ROM or a write-protected floppy.
2451 The only way to be really sure is to actually create a file and
2452 see if it succeeds. But I think that's too much to ask. */
2454 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2455 if (tmp && sys_access (tmp, D_OK) == 0)
2457 char * var = alloca (strlen (tmp) + 8);
2458 sprintf (var, "TMPDIR=%s", tmp);
2459 _putenv (strdup (var));
2460 break;
2463 if (i >= imax)
2464 cmd_error_internal
2465 (Fcons (Qerror,
2466 Fcons (build_string ("no usable temporary directories found!!"),
2467 Qnil)),
2468 "While setting TMPDIR: ");
2470 /* Check for environment variables and use registry settings if they
2471 don't exist. Fallback on default values where applicable. */
2473 int i;
2474 LPBYTE lpval;
2475 DWORD dwType;
2476 char locale_name[32];
2477 char default_home[MAX_PATH];
2478 int appdata = 0;
2480 static const struct env_entry
2482 char * name;
2483 char * def_value;
2484 } dflt_envvars[] =
2486 /* If the default value is NULL, we will use the value from the
2487 outside environment or the Registry, but will not push the
2488 variable into the Emacs environment if it is defined neither
2489 in the Registry nor in the outside environment. */
2490 {"HOME", "C:/"},
2491 {"PRELOAD_WINSOCK", NULL},
2492 {"emacs_dir", "C:/emacs"},
2493 {"EMACSLOADPATH", NULL},
2494 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2495 {"EMACSDATA", NULL},
2496 {"EMACSPATH", NULL},
2497 {"INFOPATH", NULL},
2498 {"EMACSDOC", NULL},
2499 {"TERM", "cmd"},
2500 {"LANG", NULL},
2503 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
2505 /* We need to copy dflt_envvars[] and work on the copy because we
2506 don't want the dumped Emacs to inherit the values of
2507 environment variables we saw during dumping (which could be on
2508 a different system). The defaults above must be left intact. */
2509 struct env_entry env_vars[N_ENV_VARS];
2511 for (i = 0; i < N_ENV_VARS; i++)
2512 env_vars[i] = dflt_envvars[i];
2514 /* For backwards compatibility, check if a .emacs file exists in C:/
2515 If not, then we can try to default to the appdata directory under the
2516 user's profile, which is more likely to be writable. */
2517 if (sys_access ("C:/.emacs", F_OK) != 0)
2519 HRESULT profile_result;
2520 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2521 of Windows 95 and NT4 that have not been updated to include
2522 MSIE 5. */
2523 ShGetFolderPath_fn get_folder_path;
2524 get_folder_path = (ShGetFolderPath_fn)
2525 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2527 if (get_folder_path != NULL)
2529 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2530 0, default_home);
2532 /* If we can't get the appdata dir, revert to old behavior. */
2533 if (profile_result == S_OK)
2535 env_vars[0].def_value = default_home;
2536 appdata = 1;
2541 /* Get default locale info and use it for LANG. */
2542 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2543 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2544 locale_name, sizeof (locale_name)))
2546 for (i = 0; i < N_ENV_VARS; i++)
2548 if (strcmp (env_vars[i].name, "LANG") == 0)
2550 env_vars[i].def_value = locale_name;
2551 break;
2556 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2558 /* Treat emacs_dir specially: set it unconditionally based on our
2559 location. */
2561 char *p;
2562 char modname[MAX_PATH];
2564 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2565 emacs_abort ();
2566 if ((p = _mbsrchr (modname, '\\')) == NULL)
2567 emacs_abort ();
2568 *p = 0;
2570 if ((p = _mbsrchr (modname, '\\'))
2571 /* From bin means installed Emacs, from src means uninstalled. */
2572 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2574 char buf[SET_ENV_BUF_SIZE];
2575 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2577 *p = 0;
2578 for (p = modname; *p; p = CharNext (p))
2579 if (*p == '\\') *p = '/';
2581 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2582 _putenv (strdup (buf));
2583 /* If we are running from the Posix-like build tree, define
2584 SHELL to point to our own cmdproxy. The loop below will
2585 then disregard PATH_EXEC and the default value. */
2586 if (within_build_tree)
2588 _snprintf (buf, sizeof (buf) - 1,
2589 "SHELL=%s/nt/cmdproxy.exe", modname);
2590 _putenv (strdup (buf));
2595 for (i = 0; i < N_ENV_VARS; i++)
2597 if (!getenv (env_vars[i].name))
2599 int dont_free = 0;
2600 char bufc[SET_ENV_BUF_SIZE];
2602 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2603 /* Also ignore empty environment variables. */
2604 || *lpval == 0)
2606 xfree (lpval);
2607 dont_free = 1;
2608 if (strcmp (env_vars[i].name, "SHELL") == 0)
2610 /* Look for cmdproxy.exe in every directory in
2611 PATH_EXEC. FIXME: This does not find cmdproxy
2612 in nt/ when we run uninstalled. */
2613 char fname[MAX_PATH];
2614 const char *pstart = PATH_EXEC, *pend;
2616 do {
2617 pend = _mbschr (pstart, ';');
2618 if (!pend)
2619 pend = pstart + strlen (pstart);
2620 /* Be defensive against series of ;;; characters. */
2621 if (pend > pstart)
2623 strncpy (fname, pstart, pend - pstart);
2624 fname[pend - pstart] = '/';
2625 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2626 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2627 sizeof (bufc));
2628 if (sys_access (bufc, F_OK) == 0)
2630 lpval = bufc;
2631 dwType = REG_SZ;
2632 break;
2635 if (*pend)
2636 pstart = pend + 1;
2637 else
2638 pstart = pend;
2639 if (!*pstart)
2641 /* If not found in any directory, use the
2642 default as the last resort. */
2643 lpval = env_vars[i].def_value;
2644 dwType = REG_EXPAND_SZ;
2646 } while (*pstart);
2648 else
2650 lpval = env_vars[i].def_value;
2651 dwType = REG_EXPAND_SZ;
2653 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2654 Vdelayed_warnings_list
2655 = Fcons (listn (CONSTYPE_HEAP, 2,
2656 intern ("initialization"),
2657 build_string ("Setting HOME to C:\\ by default is deprecated")),
2658 Vdelayed_warnings_list);
2661 if (lpval)
2663 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2665 if (dwType == REG_EXPAND_SZ)
2666 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2667 else if (dwType == REG_SZ)
2668 strcpy (buf1, lpval);
2669 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2671 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2672 buf1);
2673 _putenv (strdup (buf2));
2676 if (!dont_free)
2677 xfree (lpval);
2683 /* Rebuild system configuration to reflect invoking system. */
2684 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2686 /* Another special case: on NT, the PATH variable is actually named
2687 "Path" although cmd.exe (perhaps NT itself) arranges for
2688 environment variable lookup and setting to be case insensitive.
2689 However, Emacs assumes a fully case sensitive environment, so we
2690 need to change "Path" to "PATH" to match the expectations of
2691 various elisp packages. We do this by the sneaky method of
2692 modifying the string in the C runtime environ entry.
2694 The same applies to COMSPEC. */
2696 char ** envp;
2698 for (envp = environ; *envp; envp++)
2699 if (_strnicmp (*envp, "PATH=", 5) == 0)
2700 memcpy (*envp, "PATH=", 5);
2701 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
2702 memcpy (*envp, "COMSPEC=", 8);
2705 /* Remember the initial working directory for getcwd. */
2706 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2707 Does it matter anywhere in Emacs? */
2708 if (w32_unicode_filenames)
2710 wchar_t wstartup_dir[MAX_PATH];
2712 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2713 emacs_abort ();
2714 filename_from_utf16 (wstartup_dir, startup_dir);
2716 else
2718 char astartup_dir[MAX_PATH];
2720 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2721 emacs_abort ();
2722 filename_from_ansi (astartup_dir, startup_dir);
2726 static char modname[MAX_PATH];
2728 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2729 emacs_abort ();
2730 argv[0] = modname;
2733 /* Determine if there is a middle mouse button, to allow parse_button
2734 to decide whether right mouse events should be mouse-2 or
2735 mouse-3. */
2736 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2738 init_user_info ();
2741 /* Called from expand-file-name when default-directory is not a string. */
2743 char *
2744 emacs_root_dir (void)
2746 static char root_dir[MAX_UTF8_PATH];
2747 const char *p;
2749 p = getenv ("emacs_dir");
2750 if (p == NULL)
2751 emacs_abort ();
2752 filename_from_ansi (p, root_dir);
2753 root_dir[parse_root (root_dir, NULL)] = '\0';
2754 dostounix_filename (root_dir);
2755 return root_dir;
2758 #include <sys/timeb.h>
2760 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2762 gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
2764 struct _timeb tb;
2765 _ftime (&tb);
2767 tv->tv_sec = tb.time;
2768 tv->tv_usec = tb.millitm * 1000L;
2769 /* Implementation note: _ftime sometimes doesn't update the dstflag
2770 according to the new timezone when the system timezone is
2771 changed. We could fix that by using GetSystemTime and
2772 GetTimeZoneInformation, but that doesn't seem necessary, since
2773 Emacs always calls gettimeofday with the 2nd argument NULL (see
2774 current_emacs_time). */
2775 if (tz)
2777 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2778 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2780 return 0;
2783 /* Emulate fdutimens. */
2785 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2786 TIMESPEC[0] and TIMESPEC[1], respectively.
2787 FD must be either negative -- in which case it is ignored --
2788 or a file descriptor that is open on FILE.
2789 If FD is nonnegative, then FILE can be NULL, which means
2790 use just futimes instead of utimes.
2791 If TIMESPEC is null, FAIL.
2792 Return 0 on success, -1 (setting errno) on failure. */
2795 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2797 if (!timespec)
2799 errno = ENOSYS;
2800 return -1;
2802 if (fd < 0 && !file)
2804 errno = EBADF;
2805 return -1;
2807 /* _futime's prototype defines 2nd arg as having the type 'struct
2808 _utimbuf', while utime needs to accept 'struct utimbuf' for
2809 compatibility with Posix. So we need to use 2 different (but
2810 equivalent) types to avoid compiler warnings, sigh. */
2811 if (fd >= 0)
2813 struct _utimbuf _ut;
2815 _ut.actime = timespec[0].tv_sec;
2816 _ut.modtime = timespec[1].tv_sec;
2817 return _futime (fd, &_ut);
2819 else
2821 struct utimbuf ut;
2823 ut.actime = timespec[0].tv_sec;
2824 ut.modtime = timespec[1].tv_sec;
2825 /* Call 'utime', which is implemented below, not the MS library
2826 function, which fails on directories. */
2827 return utime (file, &ut);
2832 /* ------------------------------------------------------------------------- */
2833 /* IO support and wrapper functions for the Windows API. */
2834 /* ------------------------------------------------------------------------- */
2836 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2837 on network directories, so we handle that case here.
2838 (Ulrich Leodolter, 1/11/95). */
2839 char *
2840 sys_ctime (const time_t *t)
2842 char *str = (char *) ctime (t);
2843 return (str ? str : "Sun Jan 01 00:00:00 1970");
2846 /* Emulate sleep...we could have done this with a define, but that
2847 would necessitate including windows.h in the files that used it.
2848 This is much easier. */
2849 void
2850 sys_sleep (int seconds)
2852 Sleep (seconds * 1000);
2855 /* Internal MSVC functions for low-level descriptor munging */
2856 extern int __cdecl _set_osfhnd (int fd, long h);
2857 extern int __cdecl _free_osfhnd (int fd);
2859 /* parallel array of private info on file handles */
2860 filedesc fd_info [ MAXDESC ];
2862 typedef struct volume_info_data {
2863 struct volume_info_data * next;
2865 /* time when info was obtained */
2866 DWORD timestamp;
2868 /* actual volume info */
2869 char * root_dir;
2870 DWORD serialnum;
2871 DWORD maxcomp;
2872 DWORD flags;
2873 char * name;
2874 char * type;
2875 } volume_info_data;
2877 /* Global referenced by various functions. */
2878 static volume_info_data volume_info;
2880 /* Vector to indicate which drives are local and fixed (for which cached
2881 data never expires). */
2882 static BOOL fixed_drives[26];
2884 /* Consider cached volume information to be stale if older than 10s,
2885 at least for non-local drives. Info for fixed drives is never stale. */
2886 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2887 #define VOLINFO_STILL_VALID( root_dir, info ) \
2888 ( ( isalpha (root_dir[0]) && \
2889 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2890 || GetTickCount () - info->timestamp < 10000 )
2892 /* Cache support functions. */
2894 /* Simple linked list with linear search is sufficient. */
2895 static volume_info_data *volume_cache = NULL;
2897 static volume_info_data *
2898 lookup_volume_info (char * root_dir)
2900 volume_info_data * info;
2902 for (info = volume_cache; info; info = info->next)
2903 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2904 break;
2905 return info;
2908 static void
2909 add_volume_info (char * root_dir, volume_info_data * info)
2911 info->root_dir = xstrdup (root_dir);
2912 unixtodos_filename (info->root_dir);
2913 info->next = volume_cache;
2914 volume_cache = info;
2918 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2919 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2920 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2921 static volume_info_data *
2922 GetCachedVolumeInformation (char * root_dir)
2924 volume_info_data * info;
2925 char default_root[ MAX_UTF8_PATH ];
2926 char name[MAX_PATH+1];
2927 char type[MAX_PATH+1];
2929 /* NULL for root_dir means use root from current directory. */
2930 if (root_dir == NULL)
2932 if (w32_unicode_filenames)
2934 wchar_t curdirw[MAX_PATH];
2936 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
2937 return NULL;
2938 filename_from_utf16 (curdirw, default_root);
2940 else
2942 char curdira[MAX_PATH];
2944 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
2945 return NULL;
2946 filename_from_ansi (curdira, default_root);
2948 parse_root (default_root, (const char **)&root_dir);
2949 *root_dir = 0;
2950 root_dir = default_root;
2953 /* Local fixed drives can be cached permanently. Removable drives
2954 cannot be cached permanently, since the volume name and serial
2955 number (if nothing else) can change. Remote drives should be
2956 treated as if they are removable, since there is no sure way to
2957 tell whether they are or not. Also, the UNC association of drive
2958 letters mapped to remote volumes can be changed at any time (even
2959 by other processes) without notice.
2961 As a compromise, so we can benefit from caching info for remote
2962 volumes, we use a simple expiry mechanism to invalidate cache
2963 entries that are more than ten seconds old. */
2965 #if 0
2966 /* No point doing this, because WNetGetConnection is even slower than
2967 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2968 GetDriveType is about the only call of this type which does not
2969 involve network access, and so is extremely quick). */
2971 /* Map drive letter to UNC if remote. */
2972 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2974 char remote_name[ 256 ];
2975 char drive[3] = { root_dir[0], ':' };
2977 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2978 == NO_ERROR)
2979 /* do something */ ;
2981 #endif
2983 info = lookup_volume_info (root_dir);
2985 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2987 DWORD serialnum;
2988 DWORD maxcomp;
2989 DWORD flags;
2991 /* Info is not cached, or is stale. */
2992 if (w32_unicode_filenames)
2994 wchar_t root_w[MAX_PATH];
2995 wchar_t name_w[MAX_PATH+1];
2996 wchar_t type_w[MAX_PATH+1];
2998 filename_to_utf16 (root_dir, root_w);
2999 if (!GetVolumeInformationW (root_w,
3000 name_w, sizeof (name_w),
3001 &serialnum,
3002 &maxcomp,
3003 &flags,
3004 type_w, sizeof (type_w)))
3005 return NULL;
3006 /* Hmm... not really 100% correct, as these 2 are not file
3007 names... */
3008 filename_from_utf16 (name_w, name);
3009 filename_from_utf16 (type_w, type);
3011 else
3013 char root_a[MAX_PATH];
3014 char name_a[MAX_PATH+1];
3015 char type_a[MAX_PATH+1];
3017 filename_to_ansi (root_dir, root_a);
3018 if (!GetVolumeInformationA (root_a,
3019 name_a, sizeof (name_a),
3020 &serialnum,
3021 &maxcomp,
3022 &flags,
3023 type_a, sizeof (type_a)))
3024 return NULL;
3025 filename_from_ansi (name_a, name);
3026 filename_from_ansi (type_a, type);
3029 /* Cache the volume information for future use, overwriting existing
3030 entry if present. */
3031 if (info == NULL)
3033 info = xmalloc (sizeof (volume_info_data));
3034 add_volume_info (root_dir, info);
3036 else
3038 xfree (info->name);
3039 xfree (info->type);
3042 info->name = xstrdup (name);
3043 unixtodos_filename (info->name);
3044 info->serialnum = serialnum;
3045 info->maxcomp = maxcomp;
3046 info->flags = flags;
3047 info->type = xstrdup (type);
3048 info->timestamp = GetTickCount ();
3051 return info;
3054 /* Get information on the volume where NAME is held; set path pointer to
3055 start of pathname in NAME (past UNC header\volume header if present),
3056 if pPath is non-NULL.
3058 Note: if NAME includes symlinks, the information is for the volume
3059 of the symlink, not of its target. That's because, even though
3060 GetVolumeInformation returns information about the symlink target
3061 of its argument, we only pass the root directory to
3062 GetVolumeInformation, not the full NAME. */
3063 static int
3064 get_volume_info (const char * name, const char ** pPath)
3066 char temp[MAX_UTF8_PATH];
3067 char *rootname = NULL; /* default to current volume */
3068 volume_info_data * info;
3069 int root_len = parse_root (name, pPath);
3071 if (name == NULL)
3072 return FALSE;
3074 /* Copy the root name of the volume, if given. */
3075 if (root_len)
3077 strncpy (temp, name, root_len);
3078 temp[root_len] = '\0';
3079 unixtodos_filename (temp);
3080 rootname = temp;
3083 info = GetCachedVolumeInformation (rootname);
3084 if (info != NULL)
3086 /* Set global referenced by other functions. */
3087 volume_info = *info;
3088 return TRUE;
3090 return FALSE;
3093 /* Determine if volume is FAT format (ie. only supports short 8.3
3094 names); also set path pointer to start of pathname in name, if
3095 pPath is non-NULL. */
3096 static int
3097 is_fat_volume (const char * name, const char ** pPath)
3099 if (get_volume_info (name, pPath))
3100 return (volume_info.maxcomp == 12);
3101 return FALSE;
3104 /* Convert all slashes in a filename to backslashes, and map filename
3105 to a valid 8.3 name if necessary. The result is a pointer to a
3106 static buffer, so CAVEAT EMPTOR! */
3107 const char *
3108 map_w32_filename (const char * name, const char ** pPath)
3110 static char shortname[MAX_UTF8_PATH];
3111 char * str = shortname;
3112 char c;
3113 char * path;
3114 const char * save_name = name;
3116 if (strlen (name) >= sizeof (shortname))
3118 /* Return a filename which will cause callers to fail. */
3119 strcpy (shortname, "?");
3120 return shortname;
3123 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3125 register int left = 8; /* maximum number of chars in part */
3126 register int extn = 0; /* extension added? */
3127 register int dots = 2; /* maximum number of dots allowed */
3129 while (name < path)
3130 *str++ = *name++; /* skip past UNC header */
3132 while ((c = *name++))
3134 switch ( c )
3136 case ':':
3137 case '\\':
3138 case '/':
3139 *str++ = (c == ':' ? ':' : '\\');
3140 extn = 0; /* reset extension flags */
3141 dots = 2; /* max 2 dots */
3142 left = 8; /* max length 8 for main part */
3143 break;
3144 case '.':
3145 if ( dots )
3147 /* Convert path components of the form .xxx to _xxx,
3148 but leave . and .. as they are. This allows .emacs
3149 to be read as _emacs, for example. */
3151 if (! *name ||
3152 *name == '.' ||
3153 IS_DIRECTORY_SEP (*name))
3155 *str++ = '.';
3156 dots--;
3158 else
3160 *str++ = '_';
3161 left--;
3162 dots = 0;
3165 else if ( !extn )
3167 *str++ = '.';
3168 extn = 1; /* we've got an extension */
3169 left = 3; /* 3 chars in extension */
3171 else
3173 /* any embedded dots after the first are converted to _ */
3174 *str++ = '_';
3176 break;
3177 case '~':
3178 case '#': /* don't lose these, they're important */
3179 if ( ! left )
3180 str[-1] = c; /* replace last character of part */
3181 /* FALLTHRU */
3182 default:
3183 if ( left && 'A' <= c && c <= 'Z' )
3185 *str++ = tolower (c); /* map to lower case (looks nicer) */
3186 left--;
3187 dots = 0; /* started a path component */
3189 break;
3192 *str = '\0';
3194 else
3196 strcpy (shortname, name);
3197 unixtodos_filename (shortname);
3200 if (pPath)
3201 *pPath = shortname + (path - save_name);
3203 return shortname;
3206 static int
3207 is_exec (const char * name)
3209 char * p = strrchr (name, '.');
3210 return
3211 (p != NULL
3212 && (xstrcasecmp (p, ".exe") == 0 ||
3213 xstrcasecmp (p, ".com") == 0 ||
3214 xstrcasecmp (p, ".bat") == 0 ||
3215 xstrcasecmp (p, ".cmd") == 0));
3218 /* Emulate the Unix directory procedures opendir, closedir, and
3219 readdir. We rename them to sys_* names because some versions of
3220 MinGW startup code call opendir and readdir to glob wildcards, and
3221 the code that calls them doesn't grok UTF-8 encoded file names we
3222 produce in dirent->d_name[]. */
3224 struct dirent dir_static; /* simulated directory contents */
3225 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3226 static int dir_is_fat;
3227 static char dir_pathname[MAX_UTF8_PATH];
3228 static WIN32_FIND_DATAW dir_find_data_w;
3229 static WIN32_FIND_DATAA dir_find_data_a;
3230 #define DIR_FIND_DATA_W 1
3231 #define DIR_FIND_DATA_A 2
3232 static int last_dir_find_data = -1;
3234 /* Support shares on a network resource as subdirectories of a read-only
3235 root directory. */
3236 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3237 static HANDLE open_unc_volume (const char *);
3238 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3239 static void close_unc_volume (HANDLE);
3241 DIR *
3242 sys_opendir (const char *filename)
3244 DIR *dirp;
3246 /* Opening is done by FindFirstFile. However, a read is inherent to
3247 this operation, so we defer the open until read time. */
3249 if (dir_find_handle != INVALID_HANDLE_VALUE)
3250 return NULL;
3251 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3252 return NULL;
3254 /* Note: We don't support traversal of UNC volumes via symlinks.
3255 Doing so would mean punishing 99.99% of use cases by resolving
3256 all the possible symlinks in FILENAME, recursively. */
3257 if (is_unc_volume (filename))
3259 wnet_enum_handle = open_unc_volume (filename);
3260 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3261 return NULL;
3264 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3265 return NULL;
3267 dirp->dd_fd = 0;
3268 dirp->dd_loc = 0;
3269 dirp->dd_size = 0;
3271 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3272 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3273 /* Note: We don't support symlinks to file names on FAT volumes.
3274 Doing so would mean punishing 99.99% of use cases by resolving
3275 all the possible symlinks in FILENAME, recursively. */
3276 dir_is_fat = is_fat_volume (filename, NULL);
3278 return dirp;
3281 void
3282 sys_closedir (DIR *dirp)
3284 /* If we have a find-handle open, close it. */
3285 if (dir_find_handle != INVALID_HANDLE_VALUE)
3287 FindClose (dir_find_handle);
3288 dir_find_handle = INVALID_HANDLE_VALUE;
3290 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3292 close_unc_volume (wnet_enum_handle);
3293 wnet_enum_handle = INVALID_HANDLE_VALUE;
3295 xfree ((char *) dirp);
3298 struct dirent *
3299 sys_readdir (DIR *dirp)
3301 int downcase = !NILP (Vw32_downcase_file_names);
3303 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3305 if (!read_unc_volume (wnet_enum_handle,
3306 dir_find_data_w.cFileName,
3307 dir_find_data_a.cFileName,
3308 MAX_PATH))
3309 return NULL;
3311 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3312 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3314 char filename[MAX_UTF8_PATH + 2];
3315 int ln;
3317 strcpy (filename, dir_pathname);
3318 ln = strlen (filename) - 1;
3319 if (!IS_DIRECTORY_SEP (filename[ln]))
3320 strcat (filename, "\\");
3321 strcat (filename, "*");
3323 /* Note: No need to resolve symlinks in FILENAME, because
3324 FindFirst opens the directory that is the target of a
3325 symlink. */
3326 if (w32_unicode_filenames)
3328 wchar_t fnw[MAX_PATH];
3330 filename_to_utf16 (filename, fnw);
3331 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3333 else
3335 char fna[MAX_PATH];
3337 filename_to_ansi (filename, fna);
3338 /* If FILENAME is not representable by the current ANSI
3339 codepage, we don't want FindFirstFileA to interpret the
3340 '?' characters as a wildcard. */
3341 if (_mbspbrk (fna, "?"))
3342 dir_find_handle = INVALID_HANDLE_VALUE;
3343 else
3344 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3347 if (dir_find_handle == INVALID_HANDLE_VALUE)
3348 return NULL;
3350 else if (w32_unicode_filenames)
3352 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3353 return NULL;
3355 else
3357 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3358 return NULL;
3361 /* Emacs never uses this value, so don't bother making it match
3362 value returned by stat(). */
3363 dir_static.d_ino = 1;
3365 if (w32_unicode_filenames)
3367 if (downcase || dir_is_fat)
3369 wchar_t tem[MAX_PATH];
3371 wcscpy (tem, dir_find_data_w.cFileName);
3372 CharLowerW (tem);
3373 filename_from_utf16 (tem, dir_static.d_name);
3375 else
3376 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3377 last_dir_find_data = DIR_FIND_DATA_W;
3379 else
3381 char tem[MAX_PATH];
3383 /* If the file name in cFileName[] includes `?' characters, it
3384 means the original file name used characters that cannot be
3385 represented by the current ANSI codepage. To avoid total
3386 lossage, retrieve the short 8+3 alias of the long file
3387 name. */
3388 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3390 strcpy (tem, dir_find_data_a.cAlternateFileName);
3391 /* 8+3 aliases are returned in all caps, which could break
3392 various alists that look at filenames' extensions. */
3393 downcase = 1;
3395 else if (downcase || dir_is_fat)
3396 strcpy (tem, dir_find_data_a.cFileName);
3397 else
3398 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3399 if (downcase || dir_is_fat)
3401 _mbslwr (tem);
3402 filename_from_ansi (tem, dir_static.d_name);
3404 last_dir_find_data = DIR_FIND_DATA_A;
3407 dir_static.d_namlen = strlen (dir_static.d_name);
3408 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3409 dir_static.d_namlen - dir_static.d_namlen % 4;
3411 return &dir_static;
3414 static HANDLE
3415 open_unc_volume (const char *path)
3417 const char *fn = map_w32_filename (path, NULL);
3418 DWORD result;
3419 HANDLE henum;
3421 if (w32_unicode_filenames)
3423 NETRESOURCEW nrw;
3424 wchar_t fnw[MAX_PATH];
3426 nrw.dwScope = RESOURCE_GLOBALNET;
3427 nrw.dwType = RESOURCETYPE_DISK;
3428 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3429 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3430 nrw.lpLocalName = NULL;
3431 filename_to_utf16 (fn, fnw);
3432 nrw.lpRemoteName = fnw;
3433 nrw.lpComment = NULL;
3434 nrw.lpProvider = NULL;
3436 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3437 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3439 else
3441 NETRESOURCEA nra;
3442 char fna[MAX_PATH];
3444 nra.dwScope = RESOURCE_GLOBALNET;
3445 nra.dwType = RESOURCETYPE_DISK;
3446 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3447 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3448 nra.lpLocalName = NULL;
3449 filename_to_ansi (fn, fna);
3450 nra.lpRemoteName = fna;
3451 nra.lpComment = NULL;
3452 nra.lpProvider = NULL;
3454 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3455 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3457 if (result == NO_ERROR)
3458 return henum;
3459 else
3460 return INVALID_HANDLE_VALUE;
3463 static void *
3464 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3466 DWORD count;
3467 int result;
3468 char *buffer;
3469 DWORD bufsize = 512;
3470 void *retval;
3472 count = 1;
3473 if (w32_unicode_filenames)
3475 wchar_t *ptrw;
3477 bufsize *= 2;
3478 buffer = alloca (bufsize);
3479 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3480 if (result != NO_ERROR)
3481 return NULL;
3482 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3483 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3484 ptrw += 2;
3485 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3486 ptrw++;
3487 wcsncpy (fname_w, ptrw, size);
3488 retval = fname_w;
3490 else
3492 int dbcs_p = max_filename_mbslen () > 1;
3493 char *ptra;
3495 buffer = alloca (bufsize);
3496 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3497 if (result != NO_ERROR)
3498 return NULL;
3499 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3500 ptra += 2;
3501 if (!dbcs_p)
3502 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3503 else
3505 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3506 ptra = CharNextExA (file_name_codepage, ptra, 0);
3508 ptra++;
3509 strncpy (fname_a, ptra, size);
3510 retval = fname_a;
3513 return retval;
3516 static void
3517 close_unc_volume (HANDLE henum)
3519 if (henum != INVALID_HANDLE_VALUE)
3520 WNetCloseEnum (henum);
3523 static DWORD
3524 unc_volume_file_attributes (const char *path)
3526 HANDLE henum;
3527 DWORD attrs;
3529 henum = open_unc_volume (path);
3530 if (henum == INVALID_HANDLE_VALUE)
3531 return -1;
3533 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3535 close_unc_volume (henum);
3537 return attrs;
3540 /* Ensure a network connection is authenticated. */
3541 static void
3542 logon_network_drive (const char *path)
3544 char share[MAX_UTF8_PATH];
3545 int n_slashes;
3546 char drive[4];
3547 UINT drvtype;
3548 char *p;
3549 DWORD val;
3551 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3552 drvtype = DRIVE_REMOTE;
3553 else if (path[0] == '\0' || path[1] != ':')
3554 drvtype = GetDriveType (NULL);
3555 else
3557 drive[0] = path[0];
3558 drive[1] = ':';
3559 drive[2] = '\\';
3560 drive[3] = '\0';
3561 drvtype = GetDriveType (drive);
3564 /* Only logon to networked drives. */
3565 if (drvtype != DRIVE_REMOTE)
3566 return;
3568 n_slashes = 2;
3569 strncpy (share, path, MAX_UTF8_PATH);
3570 /* Truncate to just server and share name. */
3571 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3573 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3575 *p = '\0';
3576 break;
3580 if (w32_unicode_filenames)
3582 NETRESOURCEW resourcew;
3583 wchar_t share_w[MAX_PATH];
3585 resourcew.dwScope = RESOURCE_GLOBALNET;
3586 resourcew.dwType = RESOURCETYPE_DISK;
3587 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3588 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3589 resourcew.lpLocalName = NULL;
3590 filename_to_utf16 (share, share_w);
3591 resourcew.lpRemoteName = share_w;
3592 resourcew.lpProvider = NULL;
3594 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3596 else
3598 NETRESOURCEA resourcea;
3599 char share_a[MAX_PATH];
3601 resourcea.dwScope = RESOURCE_GLOBALNET;
3602 resourcea.dwType = RESOURCETYPE_DISK;
3603 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3604 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3605 resourcea.lpLocalName = NULL;
3606 filename_to_ansi (share, share_a);
3607 resourcea.lpRemoteName = share_a;
3608 resourcea.lpProvider = NULL;
3610 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3613 switch (val)
3615 case NO_ERROR:
3616 case ERROR_ALREADY_ASSIGNED:
3617 break;
3618 case ERROR_ACCESS_DENIED:
3619 case ERROR_LOGON_FAILURE:
3620 errno = EACCES;
3621 break;
3622 case ERROR_BUSY:
3623 errno = EAGAIN;
3624 break;
3625 case ERROR_BAD_NET_NAME:
3626 case ERROR_NO_NET_OR_BAD_PATH:
3627 case ERROR_NO_NETWORK:
3628 case ERROR_CANCELLED:
3629 default:
3630 errno = ENOENT;
3631 break;
3635 /* Emulate faccessat(2). */
3637 faccessat (int dirfd, const char * path, int mode, int flags)
3639 DWORD attributes;
3641 if (dirfd != AT_FDCWD
3642 && !(IS_DIRECTORY_SEP (path[0])
3643 || IS_DEVICE_SEP (path[1])))
3645 errno = EBADF;
3646 return -1;
3649 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3650 newer versions blow up when passed D_OK. */
3651 path = map_w32_filename (path, NULL);
3652 /* If the last element of PATH is a symlink, we need to resolve it
3653 to get the attributes of its target file. Note: any symlinks in
3654 PATH elements other than the last one are transparently resolved
3655 by GetFileAttributes below. */
3656 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3657 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3658 path = chase_symlinks (path);
3660 if (w32_unicode_filenames)
3662 wchar_t path_w[MAX_PATH];
3664 filename_to_utf16 (path, path_w);
3665 attributes = GetFileAttributesW (path_w);
3667 else
3669 char path_a[MAX_PATH];
3671 filename_to_ansi (path, path_a);
3672 attributes = GetFileAttributesA (path_a);
3675 if (attributes == -1)
3677 DWORD w32err = GetLastError ();
3679 switch (w32err)
3681 case ERROR_INVALID_NAME:
3682 case ERROR_BAD_PATHNAME:
3683 if (is_unc_volume (path))
3685 attributes = unc_volume_file_attributes (path);
3686 if (attributes == -1)
3688 errno = EACCES;
3689 return -1;
3691 break;
3693 /* FALLTHROUGH */
3694 case ERROR_FILE_NOT_FOUND:
3695 case ERROR_BAD_NETPATH:
3696 errno = ENOENT;
3697 break;
3698 default:
3699 errno = EACCES;
3700 break;
3702 return -1;
3704 if ((mode & X_OK) != 0
3705 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3707 errno = EACCES;
3708 return -1;
3710 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3712 errno = EACCES;
3713 return -1;
3715 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3717 errno = EACCES;
3718 return -1;
3720 return 0;
3723 /* A version of 'access' to be used locally with file names in
3724 locale-specific encoding. Does not resolve symlinks and does not
3725 support file names on FAT12 and FAT16 volumes, but that's OK, since
3726 we only invoke this function for files inside the Emacs source or
3727 installation tree, on directories (so any symlinks should have the
3728 directory bit set), and on short file names such as "C:/.emacs". */
3729 static int
3730 sys_access (const char *fname, int mode)
3732 char fname_copy[MAX_PATH], *p;
3733 DWORD attributes;
3735 strcpy (fname_copy, fname);
3736 /* Do the equivalent of unixtodos_filename. */
3737 for (p = fname_copy; *p; p = CharNext (p))
3738 if (*p == '/')
3739 *p = '\\';
3741 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
3743 DWORD w32err = GetLastError ();
3745 switch (w32err)
3747 case ERROR_INVALID_NAME:
3748 case ERROR_BAD_PATHNAME:
3749 case ERROR_FILE_NOT_FOUND:
3750 case ERROR_BAD_NETPATH:
3751 errno = ENOENT;
3752 break;
3753 default:
3754 errno = EACCES;
3755 break;
3757 return -1;
3759 if ((mode & X_OK) != 0
3760 && !(is_exec (fname_copy)
3761 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3763 errno = EACCES;
3764 return -1;
3766 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3768 errno = EACCES;
3769 return -1;
3771 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3773 errno = EACCES;
3774 return -1;
3776 return 0;
3779 /* Shadow some MSVC runtime functions to map requests for long filenames
3780 to reasonable short names if necessary. This was originally added to
3781 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3782 long file names. */
3785 sys_chdir (const char * path)
3787 path = map_w32_filename (path, NULL);
3788 if (w32_unicode_filenames)
3790 wchar_t newdir_w[MAX_PATH];
3792 if (filename_to_utf16 (path, newdir_w) == 0)
3793 return _wchdir (newdir_w);
3794 return -1;
3796 else
3798 char newdir_a[MAX_PATH];
3800 if (filename_to_ansi (path, newdir_a) == 0)
3801 return _chdir (newdir_a);
3802 return -1;
3807 sys_chmod (const char * path, int mode)
3809 path = chase_symlinks (map_w32_filename (path, NULL));
3810 if (w32_unicode_filenames)
3812 wchar_t path_w[MAX_PATH];
3814 filename_to_utf16 (path, path_w);
3815 return _wchmod (path_w, mode);
3817 else
3819 char path_a[MAX_PATH];
3821 filename_to_ansi (path, path_a);
3822 return _chmod (path_a, mode);
3827 sys_creat (const char * path, int mode)
3829 path = map_w32_filename (path, NULL);
3830 if (w32_unicode_filenames)
3832 wchar_t path_w[MAX_PATH];
3834 filename_to_utf16 (path, path_w);
3835 return _wcreat (path_w, mode);
3837 else
3839 char path_a[MAX_PATH];
3841 filename_to_ansi (path, path_a);
3842 return _creat (path_a, mode);
3846 FILE *
3847 sys_fopen (const char * path, const char * mode)
3849 int fd;
3850 int oflag;
3851 const char * mode_save = mode;
3853 /* Force all file handles to be non-inheritable. This is necessary to
3854 ensure child processes don't unwittingly inherit handles that might
3855 prevent future file access. */
3857 if (mode[0] == 'r')
3858 oflag = O_RDONLY;
3859 else if (mode[0] == 'w' || mode[0] == 'a')
3860 oflag = O_WRONLY | O_CREAT | O_TRUNC;
3861 else
3862 return NULL;
3864 /* Only do simplistic option parsing. */
3865 while (*++mode)
3866 if (mode[0] == '+')
3868 oflag &= ~(O_RDONLY | O_WRONLY);
3869 oflag |= O_RDWR;
3871 else if (mode[0] == 'b')
3873 oflag &= ~O_TEXT;
3874 oflag |= O_BINARY;
3876 else if (mode[0] == 't')
3878 oflag &= ~O_BINARY;
3879 oflag |= O_TEXT;
3881 else break;
3883 path = map_w32_filename (path, NULL);
3884 if (w32_unicode_filenames)
3886 wchar_t path_w[MAX_PATH];
3888 filename_to_utf16 (path, path_w);
3889 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
3891 else
3893 char path_a[MAX_PATH];
3895 filename_to_ansi (path, path_a);
3896 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
3898 if (fd < 0)
3899 return NULL;
3901 return _fdopen (fd, mode_save);
3904 /* This only works on NTFS volumes, but is useful to have. */
3906 sys_link (const char * old, const char * new)
3908 HANDLE fileh;
3909 int result = -1;
3910 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
3911 wchar_t oldname_w[MAX_PATH];
3912 char oldname_a[MAX_PATH];
3914 if (old == NULL || new == NULL)
3916 errno = ENOENT;
3917 return -1;
3920 strcpy (oldname, map_w32_filename (old, NULL));
3921 strcpy (newname, map_w32_filename (new, NULL));
3923 if (w32_unicode_filenames)
3925 filename_to_utf16 (oldname, oldname_w);
3926 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
3927 FILE_FLAG_BACKUP_SEMANTICS, NULL);
3929 else
3931 filename_to_ansi (oldname, oldname_a);
3932 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
3933 FILE_FLAG_BACKUP_SEMANTICS, NULL);
3935 if (fileh != INVALID_HANDLE_VALUE)
3937 int wlen;
3939 /* Confusingly, the "alternate" stream name field does not apply
3940 when restoring a hard link, and instead contains the actual
3941 stream data for the link (ie. the name of the link to create).
3942 The WIN32_STREAM_ID structure before the cStreamName field is
3943 the stream header, which is then immediately followed by the
3944 stream data. */
3946 struct {
3947 WIN32_STREAM_ID wid;
3948 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
3949 } data;
3951 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
3952 indicates that flag is unsupported for CP_UTF8, and OTOH says
3953 it is the default anyway. */
3954 wlen = MultiByteToWideChar (CP_UTF8, 0, newname, -1,
3955 data.wid.cStreamName, MAX_PATH);
3956 if (wlen > 0)
3958 LPVOID context = NULL;
3959 DWORD wbytes = 0;
3961 data.wid.dwStreamId = BACKUP_LINK;
3962 data.wid.dwStreamAttributes = 0;
3963 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
3964 data.wid.Size.HighPart = 0;
3965 data.wid.dwStreamNameSize = 0;
3967 if (BackupWrite (fileh, (LPBYTE)&data,
3968 offsetof (WIN32_STREAM_ID, cStreamName)
3969 + data.wid.Size.LowPart,
3970 &wbytes, FALSE, FALSE, &context)
3971 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
3973 /* succeeded */
3974 result = 0;
3976 else
3978 DWORD err = GetLastError ();
3979 DWORD attributes;
3981 switch (err)
3983 case ERROR_ACCESS_DENIED:
3984 /* This is what happens when OLDNAME is a directory,
3985 since Windows doesn't support hard links to
3986 directories. Posix says to set errno to EPERM in
3987 that case. */
3988 if (w32_unicode_filenames)
3989 attributes = GetFileAttributesW (oldname_w);
3990 else
3991 attributes = GetFileAttributesA (oldname_a);
3992 if (attributes != -1
3993 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
3994 errno = EPERM;
3995 else if (attributes == -1
3996 && is_unc_volume (oldname)
3997 && unc_volume_file_attributes (oldname) != -1)
3998 errno = EPERM;
3999 else
4000 errno = EACCES;
4001 break;
4002 case ERROR_TOO_MANY_LINKS:
4003 errno = EMLINK;
4004 break;
4005 case ERROR_NOT_SAME_DEVICE:
4006 errno = EXDEV;
4007 break;
4008 default:
4009 errno = EINVAL;
4010 break;
4015 CloseHandle (fileh);
4017 else
4018 errno = ENOENT;
4020 return result;
4024 sys_mkdir (const char * path)
4026 path = map_w32_filename (path, NULL);
4028 if (w32_unicode_filenames)
4030 wchar_t path_w[MAX_PATH];
4032 filename_to_utf16 (path, path_w);
4033 return _wmkdir (path_w);
4035 else
4037 char path_a[MAX_PATH];
4039 filename_to_ansi (path, path_a);
4040 return _mkdir (path_a);
4045 sys_open (const char * path, int oflag, int mode)
4047 const char* mpath = map_w32_filename (path, NULL);
4048 int res = -1;
4050 if (w32_unicode_filenames)
4052 wchar_t mpath_w[MAX_PATH];
4054 filename_to_utf16 (mpath, mpath_w);
4055 /* If possible, try to open file without _O_CREAT, to be able to
4056 write to existing hidden and system files. Force all file
4057 handles to be non-inheritable. */
4058 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4059 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4060 if (res < 0)
4061 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4063 else
4065 char mpath_a[MAX_PATH];
4067 filename_to_ansi (mpath, mpath_a);
4068 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4069 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4070 if (res < 0)
4071 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4074 return res;
4077 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
4078 when using mktemp.
4080 Standard algorithm for generating a temporary file name seems to be
4081 use pid or tid with a letter on the front (in place of the 6 X's)
4082 and cycle through the letters to find a unique name. We extend
4083 that to allow any reasonable character as the first of the 6 X's,
4084 so that the number of simultaneously used temporary files will be
4085 greater. */
4088 mkostemp (char * template, int flags)
4090 char * p;
4091 int i, fd = -1;
4092 unsigned uid = GetCurrentThreadId ();
4093 int save_errno = errno;
4094 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
4096 errno = EINVAL;
4097 if (template == NULL)
4098 return -1;
4100 p = template + strlen (template);
4101 i = 5;
4102 /* replace up to the last 5 X's with uid in decimal */
4103 while (--p >= template && p[0] == 'X' && --i >= 0)
4105 p[0] = '0' + uid % 10;
4106 uid /= 10;
4109 if (i < 0 && p[0] == 'X')
4111 i = 0;
4114 p[0] = first_char[i];
4115 if ((fd = sys_open (template,
4116 flags | _O_CREAT | _O_EXCL | _O_RDWR,
4117 S_IRUSR | S_IWUSR)) >= 0
4118 || errno != EEXIST)
4120 if (fd >= 0)
4121 errno = save_errno;
4122 return fd;
4125 while (++i < sizeof (first_char));
4128 /* Template is badly formed or else we can't generate a unique name. */
4129 return -1;
4133 fchmod (int fd, mode_t mode)
4135 return 0;
4139 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4141 BOOL result;
4142 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4143 int newname_dev;
4144 int oldname_dev;
4145 bool have_temp_a = false;
4147 /* MoveFile on Windows 95 doesn't correctly change the short file name
4148 alias in a number of circumstances (it is not easy to predict when
4149 just by looking at oldname and newname, unfortunately). In these
4150 cases, renaming through a temporary name avoids the problem.
4152 A second problem on Windows 95 is that renaming through a temp name when
4153 newname is uppercase fails (the final long name ends up in
4154 lowercase, although the short alias might be uppercase) UNLESS the
4155 long temp name is not 8.3.
4157 So, on Windows 95 we always rename through a temp name, and we make sure
4158 the temp name has a long extension to ensure correct renaming. */
4160 strcpy (temp, map_w32_filename (oldname, NULL));
4162 /* volume_info is set indirectly by map_w32_filename. */
4163 oldname_dev = volume_info.serialnum;
4165 if (os_subtype == OS_9X)
4167 char * o;
4168 char * p;
4169 int i = 0;
4170 char oldname_a[MAX_PATH];
4172 oldname = map_w32_filename (oldname, NULL);
4173 filename_to_ansi (oldname, oldname_a);
4174 filename_to_ansi (temp, temp_a);
4175 if ((o = strrchr (oldname_a, '\\')))
4176 o++;
4177 else
4178 o = (char *) oldname_a;
4180 if ((p = strrchr (temp_a, '\\')))
4181 p++;
4182 else
4183 p = temp_a;
4187 /* Force temp name to require a manufactured 8.3 alias - this
4188 seems to make the second rename work properly. */
4189 sprintf (p, "_.%s.%u", o, i);
4190 i++;
4191 result = rename (oldname_a, temp_a);
4193 /* This loop must surely terminate! */
4194 while (result < 0 && errno == EEXIST);
4195 if (result < 0)
4196 return -1;
4197 have_temp_a = true;
4200 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4201 (at least if it is a file; don't do this for directories).
4203 Since we mustn't do this if we are just changing the case of the
4204 file name (we would end up deleting the file we are trying to
4205 rename!), we let rename detect if the destination file already
4206 exists - that way we avoid the possible pitfalls of trying to
4207 determine ourselves whether two names really refer to the same
4208 file, which is not always possible in the general case. (Consider
4209 all the permutations of shared or subst'd drives, etc.) */
4211 newname = map_w32_filename (newname, NULL);
4213 /* volume_info is set indirectly by map_w32_filename. */
4214 newname_dev = volume_info.serialnum;
4216 if (w32_unicode_filenames)
4218 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4220 filename_to_utf16 (temp, temp_w);
4221 filename_to_utf16 (newname, newname_w);
4222 result = _wrename (temp_w, newname_w);
4223 if (result < 0 && force)
4225 DWORD w32err = GetLastError ();
4227 if (errno == EACCES
4228 && newname_dev != oldname_dev)
4230 /* The implementation of `rename' on Windows does not return
4231 errno = EXDEV when you are moving a directory to a
4232 different storage device (ex. logical disk). It returns
4233 EACCES instead. So here we handle such situations and
4234 return EXDEV. */
4235 DWORD attributes;
4237 if ((attributes = GetFileAttributesW (temp_w)) != -1
4238 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4239 errno = EXDEV;
4241 else if (errno == EEXIST)
4243 if (_wchmod (newname_w, 0666) != 0)
4244 return result;
4245 if (_wunlink (newname_w) != 0)
4246 return result;
4247 result = _wrename (temp_w, newname_w);
4249 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4250 && is_symlink (temp))
4252 /* This is Windows prohibiting the user from creating a
4253 symlink in another place, since that requires
4254 privileges. */
4255 errno = EPERM;
4259 else
4261 char newname_a[MAX_PATH];
4263 if (!have_temp_a)
4264 filename_to_ansi (temp, temp_a);
4265 filename_to_ansi (newname, newname_a);
4266 result = rename (temp_a, newname_a);
4267 if (result < 0 && force)
4269 DWORD w32err = GetLastError ();
4271 if (errno == EACCES
4272 && newname_dev != oldname_dev)
4274 DWORD attributes;
4276 if ((attributes = GetFileAttributesA (temp_a)) != -1
4277 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4278 errno = EXDEV;
4280 else if (errno == EEXIST)
4282 if (_chmod (newname_a, 0666) != 0)
4283 return result;
4284 if (_unlink (newname_a) != 0)
4285 return result;
4286 result = rename (temp_a, newname_a);
4288 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4289 && is_symlink (temp))
4290 errno = EPERM;
4294 return result;
4298 sys_rename (char const *old, char const *new)
4300 return sys_rename_replace (old, new, TRUE);
4304 sys_rmdir (const char * path)
4306 path = map_w32_filename (path, NULL);
4308 if (w32_unicode_filenames)
4310 wchar_t path_w[MAX_PATH];
4312 filename_to_utf16 (path, path_w);
4313 return _wrmdir (path_w);
4315 else
4317 char path_a[MAX_PATH];
4319 filename_to_ansi (path, path_a);
4320 return _rmdir (path_a);
4325 sys_unlink (const char * path)
4327 path = map_w32_filename (path, NULL);
4329 if (w32_unicode_filenames)
4331 wchar_t path_w[MAX_PATH];
4333 filename_to_utf16 (path, path_w);
4334 /* On Unix, unlink works without write permission. */
4335 _wchmod (path_w, 0666);
4336 return _wunlink (path_w);
4338 else
4340 char path_a[MAX_PATH];
4342 filename_to_ansi (path, path_a);
4343 _chmod (path_a, 0666);
4344 return _unlink (path_a);
4348 static FILETIME utc_base_ft;
4349 static ULONGLONG utc_base; /* In 100ns units */
4350 static int init = 0;
4352 #define FILETIME_TO_U64(result, ft) \
4353 do { \
4354 ULARGE_INTEGER uiTemp; \
4355 uiTemp.LowPart = (ft).dwLowDateTime; \
4356 uiTemp.HighPart = (ft).dwHighDateTime; \
4357 result = uiTemp.QuadPart; \
4358 } while (0)
4360 static void
4361 initialize_utc_base (void)
4363 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4364 SYSTEMTIME st;
4366 st.wYear = 1970;
4367 st.wMonth = 1;
4368 st.wDay = 1;
4369 st.wHour = 0;
4370 st.wMinute = 0;
4371 st.wSecond = 0;
4372 st.wMilliseconds = 0;
4374 SystemTimeToFileTime (&st, &utc_base_ft);
4375 FILETIME_TO_U64 (utc_base, utc_base_ft);
4378 static time_t
4379 convert_time (FILETIME ft)
4381 ULONGLONG tmp;
4383 if (!init)
4385 initialize_utc_base ();
4386 init = 1;
4389 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4390 return 0;
4392 FILETIME_TO_U64 (tmp, ft);
4393 return (time_t) ((tmp - utc_base) / 10000000L);
4396 static void
4397 convert_from_time_t (time_t time, FILETIME * pft)
4399 ULARGE_INTEGER tmp;
4401 if (!init)
4403 initialize_utc_base ();
4404 init = 1;
4407 /* time in 100ns units since 1-Jan-1601 */
4408 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4409 pft->dwHighDateTime = tmp.HighPart;
4410 pft->dwLowDateTime = tmp.LowPart;
4413 static PSECURITY_DESCRIPTOR
4414 get_file_security_desc_by_handle (HANDLE h)
4416 PSECURITY_DESCRIPTOR psd = NULL;
4417 DWORD err;
4418 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4419 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4421 err = get_security_info (h, SE_FILE_OBJECT, si,
4422 NULL, NULL, NULL, NULL, &psd);
4423 if (err != ERROR_SUCCESS)
4424 return NULL;
4426 return psd;
4429 static PSECURITY_DESCRIPTOR
4430 get_file_security_desc_by_name (const char *fname)
4432 PSECURITY_DESCRIPTOR psd = NULL;
4433 DWORD sd_len, err;
4434 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4435 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4437 if (!get_file_security (fname, si, psd, 0, &sd_len))
4439 err = GetLastError ();
4440 if (err != ERROR_INSUFFICIENT_BUFFER)
4441 return NULL;
4444 psd = xmalloc (sd_len);
4445 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4447 xfree (psd);
4448 return NULL;
4451 return psd;
4454 static DWORD
4455 get_rid (PSID sid)
4457 unsigned n_subauthorities;
4459 /* Use the last sub-authority value of the RID, the relative
4460 portion of the SID, as user/group ID. */
4461 n_subauthorities = *get_sid_sub_authority_count (sid);
4462 if (n_subauthorities < 1)
4463 return 0; /* the "World" RID */
4464 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4467 /* Caching SID and account values for faster lokup. */
4469 struct w32_id {
4470 unsigned rid;
4471 struct w32_id *next;
4472 char name[GNLEN+1];
4473 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4476 static struct w32_id *w32_idlist;
4478 static int
4479 w32_cached_id (PSID sid, unsigned *id, char *name)
4481 struct w32_id *tail, *found;
4483 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4485 if (equal_sid ((PSID)tail->sid, sid))
4487 found = tail;
4488 break;
4491 if (found)
4493 *id = found->rid;
4494 strcpy (name, found->name);
4495 return 1;
4497 else
4498 return 0;
4501 static void
4502 w32_add_to_cache (PSID sid, unsigned id, char *name)
4504 DWORD sid_len;
4505 struct w32_id *new_entry;
4507 /* We don't want to leave behind stale cache from when Emacs was
4508 dumped. */
4509 if (initialized)
4511 sid_len = get_length_sid (sid);
4512 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4513 if (new_entry)
4515 new_entry->rid = id;
4516 strcpy (new_entry->name, name);
4517 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4518 new_entry->next = w32_idlist;
4519 w32_idlist = new_entry;
4524 #define UID 1
4525 #define GID 2
4527 static int
4528 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4530 PSID sid = NULL;
4531 BOOL dflt;
4532 SID_NAME_USE ignore;
4533 char name[UNLEN+1];
4534 DWORD name_len = sizeof (name);
4535 char domain[1024];
4536 DWORD domain_len = sizeof (domain);
4537 int use_dflt = 0;
4538 int result;
4540 if (what == UID)
4541 result = get_security_descriptor_owner (psd, &sid, &dflt);
4542 else if (what == GID)
4543 result = get_security_descriptor_group (psd, &sid, &dflt);
4544 else
4545 result = 0;
4547 if (!result || !is_valid_sid (sid))
4548 use_dflt = 1;
4549 else if (!w32_cached_id (sid, id, nm))
4551 if (!lookup_account_sid (NULL, sid, name, &name_len,
4552 domain, &domain_len, &ignore)
4553 || name_len > UNLEN+1)
4554 use_dflt = 1;
4555 else
4557 *id = get_rid (sid);
4558 strcpy (nm, name);
4559 w32_add_to_cache (sid, *id, name);
4562 return use_dflt;
4565 static void
4566 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4568 int dflt_usr = 0, dflt_grp = 0;
4570 if (!psd)
4572 dflt_usr = 1;
4573 dflt_grp = 1;
4575 else
4577 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4578 dflt_usr = 1;
4579 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4580 dflt_grp = 1;
4582 /* Consider files to belong to current user/group, if we cannot get
4583 more accurate information. */
4584 if (dflt_usr)
4586 st->st_uid = dflt_passwd.pw_uid;
4587 strcpy (st->st_uname, dflt_passwd.pw_name);
4589 if (dflt_grp)
4591 st->st_gid = dflt_passwd.pw_gid;
4592 strcpy (st->st_gname, dflt_group.gr_name);
4596 /* Return non-zero if NAME is a potentially slow filesystem. */
4598 is_slow_fs (const char *name)
4600 char drive_root[4];
4601 UINT devtype;
4603 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4604 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4605 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4606 devtype = GetDriveType (NULL); /* use root of current drive */
4607 else
4609 /* GetDriveType needs the root directory of the drive. */
4610 strncpy (drive_root, name, 2);
4611 drive_root[2] = '\\';
4612 drive_root[3] = '\0';
4613 devtype = GetDriveType (drive_root);
4615 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4618 /* If this is non-zero, the caller wants accurate information about
4619 file's owner and group, which could be expensive to get. dired.c
4620 uses this flag when needed for the job at hand. */
4621 int w32_stat_get_owner_group;
4623 /* MSVC stat function can't cope with UNC names and has other bugs, so
4624 replace it with our own. This also allows us to calculate consistent
4625 inode values and owner/group without hacks in the main Emacs code,
4626 and support file names encoded in UTF-8. */
4628 static int
4629 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4631 char *name, *save_name, *r;
4632 WIN32_FIND_DATAW wfd_w;
4633 WIN32_FIND_DATAA wfd_a;
4634 HANDLE fh;
4635 unsigned __int64 fake_inode = 0;
4636 int permission;
4637 int len;
4638 int rootdir = FALSE;
4639 PSECURITY_DESCRIPTOR psd = NULL;
4640 int is_a_symlink = 0;
4641 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4642 DWORD access_rights = 0;
4643 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4644 FILETIME ctime, atime, wtime;
4645 wchar_t name_w[MAX_PATH];
4646 char name_a[MAX_PATH];
4648 if (path == NULL || buf == NULL)
4650 errno = EFAULT;
4651 return -1;
4654 save_name = name = (char *) map_w32_filename (path, &path);
4655 /* Must be valid filename, no wild cards or other invalid
4656 characters. */
4657 if (strpbrk (name, "*?|<>\""))
4659 errno = ENOENT;
4660 return -1;
4663 /* Remove trailing directory separator, unless name is the root
4664 directory of a drive or UNC volume in which case ensure there
4665 is a trailing separator. */
4666 len = strlen (name);
4667 name = strcpy (alloca (len + 2), name);
4669 /* Avoid a somewhat costly call to is_symlink if the filesystem
4670 doesn't support symlinks. */
4671 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4672 is_a_symlink = is_symlink (name);
4674 /* Plan A: Open the file and get all the necessary information via
4675 the resulting handle. This solves several issues in one blow:
4677 . retrieves attributes for the target of a symlink, if needed
4678 . gets attributes of root directories and symlinks pointing to
4679 root directories, thus avoiding the need for special-casing
4680 these and detecting them by examining the file-name format
4681 . retrieves more accurate attributes (e.g., non-zero size for
4682 some directories, esp. directories that are junction points)
4683 . correctly resolves "c:/..", "/.." and similar file names
4684 . avoids run-time penalties for 99% of use cases
4686 Plan A is always tried first, unless the user asked not to (but
4687 if the file is a symlink and we need to follow links, we try Plan
4688 A even if the user asked not to).
4690 If Plan A fails, we go to Plan B (below), where various
4691 potentially expensive techniques must be used to handle "special"
4692 files such as UNC volumes etc. */
4693 if (!(NILP (Vw32_get_true_file_attributes)
4694 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
4695 /* Following symlinks requires getting the info by handle. */
4696 || (is_a_symlink && follow_symlinks))
4698 BY_HANDLE_FILE_INFORMATION info;
4700 if (is_a_symlink && !follow_symlinks)
4701 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
4702 /* READ_CONTROL access rights are required to get security info
4703 by handle. But if the OS doesn't support security in the
4704 first place, we don't need to try. */
4705 if (is_windows_9x () != TRUE)
4706 access_rights |= READ_CONTROL;
4708 if (w32_unicode_filenames)
4710 filename_to_utf16 (name, name_w);
4711 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
4712 file_flags, NULL);
4713 /* If CreateFile fails with READ_CONTROL, try again with
4714 zero as access rights. */
4715 if (fh == INVALID_HANDLE_VALUE && access_rights)
4716 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
4717 file_flags, NULL);
4719 else
4721 filename_to_ansi (name, name_a);
4722 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
4723 file_flags, NULL);
4724 if (fh == INVALID_HANDLE_VALUE && access_rights)
4725 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
4726 file_flags, NULL);
4728 if (fh == INVALID_HANDLE_VALUE)
4729 goto no_true_file_attributes;
4731 /* This is more accurate in terms of getting the correct number
4732 of links, but is quite slow (it is noticeable when Emacs is
4733 making a list of file name completions). */
4734 if (GetFileInformationByHandle (fh, &info))
4736 nlinks = info.nNumberOfLinks;
4737 /* Might as well use file index to fake inode values, but this
4738 is not guaranteed to be unique unless we keep a handle open
4739 all the time (even then there are situations where it is
4740 not unique). Reputedly, there are at most 48 bits of info
4741 (on NTFS, presumably less on FAT). */
4742 fake_inode = info.nFileIndexHigh;
4743 fake_inode <<= 32;
4744 fake_inode += info.nFileIndexLow;
4745 serialnum = info.dwVolumeSerialNumber;
4746 fs_high = info.nFileSizeHigh;
4747 fs_low = info.nFileSizeLow;
4748 ctime = info.ftCreationTime;
4749 atime = info.ftLastAccessTime;
4750 wtime = info.ftLastWriteTime;
4751 fattrs = info.dwFileAttributes;
4753 else
4755 /* We don't go to Plan B here, because it's not clear that
4756 it's a good idea. The only known use case where
4757 CreateFile succeeds, but GetFileInformationByHandle fails
4758 (with ERROR_INVALID_FUNCTION) is for character devices
4759 such as NUL, PRN, etc. For these, switching to Plan B is
4760 a net loss, because we lose the character device
4761 attribute returned by GetFileType below (FindFirstFile
4762 doesn't set that bit in the attributes), and the other
4763 fields don't make sense for character devices anyway.
4764 Emacs doesn't really care for non-file entities in the
4765 context of l?stat, so neither do we. */
4767 /* w32err is assigned so one could put a breakpoint here and
4768 examine its value, when GetFileInformationByHandle
4769 fails. */
4770 DWORD w32err = GetLastError ();
4772 switch (w32err)
4774 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
4775 errno = ENOENT;
4776 return -1;
4780 /* Test for a symlink before testing for a directory, since
4781 symlinks to directories have the directory bit set, but we
4782 don't want them to appear as directories. */
4783 if (is_a_symlink && !follow_symlinks)
4784 buf->st_mode = S_IFLNK;
4785 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4786 buf->st_mode = S_IFDIR;
4787 else
4789 DWORD ftype = GetFileType (fh);
4791 switch (ftype)
4793 case FILE_TYPE_DISK:
4794 buf->st_mode = S_IFREG;
4795 break;
4796 case FILE_TYPE_PIPE:
4797 buf->st_mode = S_IFIFO;
4798 break;
4799 case FILE_TYPE_CHAR:
4800 case FILE_TYPE_UNKNOWN:
4801 default:
4802 buf->st_mode = S_IFCHR;
4805 /* We produce the fallback owner and group data, based on the
4806 current user that runs Emacs, in the following cases:
4808 . caller didn't request owner and group info
4809 . this is Windows 9X
4810 . getting security by handle failed, and we need to produce
4811 information for the target of a symlink (this is better
4812 than producing a potentially misleading info about the
4813 symlink itself)
4815 If getting security by handle fails, and we don't need to
4816 resolve symlinks, we try getting security by name. */
4817 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4818 get_file_owner_and_group (NULL, buf);
4819 else
4821 psd = get_file_security_desc_by_handle (fh);
4822 if (psd)
4824 get_file_owner_and_group (psd, buf);
4825 LocalFree (psd);
4827 else if (!(is_a_symlink && follow_symlinks))
4829 psd = get_file_security_desc_by_name (name);
4830 get_file_owner_and_group (psd, buf);
4831 xfree (psd);
4833 else
4834 get_file_owner_and_group (NULL, buf);
4836 CloseHandle (fh);
4838 else
4840 no_true_file_attributes:
4841 /* Plan B: Either getting a handle on the file failed, or the
4842 caller explicitly asked us to not bother making this
4843 information more accurate.
4845 Implementation note: In Plan B, we never bother to resolve
4846 symlinks, even if we got here because we tried Plan A and
4847 failed. That's because, even if the caller asked for extra
4848 precision by setting Vw32_get_true_file_attributes to t,
4849 resolving symlinks requires acquiring a file handle to the
4850 symlink, which we already know will fail. And if the user
4851 did not ask for extra precision, resolving symlinks will fly
4852 in the face of that request, since the user then wants the
4853 lightweight version of the code. */
4854 rootdir = (path >= save_name + len - 1
4855 && (IS_DIRECTORY_SEP (*path) || *path == 0));
4857 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4858 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
4859 if (IS_DIRECTORY_SEP (r[0])
4860 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
4861 r[1] = r[2] = '\0';
4863 /* Note: If NAME is a symlink to the root of a UNC volume
4864 (i.e. "\\SERVER"), we will not detect that here, and we will
4865 return data about the symlink as result of FindFirst below.
4866 This is unfortunate, but that marginal use case does not
4867 justify a call to chase_symlinks which would impose a penalty
4868 on all the other use cases. (We get here for symlinks to
4869 roots of UNC volumes because CreateFile above fails for them,
4870 unlike with symlinks to root directories X:\ of drives.) */
4871 if (is_unc_volume (name))
4873 fattrs = unc_volume_file_attributes (name);
4874 if (fattrs == -1)
4875 return -1;
4877 ctime = atime = wtime = utc_base_ft;
4879 else if (rootdir)
4881 if (!IS_DIRECTORY_SEP (name[len-1]))
4882 strcat (name, "\\");
4883 if (GetDriveType (name) < 2)
4885 errno = ENOENT;
4886 return -1;
4889 fattrs = FILE_ATTRIBUTE_DIRECTORY;
4890 ctime = atime = wtime = utc_base_ft;
4892 else
4894 int have_wfd = -1;
4896 if (IS_DIRECTORY_SEP (name[len-1]))
4897 name[len - 1] = 0;
4899 /* (This is hacky, but helps when doing file completions on
4900 network drives.) Optimize by using information available from
4901 active readdir if possible. */
4902 len = strlen (dir_pathname);
4903 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
4904 len--;
4905 if (dir_find_handle != INVALID_HANDLE_VALUE
4906 && last_dir_find_data != -1
4907 && !(is_a_symlink && follow_symlinks)
4908 /* The 2 file-name comparisons below support only ASCII
4909 characters, and will lose (compare not equal) when
4910 the file names include non-ASCII characters that are
4911 the same but for the case. However, doing this
4912 properly involves: (a) converting both file names to
4913 UTF-16, (b) lower-casing both names using CharLowerW,
4914 and (c) comparing the results; this would be quite a
4915 bit slower, whereas Plan B is for users who want
4916 lightweight albeit inaccurate version of 'stat'. */
4917 && c_strncasecmp (save_name, dir_pathname, len) == 0
4918 && IS_DIRECTORY_SEP (name[len])
4919 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
4921 have_wfd = last_dir_find_data;
4922 /* This was the last entry returned by readdir. */
4923 if (last_dir_find_data == DIR_FIND_DATA_W)
4924 wfd_w = dir_find_data_w;
4925 else
4926 wfd_a = dir_find_data_a;
4928 else
4930 logon_network_drive (name);
4932 if (w32_unicode_filenames)
4934 filename_to_utf16 (name, name_w);
4935 fh = FindFirstFileW (name_w, &wfd_w);
4936 have_wfd = DIR_FIND_DATA_W;
4938 else
4940 filename_to_ansi (name, name_a);
4941 /* If NAME includes characters not representable by
4942 the current ANSI codepage, filename_to_ansi
4943 usually replaces them with a '?'. We don't want
4944 to let FindFirstFileA interpret those as wildcards,
4945 and "succeed", returning us data from some random
4946 file in the same directory. */
4947 if (_mbspbrk (name_a, "?"))
4948 fh = INVALID_HANDLE_VALUE;
4949 else
4950 fh = FindFirstFileA (name_a, &wfd_a);
4951 have_wfd = DIR_FIND_DATA_A;
4953 if (fh == INVALID_HANDLE_VALUE)
4955 errno = ENOENT;
4956 return -1;
4958 FindClose (fh);
4960 /* Note: if NAME is a symlink, the information we get from
4961 FindFirstFile is for the symlink, not its target. */
4962 if (have_wfd == DIR_FIND_DATA_W)
4964 fattrs = wfd_w.dwFileAttributes;
4965 ctime = wfd_w.ftCreationTime;
4966 atime = wfd_w.ftLastAccessTime;
4967 wtime = wfd_w.ftLastWriteTime;
4968 fs_high = wfd_w.nFileSizeHigh;
4969 fs_low = wfd_w.nFileSizeLow;
4971 else
4973 fattrs = wfd_a.dwFileAttributes;
4974 ctime = wfd_a.ftCreationTime;
4975 atime = wfd_a.ftLastAccessTime;
4976 wtime = wfd_a.ftLastWriteTime;
4977 fs_high = wfd_a.nFileSizeHigh;
4978 fs_low = wfd_a.nFileSizeLow;
4980 fake_inode = 0;
4981 nlinks = 1;
4982 serialnum = volume_info.serialnum;
4984 if (is_a_symlink && !follow_symlinks)
4985 buf->st_mode = S_IFLNK;
4986 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4987 buf->st_mode = S_IFDIR;
4988 else
4989 buf->st_mode = S_IFREG;
4991 get_file_owner_and_group (NULL, buf);
4994 buf->st_ino = fake_inode;
4996 buf->st_dev = serialnum;
4997 buf->st_rdev = serialnum;
4999 buf->st_size = fs_high;
5000 buf->st_size <<= 32;
5001 buf->st_size += fs_low;
5002 buf->st_nlink = nlinks;
5004 /* Convert timestamps to Unix format. */
5005 buf->st_mtime = convert_time (wtime);
5006 buf->st_atime = convert_time (atime);
5007 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5008 buf->st_ctime = convert_time (ctime);
5009 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5011 /* determine rwx permissions */
5012 if (is_a_symlink && !follow_symlinks)
5013 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5014 else
5016 if (fattrs & FILE_ATTRIBUTE_READONLY)
5017 permission = S_IREAD;
5018 else
5019 permission = S_IREAD | S_IWRITE;
5021 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5022 permission |= S_IEXEC;
5023 else if (is_exec (name))
5024 permission |= S_IEXEC;
5027 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5029 return 0;
5033 stat (const char * path, struct stat * buf)
5035 return stat_worker (path, buf, 1);
5039 lstat (const char * path, struct stat * buf)
5041 return stat_worker (path, buf, 0);
5045 fstatat (int fd, char const *name, struct stat *st, int flags)
5047 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5048 This is good enough for the current usage in Emacs, but is fragile.
5050 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5051 Gnulib does this and can serve as a model. */
5052 char fullname[MAX_UTF8_PATH];
5054 if (fd != AT_FDCWD)
5056 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5057 < 0)
5059 errno = ENAMETOOLONG;
5060 return -1;
5062 name = fullname;
5065 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5068 /* Provide fstat and utime as well as stat for consistent handling of
5069 file timestamps. */
5071 fstat (int desc, struct stat * buf)
5073 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5074 BY_HANDLE_FILE_INFORMATION info;
5075 unsigned __int64 fake_inode;
5076 int permission;
5078 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5080 case FILE_TYPE_DISK:
5081 buf->st_mode = S_IFREG;
5082 if (!GetFileInformationByHandle (fh, &info))
5084 errno = EACCES;
5085 return -1;
5087 break;
5088 case FILE_TYPE_PIPE:
5089 buf->st_mode = S_IFIFO;
5090 goto non_disk;
5091 case FILE_TYPE_CHAR:
5092 case FILE_TYPE_UNKNOWN:
5093 default:
5094 buf->st_mode = S_IFCHR;
5095 non_disk:
5096 memset (&info, 0, sizeof (info));
5097 info.dwFileAttributes = 0;
5098 info.ftCreationTime = utc_base_ft;
5099 info.ftLastAccessTime = utc_base_ft;
5100 info.ftLastWriteTime = utc_base_ft;
5103 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5104 buf->st_mode = S_IFDIR;
5106 buf->st_nlink = info.nNumberOfLinks;
5107 /* Might as well use file index to fake inode values, but this
5108 is not guaranteed to be unique unless we keep a handle open
5109 all the time (even then there are situations where it is
5110 not unique). Reputedly, there are at most 48 bits of info
5111 (on NTFS, presumably less on FAT). */
5112 fake_inode = info.nFileIndexHigh;
5113 fake_inode <<= 32;
5114 fake_inode += info.nFileIndexLow;
5116 /* MSVC defines _ino_t to be short; other libc's might not. */
5117 if (sizeof (buf->st_ino) == 2)
5118 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5119 else
5120 buf->st_ino = fake_inode;
5122 /* If the caller so requested, get the true file owner and group.
5123 Otherwise, consider the file to belong to the current user. */
5124 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5125 get_file_owner_and_group (NULL, buf);
5126 else
5128 PSECURITY_DESCRIPTOR psd = NULL;
5130 psd = get_file_security_desc_by_handle (fh);
5131 if (psd)
5133 get_file_owner_and_group (psd, buf);
5134 LocalFree (psd);
5136 else
5137 get_file_owner_and_group (NULL, buf);
5140 buf->st_dev = info.dwVolumeSerialNumber;
5141 buf->st_rdev = info.dwVolumeSerialNumber;
5143 buf->st_size = info.nFileSizeHigh;
5144 buf->st_size <<= 32;
5145 buf->st_size += info.nFileSizeLow;
5147 /* Convert timestamps to Unix format. */
5148 buf->st_mtime = convert_time (info.ftLastWriteTime);
5149 buf->st_atime = convert_time (info.ftLastAccessTime);
5150 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5151 buf->st_ctime = convert_time (info.ftCreationTime);
5152 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5154 /* determine rwx permissions */
5155 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5156 permission = S_IREAD;
5157 else
5158 permission = S_IREAD | S_IWRITE;
5160 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5161 permission |= S_IEXEC;
5162 else
5164 #if 0 /* no way of knowing the filename */
5165 char * p = strrchr (name, '.');
5166 if (p != NULL &&
5167 (xstrcasecmp (p, ".exe") == 0 ||
5168 xstrcasecmp (p, ".com") == 0 ||
5169 xstrcasecmp (p, ".bat") == 0 ||
5170 xstrcasecmp (p, ".cmd") == 0))
5171 permission |= S_IEXEC;
5172 #endif
5175 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5177 return 0;
5180 /* A version of 'utime' which handles directories as well as
5181 files. */
5184 utime (const char *name, struct utimbuf *times)
5186 struct utimbuf deftime;
5187 HANDLE fh;
5188 FILETIME mtime;
5189 FILETIME atime;
5191 if (times == NULL)
5193 deftime.modtime = deftime.actime = time (NULL);
5194 times = &deftime;
5197 if (w32_unicode_filenames)
5199 wchar_t name_utf16[MAX_PATH];
5201 if (filename_to_utf16 (name, name_utf16) != 0)
5202 return -1; /* errno set by filename_to_utf16 */
5204 /* Need write access to set times. */
5205 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5206 /* If NAME specifies a directory, FILE_SHARE_DELETE
5207 allows other processes to delete files inside it,
5208 while we have the directory open. */
5209 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5210 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5212 else
5214 char name_ansi[MAX_PATH];
5216 if (filename_to_ansi (name, name_ansi) != 0)
5217 return -1; /* errno set by filename_to_ansi */
5219 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5220 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5221 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5223 if (fh != INVALID_HANDLE_VALUE)
5225 convert_from_time_t (times->actime, &atime);
5226 convert_from_time_t (times->modtime, &mtime);
5227 if (!SetFileTime (fh, NULL, &atime, &mtime))
5229 CloseHandle (fh);
5230 errno = EACCES;
5231 return -1;
5233 CloseHandle (fh);
5235 else
5237 DWORD err = GetLastError ();
5239 switch (err)
5241 case ERROR_FILE_NOT_FOUND:
5242 case ERROR_PATH_NOT_FOUND:
5243 case ERROR_INVALID_DRIVE:
5244 case ERROR_BAD_NETPATH:
5245 case ERROR_DEV_NOT_EXIST:
5246 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5247 file name includes ?s, i.e. translation to ANSI failed. */
5248 case ERROR_INVALID_NAME:
5249 errno = ENOENT;
5250 break;
5251 case ERROR_TOO_MANY_OPEN_FILES:
5252 errno = ENFILE;
5253 break;
5254 case ERROR_ACCESS_DENIED:
5255 case ERROR_SHARING_VIOLATION:
5256 errno = EACCES;
5257 break;
5258 default:
5259 errno = EINVAL;
5260 break;
5262 return -1;
5264 return 0;
5268 /* Symlink-related functions. */
5269 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5270 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5271 #endif
5274 symlink (char const *filename, char const *linkname)
5276 char linkfn[MAX_UTF8_PATH], *tgtfn;
5277 DWORD flags = 0;
5278 int dir_access, filename_ends_in_slash;
5280 /* Diagnostics follows Posix as much as possible. */
5281 if (filename == NULL || linkname == NULL)
5283 errno = EFAULT;
5284 return -1;
5286 if (!*filename)
5288 errno = ENOENT;
5289 return -1;
5291 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5293 errno = ENAMETOOLONG;
5294 return -1;
5297 strcpy (linkfn, map_w32_filename (linkname, NULL));
5298 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5300 errno = EPERM;
5301 return -1;
5304 /* Note: since empty FILENAME was already rejected, we can safely
5305 refer to FILENAME[1]. */
5306 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5308 /* Non-absolute FILENAME is understood as being relative to
5309 LINKNAME's directory. We need to prepend that directory to
5310 FILENAME to get correct results from faccessat below, since
5311 otherwise it will interpret FILENAME relative to the
5312 directory where the Emacs process runs. Note that
5313 make-symbolic-link always makes sure LINKNAME is a fully
5314 expanded file name. */
5315 char tem[MAX_UTF8_PATH];
5316 char *p = linkfn + strlen (linkfn);
5318 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5319 p--;
5320 if (p > linkfn)
5321 strncpy (tem, linkfn, p - linkfn);
5322 tem[p - linkfn] = '\0';
5323 strcat (tem, filename);
5324 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5326 else
5327 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5329 /* Since Windows distinguishes between symlinks to directories and
5330 to files, we provide a kludgy feature: if FILENAME doesn't
5331 exist, but ends in a slash, we create a symlink to directory. If
5332 FILENAME exists and is a directory, we always create a symlink to
5333 directory. */
5334 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5335 if (dir_access == 0 || filename_ends_in_slash)
5336 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5338 tgtfn = (char *)map_w32_filename (filename, NULL);
5339 if (filename_ends_in_slash)
5340 tgtfn[strlen (tgtfn) - 1] = '\0';
5342 errno = 0;
5343 if (!create_symbolic_link (linkfn, tgtfn, flags))
5345 /* ENOSYS is set by create_symbolic_link, when it detects that
5346 the OS doesn't support the CreateSymbolicLink API. */
5347 if (errno != ENOSYS)
5349 DWORD w32err = GetLastError ();
5351 switch (w32err)
5353 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5354 TGTFN point to the same file name, go figure. */
5355 case ERROR_SUCCESS:
5356 case ERROR_FILE_EXISTS:
5357 errno = EEXIST;
5358 break;
5359 case ERROR_ACCESS_DENIED:
5360 errno = EACCES;
5361 break;
5362 case ERROR_FILE_NOT_FOUND:
5363 case ERROR_PATH_NOT_FOUND:
5364 case ERROR_BAD_NETPATH:
5365 case ERROR_INVALID_REPARSE_DATA:
5366 errno = ENOENT;
5367 break;
5368 case ERROR_DIRECTORY:
5369 errno = EISDIR;
5370 break;
5371 case ERROR_PRIVILEGE_NOT_HELD:
5372 case ERROR_NOT_ALL_ASSIGNED:
5373 errno = EPERM;
5374 break;
5375 case ERROR_DISK_FULL:
5376 errno = ENOSPC;
5377 break;
5378 default:
5379 errno = EINVAL;
5380 break;
5383 return -1;
5385 return 0;
5388 /* A quick inexpensive test of whether FILENAME identifies a file that
5389 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5390 must already be in the normalized form returned by
5391 map_w32_filename.
5393 Note: for repeated operations on many files, it is best to test
5394 whether the underlying volume actually supports symlinks, by
5395 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5396 avoid the call to this function if it doesn't. That's because the
5397 call to GetFileAttributes takes a non-negligible time, especially
5398 on non-local or removable filesystems. See stat_worker for an
5399 example of how to do that. */
5400 static int
5401 is_symlink (const char *filename)
5403 DWORD attrs;
5404 wchar_t filename_w[MAX_PATH];
5405 char filename_a[MAX_PATH];
5406 WIN32_FIND_DATAW wfdw;
5407 WIN32_FIND_DATAA wfda;
5408 HANDLE fh;
5409 int attrs_mean_symlink;
5411 if (w32_unicode_filenames)
5413 filename_to_utf16 (filename, filename_w);
5414 attrs = GetFileAttributesW (filename_w);
5416 else
5418 filename_to_ansi (filename, filename_a);
5419 attrs = GetFileAttributesA (filename_a);
5421 if (attrs == -1)
5423 DWORD w32err = GetLastError ();
5425 switch (w32err)
5427 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5428 break;
5429 case ERROR_ACCESS_DENIED:
5430 errno = EACCES;
5431 break;
5432 case ERROR_FILE_NOT_FOUND:
5433 case ERROR_PATH_NOT_FOUND:
5434 default:
5435 errno = ENOENT;
5436 break;
5438 return 0;
5440 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5441 return 0;
5442 logon_network_drive (filename);
5443 if (w32_unicode_filenames)
5445 fh = FindFirstFileW (filename_w, &wfdw);
5446 attrs_mean_symlink =
5447 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5448 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5450 else if (_mbspbrk (filename_a, "?"))
5452 /* filename_to_ansi failed to convert the file name. */
5453 errno = ENOENT;
5454 return 0;
5456 else
5458 fh = FindFirstFileA (filename_a, &wfda);
5459 attrs_mean_symlink =
5460 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5461 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5463 if (fh == INVALID_HANDLE_VALUE)
5464 return 0;
5465 FindClose (fh);
5466 return attrs_mean_symlink;
5469 /* If NAME identifies a symbolic link, copy into BUF the file name of
5470 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5471 null-terminate the target name, even if it fits. Return the number
5472 of bytes copied, or -1 if NAME is not a symlink or any error was
5473 encountered while resolving it. The file name copied into BUF is
5474 encoded in the current ANSI codepage. */
5475 ssize_t
5476 readlink (const char *name, char *buf, size_t buf_size)
5478 const char *path;
5479 TOKEN_PRIVILEGES privs;
5480 int restore_privs = 0;
5481 HANDLE sh;
5482 ssize_t retval;
5483 char resolved[MAX_UTF8_PATH];
5485 if (name == NULL)
5487 errno = EFAULT;
5488 return -1;
5490 if (!*name)
5492 errno = ENOENT;
5493 return -1;
5496 path = map_w32_filename (name, NULL);
5498 if (strlen (path) > MAX_UTF8_PATH)
5500 errno = ENAMETOOLONG;
5501 return -1;
5504 errno = 0;
5505 if (is_windows_9x () == TRUE
5506 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5507 || !is_symlink (path))
5509 if (!errno)
5510 errno = EINVAL; /* not a symlink */
5511 return -1;
5514 /* Done with simple tests, now we're in for some _real_ work. */
5515 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5516 restore_privs = 1;
5517 /* Implementation note: From here and onward, don't return early,
5518 since that will fail to restore the original set of privileges of
5519 the calling thread. */
5521 retval = -1; /* not too optimistic, are we? */
5523 /* Note: In the next call to CreateFile, we use zero as the 2nd
5524 argument because, when the symlink is a hidden/system file,
5525 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5526 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5527 and directory symlinks. */
5528 if (w32_unicode_filenames)
5530 wchar_t path_w[MAX_PATH];
5532 filename_to_utf16 (path, path_w);
5533 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5534 FILE_FLAG_OPEN_REPARSE_POINT
5535 | FILE_FLAG_BACKUP_SEMANTICS,
5536 NULL);
5538 else
5540 char path_a[MAX_PATH];
5542 filename_to_ansi (path, path_a);
5543 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5544 FILE_FLAG_OPEN_REPARSE_POINT
5545 | FILE_FLAG_BACKUP_SEMANTICS,
5546 NULL);
5548 if (sh != INVALID_HANDLE_VALUE)
5550 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5551 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5552 DWORD retbytes;
5554 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5555 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5556 &retbytes, NULL))
5557 errno = EIO;
5558 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5559 errno = EINVAL;
5560 else
5562 /* Copy the link target name, in wide characters, from
5563 reparse_data, then convert it to multibyte encoding in
5564 the current locale's codepage. */
5565 WCHAR *lwname;
5566 size_t lname_size;
5567 USHORT lwname_len =
5568 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5569 WCHAR *lwname_src =
5570 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5571 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5572 size_t size_to_copy = buf_size;
5574 /* According to MSDN, PrintNameLength does not include the
5575 terminating null character. */
5576 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5577 memcpy (lwname, lwname_src, lwname_len);
5578 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5579 filename_from_utf16 (lwname, resolved);
5580 dostounix_filename (resolved);
5581 lname_size = strlen (resolved) + 1;
5582 if (lname_size <= buf_size)
5583 size_to_copy = lname_size;
5584 strncpy (buf, resolved, size_to_copy);
5585 /* Success! */
5586 retval = size_to_copy;
5588 CloseHandle (sh);
5590 else
5592 /* CreateFile failed. */
5593 DWORD w32err2 = GetLastError ();
5595 switch (w32err2)
5597 case ERROR_FILE_NOT_FOUND:
5598 case ERROR_PATH_NOT_FOUND:
5599 errno = ENOENT;
5600 break;
5601 case ERROR_ACCESS_DENIED:
5602 case ERROR_TOO_MANY_OPEN_FILES:
5603 errno = EACCES;
5604 break;
5605 default:
5606 errno = EPERM;
5607 break;
5610 if (restore_privs)
5612 restore_privilege (&privs);
5613 revert_to_self ();
5616 return retval;
5619 ssize_t
5620 readlinkat (int fd, char const *name, char *buffer,
5621 size_t buffer_size)
5623 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5624 as in fstatat. FIXME: Add proper support for readlinkat. */
5625 char fullname[MAX_UTF8_PATH];
5627 if (fd != AT_FDCWD)
5629 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5630 < 0)
5632 errno = ENAMETOOLONG;
5633 return -1;
5635 name = fullname;
5638 return readlink (name, buffer, buffer_size);
5641 /* If FILE is a symlink, return its target (stored in a static
5642 buffer); otherwise return FILE.
5644 This function repeatedly resolves symlinks in the last component of
5645 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5646 until it arrives at a file whose last component is not a symlink,
5647 or some error occurs. It returns the target of the last
5648 successfully resolved symlink in the chain. If it succeeds to
5649 resolve even a single symlink, the value returned is an absolute
5650 file name with backslashes (result of GetFullPathName). By
5651 contrast, if the original FILE is returned, it is unaltered.
5653 Note: This function can set errno even if it succeeds.
5655 Implementation note: we only resolve the last portion ("basename")
5656 of the argument FILE and of each following file in the chain,
5657 disregarding any possible symlinks in its leading directories.
5658 This is because Windows system calls and library functions
5659 transparently resolve symlinks in leading directories and return
5660 correct information, as long as the basename is not a symlink. */
5661 static char *
5662 chase_symlinks (const char *file)
5664 static char target[MAX_UTF8_PATH];
5665 char link[MAX_UTF8_PATH];
5666 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
5667 char target_a[MAX_PATH], link_a[MAX_PATH];
5668 ssize_t res, link_len;
5669 int loop_count = 0;
5671 if (is_windows_9x () == TRUE || !is_symlink (file))
5672 return (char *)file;
5674 if (w32_unicode_filenames)
5676 wchar_t file_w[MAX_PATH];
5678 filename_to_utf16 (file, file_w);
5679 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
5680 return (char *)file;
5681 filename_from_utf16 (link_w, link);
5683 else
5685 char file_a[MAX_PATH];
5687 filename_to_ansi (file, file_a);
5688 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
5689 return (char *)file;
5690 filename_from_ansi (link_a, link);
5692 link_len = strlen (link);
5694 target[0] = '\0';
5695 do {
5697 /* Remove trailing slashes, as we want to resolve the last
5698 non-trivial part of the link name. */
5699 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
5700 link[link_len--] = '\0';
5702 res = readlink (link, target, MAX_UTF8_PATH);
5703 if (res > 0)
5705 target[res] = '\0';
5706 if (!(IS_DEVICE_SEP (target[1])
5707 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
5709 /* Target is relative. Append it to the directory part of
5710 the symlink, then copy the result back to target. */
5711 char *p = link + link_len;
5713 while (p > link && !IS_ANY_SEP (p[-1]))
5714 p--;
5715 strcpy (p, target);
5716 strcpy (target, link);
5718 /* Resolve any "." and ".." to get a fully-qualified file name
5719 in link[] again. */
5720 if (w32_unicode_filenames)
5722 filename_to_utf16 (target, target_w);
5723 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
5724 if (link_len > 0)
5725 filename_from_utf16 (link_w, link);
5727 else
5729 filename_to_ansi (target, target_a);
5730 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
5731 if (link_len > 0)
5732 filename_from_ansi (link_a, link);
5734 link_len = strlen (link);
5736 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
5738 if (loop_count > 100)
5739 errno = ELOOP;
5741 if (target[0] == '\0') /* not a single call to readlink succeeded */
5742 return (char *)file;
5743 return target;
5747 /* Posix ACL emulation. */
5750 acl_valid (acl_t acl)
5752 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
5755 char *
5756 acl_to_text (acl_t acl, ssize_t *size)
5758 LPTSTR str_acl;
5759 SECURITY_INFORMATION flags =
5760 OWNER_SECURITY_INFORMATION |
5761 GROUP_SECURITY_INFORMATION |
5762 DACL_SECURITY_INFORMATION;
5763 char *retval = NULL;
5764 ULONG local_size;
5765 int e = errno;
5767 errno = 0;
5769 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
5771 errno = e;
5772 /* We don't want to mix heaps, so we duplicate the string in our
5773 heap and free the one allocated by the API. */
5774 retval = xstrdup (str_acl);
5775 if (size)
5776 *size = local_size;
5777 LocalFree (str_acl);
5779 else if (errno != ENOTSUP)
5780 errno = EINVAL;
5782 return retval;
5785 acl_t
5786 acl_from_text (const char *acl_str)
5788 PSECURITY_DESCRIPTOR psd, retval = NULL;
5789 ULONG sd_size;
5790 int e = errno;
5792 errno = 0;
5794 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
5796 errno = e;
5797 retval = xmalloc (sd_size);
5798 memcpy (retval, psd, sd_size);
5799 LocalFree (psd);
5801 else if (errno != ENOTSUP)
5802 errno = EINVAL;
5804 return retval;
5808 acl_free (void *ptr)
5810 xfree (ptr);
5811 return 0;
5814 acl_t
5815 acl_get_file (const char *fname, acl_type_t type)
5817 PSECURITY_DESCRIPTOR psd = NULL;
5818 const char *filename;
5820 if (type == ACL_TYPE_ACCESS)
5822 DWORD sd_len, err;
5823 SECURITY_INFORMATION si =
5824 OWNER_SECURITY_INFORMATION |
5825 GROUP_SECURITY_INFORMATION |
5826 DACL_SECURITY_INFORMATION ;
5827 int e = errno;
5829 filename = map_w32_filename (fname, NULL);
5830 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5831 fname = chase_symlinks (filename);
5832 else
5833 fname = filename;
5835 errno = 0;
5836 if (!get_file_security (fname, si, psd, 0, &sd_len)
5837 && errno != ENOTSUP)
5839 err = GetLastError ();
5840 if (err == ERROR_INSUFFICIENT_BUFFER)
5842 psd = xmalloc (sd_len);
5843 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
5845 xfree (psd);
5846 errno = EIO;
5847 psd = NULL;
5850 else if (err == ERROR_FILE_NOT_FOUND
5851 || err == ERROR_PATH_NOT_FOUND
5852 /* ERROR_INVALID_NAME is what we get if
5853 w32-unicode-filenames is nil and the file cannot
5854 be encoded in the current ANSI codepage. */
5855 || err == ERROR_INVALID_NAME)
5856 errno = ENOENT;
5857 else
5858 errno = EIO;
5860 else if (!errno)
5861 errno = e;
5863 else if (type != ACL_TYPE_DEFAULT)
5864 errno = EINVAL;
5866 return psd;
5870 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
5872 TOKEN_PRIVILEGES old1, old2;
5873 DWORD err;
5874 int st = 0, retval = -1;
5875 SECURITY_INFORMATION flags = 0;
5876 PSID psid;
5877 PACL pacl;
5878 BOOL dflt;
5879 BOOL dacl_present;
5880 int e;
5881 const char *filename;
5883 if (acl_valid (acl) != 0
5884 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
5886 errno = EINVAL;
5887 return -1;
5890 if (type == ACL_TYPE_DEFAULT)
5892 errno = ENOSYS;
5893 return -1;
5896 filename = map_w32_filename (fname, NULL);
5897 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5898 fname = chase_symlinks (filename);
5899 else
5900 fname = filename;
5902 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
5903 && psid)
5904 flags |= OWNER_SECURITY_INFORMATION;
5905 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
5906 && psid)
5907 flags |= GROUP_SECURITY_INFORMATION;
5908 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
5909 &pacl, &dflt)
5910 && dacl_present)
5911 flags |= DACL_SECURITY_INFORMATION;
5912 if (!flags)
5913 return 0;
5915 /* According to KB-245153, setting the owner will succeed if either:
5916 (1) the caller is the user who will be the new owner, and has the
5917 SE_TAKE_OWNERSHIP privilege, or
5918 (2) the caller has the SE_RESTORE privilege, in which case she can
5919 set any valid user or group as the owner
5921 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5922 privileges, and disregard any failures in obtaining them. If
5923 these privileges cannot be obtained, and do not already exist in
5924 the calling thread's security token, this function could fail
5925 with EPERM. */
5926 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
5927 st++;
5928 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
5929 st++;
5931 e = errno;
5932 errno = 0;
5933 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
5935 err = GetLastError ();
5937 if (errno == ENOTSUP)
5939 else if (err == ERROR_INVALID_OWNER
5940 || err == ERROR_NOT_ALL_ASSIGNED
5941 || err == ERROR_ACCESS_DENIED)
5943 /* Maybe the requested ACL and the one the file already has
5944 are identical, in which case we can silently ignore the
5945 failure. (And no, Windows doesn't.) */
5946 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
5948 errno = EPERM;
5949 if (current_acl)
5951 char *acl_from = acl_to_text (current_acl, NULL);
5952 char *acl_to = acl_to_text (acl, NULL);
5954 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
5956 retval = 0;
5957 errno = e;
5959 if (acl_from)
5960 acl_free (acl_from);
5961 if (acl_to)
5962 acl_free (acl_to);
5963 acl_free (current_acl);
5966 else if (err == ERROR_FILE_NOT_FOUND
5967 || err == ERROR_PATH_NOT_FOUND
5968 /* ERROR_INVALID_NAME is what we get if
5969 w32-unicode-filenames is nil and the file cannot be
5970 encoded in the current ANSI codepage. */
5971 || err == ERROR_INVALID_NAME)
5972 errno = ENOENT;
5973 else
5974 errno = EACCES;
5976 else
5978 retval = 0;
5979 errno = e;
5982 if (st)
5984 if (st >= 2)
5985 restore_privilege (&old2);
5986 restore_privilege (&old1);
5987 revert_to_self ();
5990 return retval;
5994 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5995 have a fixed max size for file names, so we don't need the kind of
5996 alloc/malloc/realloc dance the gnulib version does. We also don't
5997 support FD-relative symlinks. */
5998 char *
5999 careadlinkat (int fd, char const *filename,
6000 char *buffer, size_t buffer_size,
6001 struct allocator const *alloc,
6002 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6004 char linkname[MAX_UTF8_PATH];
6005 ssize_t link_size;
6007 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6009 if (link_size > 0)
6011 char *retval = buffer;
6013 linkname[link_size++] = '\0';
6014 if (link_size > buffer_size)
6015 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6016 if (retval)
6017 memcpy (retval, linkname, link_size);
6019 return retval;
6021 return NULL;
6025 w32_copy_file (const char *from, const char *to,
6026 int keep_time, int preserve_ownership, int copy_acls)
6028 acl_t acl = NULL;
6029 BOOL copy_result;
6030 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6031 char from_a[MAX_PATH], to_a[MAX_PATH];
6033 /* We ignore preserve_ownership for now. */
6034 preserve_ownership = preserve_ownership;
6036 if (copy_acls)
6038 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6039 if (acl == NULL && acl_errno_valid (errno))
6040 return -2;
6042 if (w32_unicode_filenames)
6044 filename_to_utf16 (from, from_w);
6045 filename_to_utf16 (to, to_w);
6046 copy_result = CopyFileW (from_w, to_w, FALSE);
6048 else
6050 filename_to_ansi (from, from_a);
6051 filename_to_ansi (to, to_a);
6052 copy_result = CopyFileA (from_a, to_a, FALSE);
6054 if (!copy_result)
6056 /* CopyFile doesn't set errno when it fails. By far the most
6057 "popular" reason is that the target is read-only. */
6058 DWORD err = GetLastError ();
6060 switch (err)
6062 case ERROR_FILE_NOT_FOUND:
6063 errno = ENOENT;
6064 break;
6065 case ERROR_ACCESS_DENIED:
6066 errno = EACCES;
6067 break;
6068 case ERROR_ENCRYPTION_FAILED:
6069 errno = EIO;
6070 break;
6071 default:
6072 errno = EPERM;
6073 break;
6076 if (acl)
6077 acl_free (acl);
6078 return -1;
6080 /* CopyFile retains the timestamp by default. However, see
6081 "Community Additions" for CopyFile: it sounds like that is not
6082 entirely true. Testing on Windows XP confirms that modified time
6083 is copied, but creation and last-access times are not.
6084 FIXME? */
6085 else if (!keep_time)
6087 struct timespec now;
6088 DWORD attributes;
6090 if (w32_unicode_filenames)
6092 /* Ensure file is writable while its times are set. */
6093 attributes = GetFileAttributesW (to_w);
6094 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6095 now = current_timespec ();
6096 if (set_file_times (-1, to, now, now))
6098 /* Restore original attributes. */
6099 SetFileAttributesW (to_w, attributes);
6100 if (acl)
6101 acl_free (acl);
6102 return -3;
6104 /* Restore original attributes. */
6105 SetFileAttributesW (to_w, attributes);
6107 else
6109 attributes = GetFileAttributesA (to_a);
6110 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6111 now = current_timespec ();
6112 if (set_file_times (-1, to, now, now))
6114 SetFileAttributesA (to_a, attributes);
6115 if (acl)
6116 acl_free (acl);
6117 return -3;
6119 SetFileAttributesA (to_a, attributes);
6122 if (acl != NULL)
6124 bool fail =
6125 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6126 acl_free (acl);
6127 if (fail && acl_errno_valid (errno))
6128 return -4;
6131 return 0;
6135 /* Support for browsing other processes and their attributes. See
6136 process.c for the Lisp bindings. */
6138 /* Helper wrapper functions. */
6140 static HANDLE WINAPI
6141 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6143 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6145 if (g_b_init_create_toolhelp32_snapshot == 0)
6147 g_b_init_create_toolhelp32_snapshot = 1;
6148 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6149 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6150 "CreateToolhelp32Snapshot");
6152 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6154 return INVALID_HANDLE_VALUE;
6156 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6159 static BOOL WINAPI
6160 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6162 static Process32First_Proc s_pfn_Process32_First = NULL;
6164 if (g_b_init_process32_first == 0)
6166 g_b_init_process32_first = 1;
6167 s_pfn_Process32_First = (Process32First_Proc)
6168 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6169 "Process32First");
6171 if (s_pfn_Process32_First == NULL)
6173 return FALSE;
6175 return (s_pfn_Process32_First (hSnapshot, lppe));
6178 static BOOL WINAPI
6179 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6181 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6183 if (g_b_init_process32_next == 0)
6185 g_b_init_process32_next = 1;
6186 s_pfn_Process32_Next = (Process32Next_Proc)
6187 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6188 "Process32Next");
6190 if (s_pfn_Process32_Next == NULL)
6192 return FALSE;
6194 return (s_pfn_Process32_Next (hSnapshot, lppe));
6197 static BOOL WINAPI
6198 open_thread_token (HANDLE ThreadHandle,
6199 DWORD DesiredAccess,
6200 BOOL OpenAsSelf,
6201 PHANDLE TokenHandle)
6203 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6204 HMODULE hm_advapi32 = NULL;
6205 if (is_windows_9x () == TRUE)
6207 SetLastError (ERROR_NOT_SUPPORTED);
6208 return FALSE;
6210 if (g_b_init_open_thread_token == 0)
6212 g_b_init_open_thread_token = 1;
6213 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6214 s_pfn_Open_Thread_Token =
6215 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6217 if (s_pfn_Open_Thread_Token == NULL)
6219 SetLastError (ERROR_NOT_SUPPORTED);
6220 return FALSE;
6222 return (
6223 s_pfn_Open_Thread_Token (
6224 ThreadHandle,
6225 DesiredAccess,
6226 OpenAsSelf,
6227 TokenHandle)
6231 static BOOL WINAPI
6232 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6234 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6235 HMODULE hm_advapi32 = NULL;
6236 if (is_windows_9x () == TRUE)
6238 return FALSE;
6240 if (g_b_init_impersonate_self == 0)
6242 g_b_init_impersonate_self = 1;
6243 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6244 s_pfn_Impersonate_Self =
6245 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6247 if (s_pfn_Impersonate_Self == NULL)
6249 return FALSE;
6251 return s_pfn_Impersonate_Self (ImpersonationLevel);
6254 static BOOL WINAPI
6255 revert_to_self (void)
6257 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6258 HMODULE hm_advapi32 = NULL;
6259 if (is_windows_9x () == TRUE)
6261 return FALSE;
6263 if (g_b_init_revert_to_self == 0)
6265 g_b_init_revert_to_self = 1;
6266 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6267 s_pfn_Revert_To_Self =
6268 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6270 if (s_pfn_Revert_To_Self == NULL)
6272 return FALSE;
6274 return s_pfn_Revert_To_Self ();
6277 static BOOL WINAPI
6278 get_process_memory_info (HANDLE h_proc,
6279 PPROCESS_MEMORY_COUNTERS mem_counters,
6280 DWORD bufsize)
6282 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6283 HMODULE hm_psapi = NULL;
6284 if (is_windows_9x () == TRUE)
6286 return FALSE;
6288 if (g_b_init_get_process_memory_info == 0)
6290 g_b_init_get_process_memory_info = 1;
6291 hm_psapi = LoadLibrary ("Psapi.dll");
6292 if (hm_psapi)
6293 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6294 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6296 if (s_pfn_Get_Process_Memory_Info == NULL)
6298 return FALSE;
6300 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6303 static BOOL WINAPI
6304 get_process_working_set_size (HANDLE h_proc,
6305 PSIZE_T minrss,
6306 PSIZE_T maxrss)
6308 static GetProcessWorkingSetSize_Proc
6309 s_pfn_Get_Process_Working_Set_Size = NULL;
6311 if (is_windows_9x () == TRUE)
6313 return FALSE;
6315 if (g_b_init_get_process_working_set_size == 0)
6317 g_b_init_get_process_working_set_size = 1;
6318 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6319 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6320 "GetProcessWorkingSetSize");
6322 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6324 return FALSE;
6326 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6329 static BOOL WINAPI
6330 global_memory_status (MEMORYSTATUS *buf)
6332 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6334 if (is_windows_9x () == TRUE)
6336 return FALSE;
6338 if (g_b_init_global_memory_status == 0)
6340 g_b_init_global_memory_status = 1;
6341 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6342 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6343 "GlobalMemoryStatus");
6345 if (s_pfn_Global_Memory_Status == NULL)
6347 return FALSE;
6349 return s_pfn_Global_Memory_Status (buf);
6352 static BOOL WINAPI
6353 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6355 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6357 if (is_windows_9x () == TRUE)
6359 return FALSE;
6361 if (g_b_init_global_memory_status_ex == 0)
6363 g_b_init_global_memory_status_ex = 1;
6364 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6365 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6366 "GlobalMemoryStatusEx");
6368 if (s_pfn_Global_Memory_Status_Ex == NULL)
6370 return FALSE;
6372 return s_pfn_Global_Memory_Status_Ex (buf);
6375 Lisp_Object
6376 list_system_processes (void)
6378 struct gcpro gcpro1;
6379 Lisp_Object proclist = Qnil;
6380 HANDLE h_snapshot;
6382 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6384 if (h_snapshot != INVALID_HANDLE_VALUE)
6386 PROCESSENTRY32 proc_entry;
6387 DWORD proc_id;
6388 BOOL res;
6390 GCPRO1 (proclist);
6392 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6393 for (res = process32_first (h_snapshot, &proc_entry); res;
6394 res = process32_next (h_snapshot, &proc_entry))
6396 proc_id = proc_entry.th32ProcessID;
6397 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6400 CloseHandle (h_snapshot);
6401 UNGCPRO;
6402 proclist = Fnreverse (proclist);
6405 return proclist;
6408 static int
6409 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6411 TOKEN_PRIVILEGES priv;
6412 DWORD priv_size = sizeof (priv);
6413 DWORD opriv_size = sizeof (*old_priv);
6414 HANDLE h_token = NULL;
6415 HANDLE h_thread = GetCurrentThread ();
6416 int ret_val = 0;
6417 BOOL res;
6419 res = open_thread_token (h_thread,
6420 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6421 FALSE, &h_token);
6422 if (!res && GetLastError () == ERROR_NO_TOKEN)
6424 if (impersonate_self (SecurityImpersonation))
6425 res = open_thread_token (h_thread,
6426 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6427 FALSE, &h_token);
6429 if (res)
6431 priv.PrivilegeCount = 1;
6432 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6433 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6434 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6435 old_priv, &opriv_size)
6436 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6437 ret_val = 1;
6439 if (h_token)
6440 CloseHandle (h_token);
6442 return ret_val;
6445 static int
6446 restore_privilege (TOKEN_PRIVILEGES *priv)
6448 DWORD priv_size = sizeof (*priv);
6449 HANDLE h_token = NULL;
6450 int ret_val = 0;
6452 if (open_thread_token (GetCurrentThread (),
6453 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6454 FALSE, &h_token))
6456 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6457 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6458 ret_val = 1;
6460 if (h_token)
6461 CloseHandle (h_token);
6463 return ret_val;
6466 static Lisp_Object
6467 ltime (ULONGLONG time_100ns)
6469 ULONGLONG time_sec = time_100ns / 10000000;
6470 int subsec = time_100ns % 10000000;
6471 return list4i (time_sec >> 16, time_sec & 0xffff,
6472 subsec / 10, subsec % 10 * 100000);
6475 #define U64_TO_LISP_TIME(time) ltime (time)
6477 static int
6478 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6479 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6480 double *pcpu)
6482 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6483 ULONGLONG tem1, tem2, tem3, tem;
6485 if (!h_proc
6486 || !get_process_times_fn
6487 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6488 &ft_kernel, &ft_user))
6489 return 0;
6491 GetSystemTimeAsFileTime (&ft_current);
6493 FILETIME_TO_U64 (tem1, ft_kernel);
6494 *stime = U64_TO_LISP_TIME (tem1);
6496 FILETIME_TO_U64 (tem2, ft_user);
6497 *utime = U64_TO_LISP_TIME (tem2);
6499 tem3 = tem1 + tem2;
6500 *ttime = U64_TO_LISP_TIME (tem3);
6502 FILETIME_TO_U64 (tem, ft_creation);
6503 /* Process no 4 (System) returns zero creation time. */
6504 if (tem)
6505 tem -= utc_base;
6506 *ctime = U64_TO_LISP_TIME (tem);
6508 if (tem)
6510 FILETIME_TO_U64 (tem3, ft_current);
6511 tem = (tem3 - utc_base) - tem;
6513 *etime = U64_TO_LISP_TIME (tem);
6515 if (tem)
6517 *pcpu = 100.0 * (tem1 + tem2) / tem;
6518 if (*pcpu > 100)
6519 *pcpu = 100.0;
6521 else
6522 *pcpu = 0;
6524 return 1;
6527 Lisp_Object
6528 system_process_attributes (Lisp_Object pid)
6530 struct gcpro gcpro1, gcpro2, gcpro3;
6531 Lisp_Object attrs = Qnil;
6532 Lisp_Object cmd_str, decoded_cmd, tem;
6533 HANDLE h_snapshot, h_proc;
6534 DWORD proc_id;
6535 int found_proc = 0;
6536 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
6537 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
6538 DWORD glength = sizeof (gname);
6539 HANDLE token = NULL;
6540 SID_NAME_USE user_type;
6541 unsigned char *buf = NULL;
6542 DWORD blen = 0;
6543 TOKEN_USER user_token;
6544 TOKEN_PRIMARY_GROUP group_token;
6545 unsigned euid;
6546 unsigned egid;
6547 PROCESS_MEMORY_COUNTERS mem;
6548 PROCESS_MEMORY_COUNTERS_EX mem_ex;
6549 SIZE_T minrss, maxrss;
6550 MEMORYSTATUS memst;
6551 MEMORY_STATUS_EX memstex;
6552 double totphys = 0.0;
6553 Lisp_Object ctime, stime, utime, etime, ttime;
6554 double pcpu;
6555 BOOL result = FALSE;
6557 CHECK_NUMBER_OR_FLOAT (pid);
6558 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
6560 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6562 GCPRO3 (attrs, decoded_cmd, tem);
6564 if (h_snapshot != INVALID_HANDLE_VALUE)
6566 PROCESSENTRY32 pe;
6567 BOOL res;
6569 pe.dwSize = sizeof (PROCESSENTRY32);
6570 for (res = process32_first (h_snapshot, &pe); res;
6571 res = process32_next (h_snapshot, &pe))
6573 if (proc_id == pe.th32ProcessID)
6575 if (proc_id == 0)
6576 decoded_cmd = build_string ("Idle");
6577 else
6579 /* Decode the command name from locale-specific
6580 encoding. */
6581 cmd_str = build_unibyte_string (pe.szExeFile);
6583 decoded_cmd =
6584 code_convert_string_norecord (cmd_str,
6585 Vlocale_coding_system, 0);
6587 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
6588 attrs = Fcons (Fcons (Qppid,
6589 make_fixnum_or_float (pe.th32ParentProcessID)),
6590 attrs);
6591 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
6592 attrs);
6593 attrs = Fcons (Fcons (Qthcount,
6594 make_fixnum_or_float (pe.cntThreads)),
6595 attrs);
6596 found_proc = 1;
6597 break;
6601 CloseHandle (h_snapshot);
6604 if (!found_proc)
6606 UNGCPRO;
6607 return Qnil;
6610 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6611 FALSE, proc_id);
6612 /* If we were denied a handle to the process, try again after
6613 enabling the SeDebugPrivilege in our process. */
6614 if (!h_proc)
6616 TOKEN_PRIVILEGES priv_current;
6618 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
6620 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6621 FALSE, proc_id);
6622 restore_privilege (&priv_current);
6623 revert_to_self ();
6626 if (h_proc)
6628 result = open_process_token (h_proc, TOKEN_QUERY, &token);
6629 if (result)
6631 result = get_token_information (token, TokenUser, NULL, 0, &blen);
6632 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6634 buf = xmalloc (blen);
6635 result = get_token_information (token, TokenUser,
6636 (LPVOID)buf, blen, &needed);
6637 if (result)
6639 memcpy (&user_token, buf, sizeof (user_token));
6640 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
6642 euid = get_rid (user_token.User.Sid);
6643 result = lookup_account_sid (NULL, user_token.User.Sid,
6644 uname, &ulength,
6645 domain, &dlength,
6646 &user_type);
6647 if (result)
6648 w32_add_to_cache (user_token.User.Sid, euid, uname);
6649 else
6651 strcpy (uname, "unknown");
6652 result = TRUE;
6655 ulength = strlen (uname);
6659 if (result)
6661 /* Determine a reasonable euid and gid values. */
6662 if (xstrcasecmp ("administrator", uname) == 0)
6664 euid = 500; /* well-known Administrator uid */
6665 egid = 513; /* well-known None gid */
6667 else
6669 /* Get group id and name. */
6670 result = get_token_information (token, TokenPrimaryGroup,
6671 (LPVOID)buf, blen, &needed);
6672 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6674 buf = xrealloc (buf, blen = needed);
6675 result = get_token_information (token, TokenPrimaryGroup,
6676 (LPVOID)buf, blen, &needed);
6678 if (result)
6680 memcpy (&group_token, buf, sizeof (group_token));
6681 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
6683 egid = get_rid (group_token.PrimaryGroup);
6684 dlength = sizeof (domain);
6685 result =
6686 lookup_account_sid (NULL, group_token.PrimaryGroup,
6687 gname, &glength, NULL, &dlength,
6688 &user_type);
6689 if (result)
6690 w32_add_to_cache (group_token.PrimaryGroup,
6691 egid, gname);
6692 else
6694 strcpy (gname, "None");
6695 result = TRUE;
6698 glength = strlen (gname);
6702 xfree (buf);
6704 if (!result)
6706 if (!is_windows_9x ())
6708 /* We couldn't open the process token, presumably because of
6709 insufficient access rights. Assume this process is run
6710 by the system. */
6711 strcpy (uname, "SYSTEM");
6712 strcpy (gname, "None");
6713 euid = 18; /* SYSTEM */
6714 egid = 513; /* None */
6715 glength = strlen (gname);
6716 ulength = strlen (uname);
6718 /* If we are running under Windows 9X, where security calls are
6719 not supported, we assume all processes are run by the current
6720 user. */
6721 else if (GetUserName (uname, &ulength))
6723 if (xstrcasecmp ("administrator", uname) == 0)
6724 euid = 0;
6725 else
6726 euid = 123;
6727 egid = euid;
6728 strcpy (gname, "None");
6729 glength = strlen (gname);
6730 ulength = strlen (uname);
6732 else
6734 euid = 123;
6735 egid = 123;
6736 strcpy (uname, "administrator");
6737 ulength = strlen (uname);
6738 strcpy (gname, "None");
6739 glength = strlen (gname);
6741 if (token)
6742 CloseHandle (token);
6745 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
6746 tem = make_unibyte_string (uname, ulength);
6747 attrs = Fcons (Fcons (Quser,
6748 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6749 attrs);
6750 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
6751 tem = make_unibyte_string (gname, glength);
6752 attrs = Fcons (Fcons (Qgroup,
6753 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6754 attrs);
6756 if (global_memory_status_ex (&memstex))
6757 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
6758 totphys = memstex.ullTotalPhys / 1024.0;
6759 #else
6760 /* Visual Studio 6 cannot convert an unsigned __int64 type to
6761 double, so we need to do this for it... */
6763 DWORD tot_hi = memstex.ullTotalPhys >> 32;
6764 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
6765 DWORD tot_lo = memstex.ullTotalPhys % 1024;
6767 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
6769 #endif /* __GNUC__ || _MSC_VER >= 1300 */
6770 else if (global_memory_status (&memst))
6771 totphys = memst.dwTotalPhys / 1024.0;
6773 if (h_proc
6774 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
6775 sizeof (mem_ex)))
6777 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6779 attrs = Fcons (Fcons (Qmajflt,
6780 make_fixnum_or_float (mem_ex.PageFaultCount)),
6781 attrs);
6782 attrs = Fcons (Fcons (Qvsize,
6783 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
6784 attrs);
6785 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6786 if (totphys)
6787 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6789 else if (h_proc
6790 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
6792 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6794 attrs = Fcons (Fcons (Qmajflt,
6795 make_fixnum_or_float (mem.PageFaultCount)),
6796 attrs);
6797 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6798 if (totphys)
6799 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6801 else if (h_proc
6802 && get_process_working_set_size (h_proc, &minrss, &maxrss))
6804 DWORD rss = maxrss / 1024;
6806 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
6807 if (totphys)
6808 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6811 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
6813 attrs = Fcons (Fcons (Qutime, utime), attrs);
6814 attrs = Fcons (Fcons (Qstime, stime), attrs);
6815 attrs = Fcons (Fcons (Qtime, ttime), attrs);
6816 attrs = Fcons (Fcons (Qstart, ctime), attrs);
6817 attrs = Fcons (Fcons (Qetime, etime), attrs);
6818 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
6821 /* FIXME: Retrieve command line by walking the PEB of the process. */
6823 if (h_proc)
6824 CloseHandle (h_proc);
6825 UNGCPRO;
6826 return attrs;
6830 /* Wrappers for winsock functions to map between our file descriptors
6831 and winsock's handles; also set h_errno for convenience.
6833 To allow Emacs to run on systems which don't have winsock support
6834 installed, we dynamically link to winsock on startup if present, and
6835 otherwise provide the minimum necessary functionality
6836 (eg. gethostname). */
6838 /* function pointers for relevant socket functions */
6839 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
6840 void (PASCAL *pfn_WSASetLastError) (int iError);
6841 int (PASCAL *pfn_WSAGetLastError) (void);
6842 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
6843 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
6844 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
6845 int (PASCAL *pfn_socket) (int af, int type, int protocol);
6846 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
6847 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
6848 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
6849 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
6850 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
6851 int (PASCAL *pfn_closesocket) (SOCKET s);
6852 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
6853 int (PASCAL *pfn_WSACleanup) (void);
6855 u_short (PASCAL *pfn_htons) (u_short hostshort);
6856 u_short (PASCAL *pfn_ntohs) (u_short netshort);
6857 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
6858 int (PASCAL *pfn_gethostname) (char * name, int namelen);
6859 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
6860 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
6861 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
6862 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
6863 const char * optval, int optlen);
6864 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
6865 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
6866 int * namelen);
6867 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
6868 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
6869 struct sockaddr * from, int * fromlen);
6870 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
6871 const struct sockaddr * to, int tolen);
6873 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6874 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
6875 #ifndef HANDLE_FLAG_INHERIT
6876 #define HANDLE_FLAG_INHERIT 1
6877 #endif
6879 HANDLE winsock_lib;
6880 static int winsock_inuse;
6882 BOOL
6883 term_winsock (void)
6885 if (winsock_lib != NULL && winsock_inuse == 0)
6887 release_listen_threads ();
6888 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6889 after WSAStartup returns successfully, but it seems reasonable
6890 to allow unloading winsock anyway in that case. */
6891 if (pfn_WSACleanup () == 0 ||
6892 pfn_WSAGetLastError () == WSAENETDOWN)
6894 if (FreeLibrary (winsock_lib))
6895 winsock_lib = NULL;
6896 return TRUE;
6899 return FALSE;
6902 BOOL
6903 init_winsock (int load_now)
6905 WSADATA winsockData;
6907 if (winsock_lib != NULL)
6908 return TRUE;
6910 pfn_SetHandleInformation
6911 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6912 "SetHandleInformation");
6914 winsock_lib = LoadLibrary ("Ws2_32.dll");
6916 if (winsock_lib != NULL)
6918 /* dynamically link to socket functions */
6920 #define LOAD_PROC(fn) \
6921 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6922 goto fail;
6924 LOAD_PROC (WSAStartup);
6925 LOAD_PROC (WSASetLastError);
6926 LOAD_PROC (WSAGetLastError);
6927 LOAD_PROC (WSAEventSelect);
6928 LOAD_PROC (WSACreateEvent);
6929 LOAD_PROC (WSACloseEvent);
6930 LOAD_PROC (socket);
6931 LOAD_PROC (bind);
6932 LOAD_PROC (connect);
6933 LOAD_PROC (ioctlsocket);
6934 LOAD_PROC (recv);
6935 LOAD_PROC (send);
6936 LOAD_PROC (closesocket);
6937 LOAD_PROC (shutdown);
6938 LOAD_PROC (htons);
6939 LOAD_PROC (ntohs);
6940 LOAD_PROC (inet_addr);
6941 LOAD_PROC (gethostname);
6942 LOAD_PROC (gethostbyname);
6943 LOAD_PROC (getservbyname);
6944 LOAD_PROC (getpeername);
6945 LOAD_PROC (WSACleanup);
6946 LOAD_PROC (setsockopt);
6947 LOAD_PROC (listen);
6948 LOAD_PROC (getsockname);
6949 LOAD_PROC (accept);
6950 LOAD_PROC (recvfrom);
6951 LOAD_PROC (sendto);
6952 #undef LOAD_PROC
6954 /* specify version 1.1 of winsock */
6955 if (pfn_WSAStartup (0x101, &winsockData) == 0)
6957 if (winsockData.wVersion != 0x101)
6958 goto fail;
6960 if (!load_now)
6962 /* Report that winsock exists and is usable, but leave
6963 socket functions disabled. I am assuming that calling
6964 WSAStartup does not require any network interaction,
6965 and in particular does not cause or require a dial-up
6966 connection to be established. */
6968 pfn_WSACleanup ();
6969 FreeLibrary (winsock_lib);
6970 winsock_lib = NULL;
6972 winsock_inuse = 0;
6973 return TRUE;
6976 fail:
6977 FreeLibrary (winsock_lib);
6978 winsock_lib = NULL;
6981 return FALSE;
6985 int h_errno = 0;
6987 /* Function to map winsock error codes to errno codes for those errno
6988 code defined in errno.h (errno values not defined by errno.h are
6989 already in nt/inc/sys/socket.h). */
6990 static void
6991 set_errno (void)
6993 int wsa_err;
6995 h_errno = 0;
6996 if (winsock_lib == NULL)
6997 wsa_err = EINVAL;
6998 else
6999 wsa_err = pfn_WSAGetLastError ();
7001 switch (wsa_err)
7003 case WSAEACCES: errno = EACCES; break;
7004 case WSAEBADF: errno = EBADF; break;
7005 case WSAEFAULT: errno = EFAULT; break;
7006 case WSAEINTR: errno = EINTR; break;
7007 case WSAEINVAL: errno = EINVAL; break;
7008 case WSAEMFILE: errno = EMFILE; break;
7009 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7010 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7011 default: errno = wsa_err; break;
7015 static void
7016 check_errno (void)
7018 h_errno = 0;
7019 if (winsock_lib != NULL)
7020 pfn_WSASetLastError (0);
7023 /* Extend strerror to handle the winsock-specific error codes. */
7024 struct {
7025 int errnum;
7026 char * msg;
7027 } _wsa_errlist[] = {
7028 {WSAEINTR , "Interrupted function call"},
7029 {WSAEBADF , "Bad file descriptor"},
7030 {WSAEACCES , "Permission denied"},
7031 {WSAEFAULT , "Bad address"},
7032 {WSAEINVAL , "Invalid argument"},
7033 {WSAEMFILE , "Too many open files"},
7035 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7036 {WSAEINPROGRESS , "Operation now in progress"},
7037 {WSAEALREADY , "Operation already in progress"},
7038 {WSAENOTSOCK , "Socket operation on non-socket"},
7039 {WSAEDESTADDRREQ , "Destination address required"},
7040 {WSAEMSGSIZE , "Message too long"},
7041 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7042 {WSAENOPROTOOPT , "Bad protocol option"},
7043 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7044 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7045 {WSAEOPNOTSUPP , "Operation not supported"},
7046 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7047 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7048 {WSAEADDRINUSE , "Address already in use"},
7049 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7050 {WSAENETDOWN , "Network is down"},
7051 {WSAENETUNREACH , "Network is unreachable"},
7052 {WSAENETRESET , "Network dropped connection on reset"},
7053 {WSAECONNABORTED , "Software caused connection abort"},
7054 {WSAECONNRESET , "Connection reset by peer"},
7055 {WSAENOBUFS , "No buffer space available"},
7056 {WSAEISCONN , "Socket is already connected"},
7057 {WSAENOTCONN , "Socket is not connected"},
7058 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7059 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7060 {WSAETIMEDOUT , "Connection timed out"},
7061 {WSAECONNREFUSED , "Connection refused"},
7062 {WSAELOOP , "Network loop"}, /* not sure */
7063 {WSAENAMETOOLONG , "Name is too long"},
7064 {WSAEHOSTDOWN , "Host is down"},
7065 {WSAEHOSTUNREACH , "No route to host"},
7066 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7067 {WSAEPROCLIM , "Too many processes"},
7068 {WSAEUSERS , "Too many users"}, /* not sure */
7069 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7070 {WSAESTALE , "Data is stale"}, /* not sure */
7071 {WSAEREMOTE , "Remote error"}, /* not sure */
7073 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7074 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7075 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7076 {WSAEDISCON , "Graceful shutdown in progress"},
7077 #ifdef WSAENOMORE
7078 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7079 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7080 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7081 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7082 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7083 {WSASYSCALLFAILURE , "System call failure"},
7084 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7085 {WSATYPE_NOT_FOUND , "Class type not found"},
7086 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7087 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7088 {WSAEREFUSED , "Operation refused"}, /* not sure */
7089 #endif
7091 {WSAHOST_NOT_FOUND , "Host not found"},
7092 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7093 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7094 {WSANO_DATA , "Valid name, no data record of requested type"},
7096 {-1, NULL}
7099 char *
7100 sys_strerror (int error_no)
7102 int i;
7103 static char unknown_msg[40];
7105 if (error_no >= 0 && error_no < sys_nerr)
7106 return sys_errlist[error_no];
7108 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7109 if (_wsa_errlist[i].errnum == error_no)
7110 return _wsa_errlist[i].msg;
7112 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7113 return unknown_msg;
7116 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7117 but I believe the method of keeping the socket handle separate (and
7118 insuring it is not inheritable) is the correct one. */
7120 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7122 static int socket_to_fd (SOCKET s);
7125 sys_socket (int af, int type, int protocol)
7127 SOCKET s;
7129 if (winsock_lib == NULL)
7131 errno = ENETDOWN;
7132 return INVALID_SOCKET;
7135 check_errno ();
7137 /* call the real socket function */
7138 s = pfn_socket (af, type, protocol);
7140 if (s != INVALID_SOCKET)
7141 return socket_to_fd (s);
7143 set_errno ();
7144 return -1;
7147 /* Convert a SOCKET to a file descriptor. */
7148 static int
7149 socket_to_fd (SOCKET s)
7151 int fd;
7152 child_process * cp;
7154 /* Although under NT 3.5 _open_osfhandle will accept a socket
7155 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7156 that does not work under NT 3.1. However, we can get the same
7157 effect by using a backdoor function to replace an existing
7158 descriptor handle with the one we want. */
7160 /* allocate a file descriptor (with appropriate flags) */
7161 fd = _open ("NUL:", _O_RDWR);
7162 if (fd >= 0)
7164 /* Make a non-inheritable copy of the socket handle. Note
7165 that it is possible that sockets aren't actually kernel
7166 handles, which appears to be the case on Windows 9x when
7167 the MS Proxy winsock client is installed. */
7169 /* Apparently there is a bug in NT 3.51 with some service
7170 packs, which prevents using DuplicateHandle to make a
7171 socket handle non-inheritable (causes WSACleanup to
7172 hang). The work-around is to use SetHandleInformation
7173 instead if it is available and implemented. */
7174 if (pfn_SetHandleInformation)
7176 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7178 else
7180 HANDLE parent = GetCurrentProcess ();
7181 HANDLE new_s = INVALID_HANDLE_VALUE;
7183 if (DuplicateHandle (parent,
7184 (HANDLE) s,
7185 parent,
7186 &new_s,
7188 FALSE,
7189 DUPLICATE_SAME_ACCESS))
7191 /* It is possible that DuplicateHandle succeeds even
7192 though the socket wasn't really a kernel handle,
7193 because a real handle has the same value. So
7194 test whether the new handle really is a socket. */
7195 long nonblocking = 0;
7196 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7198 pfn_closesocket (s);
7199 s = (SOCKET) new_s;
7201 else
7203 CloseHandle (new_s);
7208 eassert (fd < MAXDESC);
7209 fd_info[fd].hnd = (HANDLE) s;
7211 /* set our own internal flags */
7212 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7214 cp = new_child ();
7215 if (cp)
7217 cp->fd = fd;
7218 cp->status = STATUS_READ_ACKNOWLEDGED;
7220 /* attach child_process to fd_info */
7221 if (fd_info[ fd ].cp != NULL)
7223 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7224 emacs_abort ();
7227 fd_info[ fd ].cp = cp;
7229 /* success! */
7230 winsock_inuse++; /* count open sockets */
7231 return fd;
7234 /* clean up */
7235 _close (fd);
7237 else
7238 pfn_closesocket (s);
7239 errno = EMFILE;
7240 return -1;
7244 sys_bind (int s, const struct sockaddr * addr, int namelen)
7246 if (winsock_lib == NULL)
7248 errno = ENOTSOCK;
7249 return SOCKET_ERROR;
7252 check_errno ();
7253 if (fd_info[s].flags & FILE_SOCKET)
7255 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7256 if (rc == SOCKET_ERROR)
7257 set_errno ();
7258 return rc;
7260 errno = ENOTSOCK;
7261 return SOCKET_ERROR;
7265 sys_connect (int s, const struct sockaddr * name, int namelen)
7267 if (winsock_lib == NULL)
7269 errno = ENOTSOCK;
7270 return SOCKET_ERROR;
7273 check_errno ();
7274 if (fd_info[s].flags & FILE_SOCKET)
7276 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7277 if (rc == SOCKET_ERROR)
7278 set_errno ();
7279 return rc;
7281 errno = ENOTSOCK;
7282 return SOCKET_ERROR;
7285 u_short
7286 sys_htons (u_short hostshort)
7288 return (winsock_lib != NULL) ?
7289 pfn_htons (hostshort) : hostshort;
7292 u_short
7293 sys_ntohs (u_short netshort)
7295 return (winsock_lib != NULL) ?
7296 pfn_ntohs (netshort) : netshort;
7299 unsigned long
7300 sys_inet_addr (const char * cp)
7302 return (winsock_lib != NULL) ?
7303 pfn_inet_addr (cp) : INADDR_NONE;
7307 sys_gethostname (char * name, int namelen)
7309 if (winsock_lib != NULL)
7311 int retval;
7313 check_errno ();
7314 retval = pfn_gethostname (name, namelen);
7315 if (retval == SOCKET_ERROR)
7316 set_errno ();
7317 return retval;
7320 if (namelen > MAX_COMPUTERNAME_LENGTH)
7321 return !GetComputerName (name, (DWORD *)&namelen);
7323 errno = EFAULT;
7324 return SOCKET_ERROR;
7327 struct hostent *
7328 sys_gethostbyname (const char * name)
7330 struct hostent * host;
7331 int h_err = h_errno;
7333 if (winsock_lib == NULL)
7335 h_errno = NO_RECOVERY;
7336 errno = ENETDOWN;
7337 return NULL;
7340 check_errno ();
7341 host = pfn_gethostbyname (name);
7342 if (!host)
7344 set_errno ();
7345 h_errno = errno;
7347 else
7348 h_errno = h_err;
7349 return host;
7352 struct servent *
7353 sys_getservbyname (const char * name, const char * proto)
7355 struct servent * serv;
7357 if (winsock_lib == NULL)
7359 errno = ENETDOWN;
7360 return NULL;
7363 check_errno ();
7364 serv = pfn_getservbyname (name, proto);
7365 if (!serv)
7366 set_errno ();
7367 return serv;
7371 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7373 if (winsock_lib == NULL)
7375 errno = ENETDOWN;
7376 return SOCKET_ERROR;
7379 check_errno ();
7380 if (fd_info[s].flags & FILE_SOCKET)
7382 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7383 if (rc == SOCKET_ERROR)
7384 set_errno ();
7385 return rc;
7387 errno = ENOTSOCK;
7388 return SOCKET_ERROR;
7392 sys_shutdown (int s, int how)
7394 if (winsock_lib == NULL)
7396 errno = ENETDOWN;
7397 return SOCKET_ERROR;
7400 check_errno ();
7401 if (fd_info[s].flags & FILE_SOCKET)
7403 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
7404 if (rc == SOCKET_ERROR)
7405 set_errno ();
7406 return rc;
7408 errno = ENOTSOCK;
7409 return SOCKET_ERROR;
7413 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
7415 if (winsock_lib == NULL)
7417 errno = ENETDOWN;
7418 return SOCKET_ERROR;
7421 check_errno ();
7422 if (fd_info[s].flags & FILE_SOCKET)
7424 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
7425 (const char *)optval, optlen);
7426 if (rc == SOCKET_ERROR)
7427 set_errno ();
7428 return rc;
7430 errno = ENOTSOCK;
7431 return SOCKET_ERROR;
7435 sys_listen (int s, int backlog)
7437 if (winsock_lib == NULL)
7439 errno = ENETDOWN;
7440 return SOCKET_ERROR;
7443 check_errno ();
7444 if (fd_info[s].flags & FILE_SOCKET)
7446 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
7447 if (rc == SOCKET_ERROR)
7448 set_errno ();
7449 else
7450 fd_info[s].flags |= FILE_LISTEN;
7451 return rc;
7453 errno = ENOTSOCK;
7454 return SOCKET_ERROR;
7458 sys_getsockname (int s, struct sockaddr * name, int * namelen)
7460 if (winsock_lib == NULL)
7462 errno = ENETDOWN;
7463 return SOCKET_ERROR;
7466 check_errno ();
7467 if (fd_info[s].flags & FILE_SOCKET)
7469 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
7470 if (rc == SOCKET_ERROR)
7471 set_errno ();
7472 return rc;
7474 errno = ENOTSOCK;
7475 return SOCKET_ERROR;
7479 sys_accept (int s, struct sockaddr * addr, int * addrlen)
7481 if (winsock_lib == NULL)
7483 errno = ENETDOWN;
7484 return -1;
7487 check_errno ();
7488 if (fd_info[s].flags & FILE_LISTEN)
7490 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
7491 int fd = -1;
7492 if (t == INVALID_SOCKET)
7493 set_errno ();
7494 else
7495 fd = socket_to_fd (t);
7497 if (fd >= 0)
7499 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
7500 ResetEvent (fd_info[s].cp->char_avail);
7502 return fd;
7504 errno = ENOTSOCK;
7505 return -1;
7509 sys_recvfrom (int s, char * buf, int len, int flags,
7510 struct sockaddr * from, int * fromlen)
7512 if (winsock_lib == NULL)
7514 errno = ENETDOWN;
7515 return SOCKET_ERROR;
7518 check_errno ();
7519 if (fd_info[s].flags & FILE_SOCKET)
7521 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
7522 if (rc == SOCKET_ERROR)
7523 set_errno ();
7524 return rc;
7526 errno = ENOTSOCK;
7527 return SOCKET_ERROR;
7531 sys_sendto (int s, const char * buf, int len, int flags,
7532 const struct sockaddr * to, int tolen)
7534 if (winsock_lib == NULL)
7536 errno = ENETDOWN;
7537 return SOCKET_ERROR;
7540 check_errno ();
7541 if (fd_info[s].flags & FILE_SOCKET)
7543 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
7544 if (rc == SOCKET_ERROR)
7545 set_errno ();
7546 return rc;
7548 errno = ENOTSOCK;
7549 return SOCKET_ERROR;
7552 /* Windows does not have an fcntl function. Provide an implementation
7553 good enough for Emacs. */
7555 fcntl (int s, int cmd, int options)
7557 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
7558 invoked in a context where fd1 is closed and all descriptors less
7559 than fd1 are open, so sys_dup is an adequate implementation. */
7560 if (cmd == F_DUPFD_CLOEXEC)
7561 return sys_dup (s);
7563 if (winsock_lib == NULL)
7565 errno = ENETDOWN;
7566 return -1;
7569 check_errno ();
7570 if (fd_info[s].flags & FILE_SOCKET)
7572 if (cmd == F_SETFL && options == O_NONBLOCK)
7574 unsigned long nblock = 1;
7575 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
7576 if (rc == SOCKET_ERROR)
7577 set_errno ();
7578 /* Keep track of the fact that we set this to non-blocking. */
7579 fd_info[s].flags |= FILE_NDELAY;
7580 return rc;
7582 else
7584 errno = EINVAL;
7585 return SOCKET_ERROR;
7588 errno = ENOTSOCK;
7589 return SOCKET_ERROR;
7593 /* Shadow main io functions: we need to handle pipes and sockets more
7594 intelligently, and implement non-blocking mode as well. */
7597 sys_close (int fd)
7599 int rc;
7601 if (fd < 0)
7603 errno = EBADF;
7604 return -1;
7607 if (fd < MAXDESC && fd_info[fd].cp)
7609 child_process * cp = fd_info[fd].cp;
7611 fd_info[fd].cp = NULL;
7613 if (CHILD_ACTIVE (cp))
7615 /* if last descriptor to active child_process then cleanup */
7616 int i;
7617 for (i = 0; i < MAXDESC; i++)
7619 if (i == fd)
7620 continue;
7621 if (fd_info[i].cp == cp)
7622 break;
7624 if (i == MAXDESC)
7626 if (fd_info[fd].flags & FILE_SOCKET)
7628 if (winsock_lib == NULL) emacs_abort ();
7630 pfn_shutdown (SOCK_HANDLE (fd), 2);
7631 rc = pfn_closesocket (SOCK_HANDLE (fd));
7633 winsock_inuse--; /* count open sockets */
7635 /* If the process handle is NULL, it's either a socket
7636 or serial connection, or a subprocess that was
7637 already reaped by reap_subprocess, but whose
7638 resources were not yet freed, because its output was
7639 not fully read yet by the time it was reaped. (This
7640 usually happens with async subprocesses whose output
7641 is being read by Emacs.) Otherwise, this process was
7642 not reaped yet, so we set its FD to a negative value
7643 to make sure sys_select will eventually get to
7644 calling the SIGCHLD handler for it, which will then
7645 invoke waitpid and reap_subprocess. */
7646 if (cp->procinfo.hProcess == NULL)
7647 delete_child (cp);
7648 else
7649 cp->fd = -1;
7654 if (fd >= 0 && fd < MAXDESC)
7655 fd_info[fd].flags = 0;
7657 /* Note that sockets do not need special treatment here (at least on
7658 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
7659 closesocket is equivalent to CloseHandle, which is to be expected
7660 because socket handles are fully fledged kernel handles. */
7661 rc = _close (fd);
7663 return rc;
7667 sys_dup (int fd)
7669 int new_fd;
7671 new_fd = _dup (fd);
7672 if (new_fd >= 0 && new_fd < MAXDESC)
7674 /* duplicate our internal info as well */
7675 fd_info[new_fd] = fd_info[fd];
7677 return new_fd;
7681 sys_dup2 (int src, int dst)
7683 int rc;
7685 if (dst < 0 || dst >= MAXDESC)
7687 errno = EBADF;
7688 return -1;
7691 /* make sure we close the destination first if it's a pipe or socket */
7692 if (src != dst && fd_info[dst].flags != 0)
7693 sys_close (dst);
7695 rc = _dup2 (src, dst);
7696 if (rc == 0)
7698 /* duplicate our internal info as well */
7699 fd_info[dst] = fd_info[src];
7701 return rc;
7705 pipe2 (int * phandles, int pipe2_flags)
7707 int rc;
7708 unsigned flags;
7710 eassert (pipe2_flags == O_CLOEXEC);
7712 /* make pipe handles non-inheritable; when we spawn a child, we
7713 replace the relevant handle with an inheritable one. Also put
7714 pipes into binary mode; we will do text mode translation ourselves
7715 if required. */
7716 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
7718 if (rc == 0)
7720 /* Protect against overflow, since Windows can open more handles than
7721 our fd_info array has room for. */
7722 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
7724 _close (phandles[0]);
7725 _close (phandles[1]);
7726 errno = EMFILE;
7727 rc = -1;
7729 else
7731 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
7732 fd_info[phandles[0]].flags = flags;
7734 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
7735 fd_info[phandles[1]].flags = flags;
7739 return rc;
7742 /* Function to do blocking read of one byte, needed to implement
7743 select. It is only allowed on communication ports, sockets, or
7744 pipes. */
7746 _sys_read_ahead (int fd)
7748 child_process * cp;
7749 int rc;
7751 if (fd < 0 || fd >= MAXDESC)
7752 return STATUS_READ_ERROR;
7754 cp = fd_info[fd].cp;
7756 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7757 return STATUS_READ_ERROR;
7759 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
7760 || (fd_info[fd].flags & FILE_READ) == 0)
7762 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
7763 emacs_abort ();
7766 cp->status = STATUS_READ_IN_PROGRESS;
7768 if (fd_info[fd].flags & FILE_PIPE)
7770 rc = _read (fd, &cp->chr, sizeof (char));
7772 /* Give subprocess time to buffer some more output for us before
7773 reporting that input is available; we need this because Windows 95
7774 connects DOS programs to pipes by making the pipe appear to be
7775 the normal console stdout - as a result most DOS programs will
7776 write to stdout without buffering, ie. one character at a
7777 time. Even some W32 programs do this - "dir" in a command
7778 shell on NT is very slow if we don't do this. */
7779 if (rc > 0)
7781 int wait = w32_pipe_read_delay;
7783 if (wait > 0)
7784 Sleep (wait);
7785 else if (wait < 0)
7786 while (++wait <= 0)
7787 /* Yield remainder of our time slice, effectively giving a
7788 temporary priority boost to the child process. */
7789 Sleep (0);
7792 else if (fd_info[fd].flags & FILE_SERIAL)
7794 HANDLE hnd = fd_info[fd].hnd;
7795 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7796 COMMTIMEOUTS ct;
7798 /* Configure timeouts for blocking read. */
7799 if (!GetCommTimeouts (hnd, &ct))
7801 cp->status = STATUS_READ_ERROR;
7802 return STATUS_READ_ERROR;
7804 ct.ReadIntervalTimeout = 0;
7805 ct.ReadTotalTimeoutMultiplier = 0;
7806 ct.ReadTotalTimeoutConstant = 0;
7807 if (!SetCommTimeouts (hnd, &ct))
7809 cp->status = STATUS_READ_ERROR;
7810 return STATUS_READ_ERROR;
7813 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
7815 if (GetLastError () != ERROR_IO_PENDING)
7817 cp->status = STATUS_READ_ERROR;
7818 return STATUS_READ_ERROR;
7820 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
7822 cp->status = STATUS_READ_ERROR;
7823 return STATUS_READ_ERROR;
7827 else if (fd_info[fd].flags & FILE_SOCKET)
7829 unsigned long nblock = 0;
7830 /* We always want this to block, so temporarily disable NDELAY. */
7831 if (fd_info[fd].flags & FILE_NDELAY)
7832 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7834 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
7836 if (fd_info[fd].flags & FILE_NDELAY)
7838 nblock = 1;
7839 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7843 if (rc == sizeof (char))
7844 cp->status = STATUS_READ_SUCCEEDED;
7845 else
7846 cp->status = STATUS_READ_FAILED;
7848 return cp->status;
7852 _sys_wait_accept (int fd)
7854 HANDLE hEv;
7855 child_process * cp;
7856 int rc;
7858 if (fd < 0 || fd >= MAXDESC)
7859 return STATUS_READ_ERROR;
7861 cp = fd_info[fd].cp;
7863 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7864 return STATUS_READ_ERROR;
7866 cp->status = STATUS_READ_FAILED;
7868 hEv = pfn_WSACreateEvent ();
7869 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
7870 if (rc != SOCKET_ERROR)
7872 do {
7873 rc = WaitForSingleObject (hEv, 500);
7874 Sleep (5);
7875 } while (rc == WAIT_TIMEOUT
7876 && cp->status != STATUS_READ_ERROR
7877 && cp->char_avail);
7878 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
7879 if (rc == WAIT_OBJECT_0)
7880 cp->status = STATUS_READ_SUCCEEDED;
7882 pfn_WSACloseEvent (hEv);
7884 return cp->status;
7888 sys_read (int fd, char * buffer, unsigned int count)
7890 int nchars;
7891 int to_read;
7892 DWORD waiting;
7893 char * orig_buffer = buffer;
7895 if (fd < 0)
7897 errno = EBADF;
7898 return -1;
7901 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
7903 child_process *cp = fd_info[fd].cp;
7905 if ((fd_info[fd].flags & FILE_READ) == 0)
7907 errno = EBADF;
7908 return -1;
7911 nchars = 0;
7913 /* re-read CR carried over from last read */
7914 if (fd_info[fd].flags & FILE_LAST_CR)
7916 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
7917 *buffer++ = 0x0d;
7918 count--;
7919 nchars++;
7920 fd_info[fd].flags &= ~FILE_LAST_CR;
7923 /* presence of a child_process structure means we are operating in
7924 non-blocking mode - otherwise we just call _read directly.
7925 Note that the child_process structure might be missing because
7926 reap_subprocess has been called; in this case the pipe is
7927 already broken, so calling _read on it is okay. */
7928 if (cp)
7930 int current_status = cp->status;
7932 switch (current_status)
7934 case STATUS_READ_FAILED:
7935 case STATUS_READ_ERROR:
7936 /* report normal EOF if nothing in buffer */
7937 if (nchars <= 0)
7938 fd_info[fd].flags |= FILE_AT_EOF;
7939 return nchars;
7941 case STATUS_READ_READY:
7942 case STATUS_READ_IN_PROGRESS:
7943 DebPrint (("sys_read called when read is in progress\n"));
7944 errno = EWOULDBLOCK;
7945 return -1;
7947 case STATUS_READ_SUCCEEDED:
7948 /* consume read-ahead char */
7949 *buffer++ = cp->chr;
7950 count--;
7951 nchars++;
7952 cp->status = STATUS_READ_ACKNOWLEDGED;
7953 ResetEvent (cp->char_avail);
7955 case STATUS_READ_ACKNOWLEDGED:
7956 break;
7958 default:
7959 DebPrint (("sys_read: bad status %d\n", current_status));
7960 errno = EBADF;
7961 return -1;
7964 if (fd_info[fd].flags & FILE_PIPE)
7966 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
7967 to_read = min (waiting, (DWORD) count);
7969 if (to_read > 0)
7970 nchars += _read (fd, buffer, to_read);
7972 else if (fd_info[fd].flags & FILE_SERIAL)
7974 HANDLE hnd = fd_info[fd].hnd;
7975 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7976 int rc = 0;
7977 COMMTIMEOUTS ct;
7979 if (count > 0)
7981 /* Configure timeouts for non-blocking read. */
7982 if (!GetCommTimeouts (hnd, &ct))
7984 errno = EIO;
7985 return -1;
7987 ct.ReadIntervalTimeout = MAXDWORD;
7988 ct.ReadTotalTimeoutMultiplier = 0;
7989 ct.ReadTotalTimeoutConstant = 0;
7990 if (!SetCommTimeouts (hnd, &ct))
7992 errno = EIO;
7993 return -1;
7996 if (!ResetEvent (ovl->hEvent))
7998 errno = EIO;
7999 return -1;
8001 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8003 if (GetLastError () != ERROR_IO_PENDING)
8005 errno = EIO;
8006 return -1;
8008 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8010 errno = EIO;
8011 return -1;
8014 nchars += rc;
8017 else /* FILE_SOCKET */
8019 if (winsock_lib == NULL) emacs_abort ();
8021 /* do the equivalent of a non-blocking read */
8022 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8023 if (waiting == 0 && nchars == 0)
8025 errno = EWOULDBLOCK;
8026 return -1;
8029 if (waiting)
8031 /* always use binary mode for sockets */
8032 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8033 if (res == SOCKET_ERROR)
8035 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8036 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8037 set_errno ();
8038 return -1;
8040 nchars += res;
8044 else
8046 int nread = _read (fd, buffer, count);
8047 if (nread >= 0)
8048 nchars += nread;
8049 else if (nchars == 0)
8050 nchars = nread;
8053 if (nchars <= 0)
8054 fd_info[fd].flags |= FILE_AT_EOF;
8055 /* Perform text mode translation if required. */
8056 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8058 nchars = crlf_to_lf (nchars, orig_buffer);
8059 /* If buffer contains only CR, return that. To be absolutely
8060 sure we should attempt to read the next char, but in
8061 practice a CR to be followed by LF would not appear by
8062 itself in the buffer. */
8063 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8065 fd_info[fd].flags |= FILE_LAST_CR;
8066 nchars--;
8070 else
8071 nchars = _read (fd, buffer, count);
8073 return nchars;
8076 /* From w32xfns.c */
8077 extern HANDLE interrupt_handle;
8079 /* For now, don't bother with a non-blocking mode */
8081 sys_write (int fd, const void * buffer, unsigned int count)
8083 int nchars;
8085 if (fd < 0)
8087 errno = EBADF;
8088 return -1;
8091 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8093 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8095 errno = EBADF;
8096 return -1;
8099 /* Perform text mode translation if required. */
8100 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8102 char * tmpbuf = alloca (count * 2);
8103 unsigned char * src = (void *)buffer;
8104 unsigned char * dst = tmpbuf;
8105 int nbytes = count;
8107 while (1)
8109 unsigned char *next;
8110 /* copy next line or remaining bytes */
8111 next = _memccpy (dst, src, '\n', nbytes);
8112 if (next)
8114 /* copied one line ending with '\n' */
8115 int copied = next - dst;
8116 nbytes -= copied;
8117 src += copied;
8118 /* insert '\r' before '\n' */
8119 next[-1] = '\r';
8120 next[0] = '\n';
8121 dst = next + 1;
8122 count++;
8124 else
8125 /* copied remaining partial line -> now finished */
8126 break;
8128 buffer = tmpbuf;
8132 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8134 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8135 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8136 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8137 DWORD active = 0;
8139 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8141 if (GetLastError () != ERROR_IO_PENDING)
8143 errno = EIO;
8144 return -1;
8146 if (detect_input_pending ())
8147 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
8148 QS_ALLINPUT);
8149 else
8150 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8151 if (active == WAIT_OBJECT_0)
8152 { /* User pressed C-g, cancel write, then leave. Don't bother
8153 cleaning up as we may only get stuck in buggy drivers. */
8154 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8155 CancelIo (hnd);
8156 errno = EIO;
8157 return -1;
8159 if (active == WAIT_OBJECT_0 + 1
8160 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8162 errno = EIO;
8163 return -1;
8167 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8169 unsigned long nblock = 0;
8170 if (winsock_lib == NULL) emacs_abort ();
8172 /* TODO: implement select() properly so non-blocking I/O works. */
8173 /* For now, make sure the write blocks. */
8174 if (fd_info[fd].flags & FILE_NDELAY)
8175 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8177 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
8179 /* Set the socket back to non-blocking if it was before,
8180 for other operations that support it. */
8181 if (fd_info[fd].flags & FILE_NDELAY)
8183 nblock = 1;
8184 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8187 if (nchars == SOCKET_ERROR)
8189 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
8190 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8191 set_errno ();
8194 else
8196 /* Some networked filesystems don't like too large writes, so
8197 break them into smaller chunks. See the Comments section of
8198 the MSDN documentation of WriteFile for details behind the
8199 choice of the value of CHUNK below. See also the thread
8200 http://thread.gmane.org/gmane.comp.version-control.git/145294
8201 in the git mailing list. */
8202 const unsigned char *p = buffer;
8203 const unsigned chunk = 30 * 1024 * 1024;
8205 nchars = 0;
8206 while (count > 0)
8208 unsigned this_chunk = count < chunk ? count : chunk;
8209 int n = _write (fd, p, this_chunk);
8211 nchars += n;
8212 if (n < 0)
8214 nchars = n;
8215 break;
8217 else if (n < this_chunk)
8218 break;
8219 count -= n;
8220 p += n;
8224 return nchars;
8228 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
8230 extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
8232 /* Return information about network interface IFNAME, or about all
8233 interfaces (if IFNAME is nil). */
8234 static Lisp_Object
8235 network_interface_get_info (Lisp_Object ifname)
8237 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
8238 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
8239 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
8240 Lisp_Object res = Qnil;
8242 if (retval == ERROR_BUFFER_OVERFLOW)
8244 ainfo = xrealloc (ainfo, ainfo_len);
8245 retval = get_adapters_info (ainfo, &ainfo_len);
8248 if (retval == ERROR_SUCCESS)
8250 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
8251 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
8252 int if_num;
8253 struct sockaddr_in sa;
8255 /* For the below, we need some winsock functions, so make sure
8256 the winsock DLL is loaded. If we cannot successfully load
8257 it, they will have no use of the information we provide,
8258 anyway, so punt. */
8259 if (!winsock_lib && !init_winsock (1))
8260 goto done;
8262 for (adapter = ainfo; adapter; adapter = adapter->Next)
8264 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
8265 u_long ip_addr;
8266 /* Present Unix-compatible interface names, instead of the
8267 Windows names, which are really GUIDs not readable by
8268 humans. */
8269 static const char *ifmt[] = {
8270 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
8271 "lo", "ifx%d"
8273 enum {
8274 NONE = -1,
8275 ETHERNET = 0,
8276 TOKENRING = 1,
8277 FDDI = 2,
8278 PPP = 3,
8279 SLIP = 4,
8280 WLAN = 5,
8281 LOOPBACK = 6,
8282 OTHER_IF = 7
8283 } ifmt_idx;
8285 switch (adapter->Type)
8287 case MIB_IF_TYPE_ETHERNET:
8288 /* Windows before Vista reports wireless adapters as
8289 Ethernet. Work around by looking at the Description
8290 string. */
8291 if (strstr (adapter->Description, "Wireless "))
8293 ifmt_idx = WLAN;
8294 if_num = wlan_count++;
8296 else
8298 ifmt_idx = ETHERNET;
8299 if_num = eth_count++;
8301 break;
8302 case MIB_IF_TYPE_TOKENRING:
8303 ifmt_idx = TOKENRING;
8304 if_num = tr_count++;
8305 break;
8306 case MIB_IF_TYPE_FDDI:
8307 ifmt_idx = FDDI;
8308 if_num = fddi_count++;
8309 break;
8310 case MIB_IF_TYPE_PPP:
8311 ifmt_idx = PPP;
8312 if_num = ppp_count++;
8313 break;
8314 case MIB_IF_TYPE_SLIP:
8315 ifmt_idx = SLIP;
8316 if_num = sl_count++;
8317 break;
8318 case IF_TYPE_IEEE80211:
8319 ifmt_idx = WLAN;
8320 if_num = wlan_count++;
8321 break;
8322 case MIB_IF_TYPE_LOOPBACK:
8323 if (lo_count < 0)
8325 ifmt_idx = LOOPBACK;
8326 if_num = lo_count++;
8328 else
8329 ifmt_idx = NONE;
8330 break;
8331 default:
8332 ifmt_idx = OTHER_IF;
8333 if_num = ifx_count++;
8334 break;
8336 if (ifmt_idx == NONE)
8337 continue;
8338 sprintf (namebuf, ifmt[ifmt_idx], if_num);
8340 sa.sin_family = AF_INET;
8341 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
8342 if (ip_addr == INADDR_NONE)
8344 /* Bogus address, skip this interface. */
8345 continue;
8347 sa.sin_addr.s_addr = ip_addr;
8348 sa.sin_port = 0;
8349 if (NILP (ifname))
8350 res = Fcons (Fcons (build_string (namebuf),
8351 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
8352 sizeof (struct sockaddr))),
8353 res);
8354 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
8356 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
8357 register struct Lisp_Vector *p = XVECTOR (hwaddr);
8358 Lisp_Object flags = Qnil;
8359 int n;
8360 u_long net_mask;
8362 /* Flags. We guess most of them by type, since the
8363 Windows flags are different and hard to get by. */
8364 flags = Fcons (intern ("up"), flags);
8365 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
8367 flags = Fcons (intern ("broadcast"), flags);
8368 flags = Fcons (intern ("multicast"), flags);
8370 flags = Fcons (intern ("running"), flags);
8371 if (ifmt_idx == PPP)
8373 flags = Fcons (intern ("pointopoint"), flags);
8374 flags = Fcons (intern ("noarp"), flags);
8376 if (adapter->HaveWins)
8377 flags = Fcons (intern ("WINS"), flags);
8378 if (adapter->DhcpEnabled)
8379 flags = Fcons (intern ("dynamic"), flags);
8381 res = Fcons (flags, res);
8383 /* Hardware address and its family. */
8384 for (n = 0; n < adapter->AddressLength; n++)
8385 p->contents[n] = make_number ((int) adapter->Address[n]);
8386 /* Windows does not support AF_LINK or AF_PACKET family
8387 of addresses. Use an arbitrary family number that is
8388 identical to what GNU/Linux returns. */
8389 res = Fcons (Fcons (make_number (1), hwaddr), res);
8391 /* Network mask. */
8392 sa.sin_family = AF_INET;
8393 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
8394 if (net_mask != INADDR_NONE)
8396 sa.sin_addr.s_addr = net_mask;
8397 sa.sin_port = 0;
8398 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8399 sizeof (struct sockaddr)),
8400 res);
8402 else
8403 res = Fcons (Qnil, res);
8405 sa.sin_family = AF_INET;
8406 if (ip_addr != INADDR_NONE)
8408 /* Broadcast address is only reported by
8409 GetAdaptersAddresses, which is of limited
8410 availability. Generate it on our own. */
8411 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
8413 sa.sin_addr.s_addr = bcast_addr;
8414 sa.sin_port = 0;
8415 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8416 sizeof (struct sockaddr)),
8417 res);
8419 /* IP address. */
8420 sa.sin_addr.s_addr = ip_addr;
8421 sa.sin_port = 0;
8422 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8423 sizeof (struct sockaddr)),
8424 res);
8426 else
8427 res = Fcons (Qnil, Fcons (Qnil, res));
8430 /* GetAdaptersInfo is documented to not report loopback
8431 interfaces, so we generate one out of thin air. */
8432 if (!lo_count)
8434 sa.sin_family = AF_INET;
8435 sa.sin_port = 0;
8436 if (NILP (ifname))
8438 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
8439 res = Fcons (Fcons (build_string ("lo"),
8440 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
8441 sizeof (struct sockaddr))),
8442 res);
8444 else if (strcmp (SSDATA (ifname), "lo") == 0)
8446 res = Fcons (Fcons (intern ("running"),
8447 Fcons (intern ("loopback"),
8448 Fcons (intern ("up"), Qnil))), Qnil);
8449 /* 772 is what 3 different GNU/Linux systems report for
8450 the loopback interface. */
8451 res = Fcons (Fcons (make_number (772),
8452 Fmake_vector (make_number (6),
8453 make_number (0))),
8454 res);
8455 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
8456 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8457 sizeof (struct sockaddr)),
8458 res);
8459 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
8460 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8461 sizeof (struct sockaddr)),
8462 res);
8463 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
8464 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8465 sizeof (struct sockaddr)),
8466 res);
8472 done:
8473 xfree (ainfo);
8474 return res;
8477 Lisp_Object
8478 network_interface_list (void)
8480 return network_interface_get_info (Qnil);
8483 Lisp_Object
8484 network_interface_info (Lisp_Object ifname)
8486 return network_interface_get_info (ifname);
8490 /* The Windows CRT functions are "optimized for speed", so they don't
8491 check for timezone and DST changes if they were last called less
8492 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
8493 all Emacs features that repeatedly call time functions (e.g.,
8494 display-time) are in real danger of missing timezone and DST
8495 changes. Calling tzset before each localtime call fixes that. */
8496 struct tm *
8497 sys_localtime (const time_t *t)
8499 tzset ();
8500 return localtime (t);
8505 /* Try loading LIBRARY_ID from the file(s) specified in
8506 Vdynamic_library_alist. If the library is loaded successfully,
8507 return the handle of the DLL, and record the filename in the
8508 property :loaded-from of LIBRARY_ID. If the library could not be
8509 found, or when it was already loaded (because the handle is not
8510 recorded anywhere, and so is lost after use), return NULL.
8512 We could also save the handle in :loaded-from, but currently
8513 there's no use case for it. */
8514 HMODULE
8515 w32_delayed_load (Lisp_Object library_id)
8517 HMODULE dll_handle = NULL;
8519 CHECK_SYMBOL (library_id);
8521 if (CONSP (Vdynamic_library_alist)
8522 && NILP (Fassq (library_id, Vlibrary_cache)))
8524 Lisp_Object found = Qnil;
8525 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
8527 if (CONSP (dlls))
8528 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
8530 Lisp_Object dll = XCAR (dlls);
8531 char name[MAX_UTF8_PATH];
8532 DWORD res = -1;
8534 CHECK_STRING (dll);
8535 dll = ENCODE_FILE (dll);
8536 if (w32_unicode_filenames)
8538 wchar_t name_w[MAX_PATH];
8540 filename_to_utf16 (SSDATA (dll), name_w);
8541 dll_handle = LoadLibraryW (name_w);
8542 if (dll_handle)
8544 res = GetModuleFileNameW (dll_handle, name_w,
8545 sizeof (name_w));
8546 if (res > 0)
8547 filename_from_utf16 (name_w, name);
8550 else
8552 char name_a[MAX_PATH];
8554 filename_to_ansi (SSDATA (dll), name_a);
8555 dll_handle = LoadLibraryA (name_a);
8556 if (dll_handle)
8558 res = GetModuleFileNameA (dll_handle, name_a,
8559 sizeof (name_a));
8560 if (res > 0)
8561 filename_from_ansi (name_a, name);
8564 if (dll_handle)
8566 ptrdiff_t len = strlen (name);
8567 found = Fcons (dll,
8568 (res > 0)
8569 /* Possibly truncated */
8570 ? make_specified_string (name, -1, len, 1)
8571 : Qnil);
8572 break;
8576 Fput (library_id, QCloaded_from, found);
8579 return dll_handle;
8583 void
8584 check_windows_init_file (void)
8586 /* A common indication that Emacs is not installed properly is when
8587 it cannot find the Windows installation file. If this file does
8588 not exist in the expected place, tell the user. */
8590 if (!noninteractive && !inhibit_window_system
8591 /* Vload_path is not yet initialized when we are loading
8592 loadup.el. */
8593 && NILP (Vpurify_flag))
8595 Lisp_Object init_file;
8596 int fd;
8598 /* Implementation note: this function runs early during Emacs
8599 startup, before startup.el is run. So Vload_path is still in
8600 its initial unibyte form, but it holds UTF-8 encoded file
8601 names, since init_callproc was already called. So we do not
8602 need to ENCODE_FILE here, but we do need to convert the file
8603 names from UTF-8 to ANSI. */
8604 init_file = build_string ("term/w32-win");
8605 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
8606 if (fd < 0)
8608 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
8609 char *init_file_name = SDATA (init_file);
8610 char *load_path = SDATA (load_path_print);
8611 char *buffer = alloca (1024
8612 + strlen (init_file_name)
8613 + strlen (load_path));
8614 char *msg = buffer;
8615 int needed;
8617 sprintf (buffer,
8618 "The Emacs Windows initialization file \"%s.el\" "
8619 "could not be found in your Emacs installation. "
8620 "Emacs checked the following directories for this file:\n"
8621 "\n%s\n\n"
8622 "When Emacs cannot find this file, it usually means that it "
8623 "was not installed properly, or its distribution file was "
8624 "not unpacked properly.\nSee the README.W32 file in the "
8625 "top-level Emacs directory for more information.",
8626 init_file_name, load_path);
8627 needed = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
8628 -1, NULL, 0);
8629 if (needed > 0)
8631 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
8633 MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
8634 msg_w, needed);
8635 needed = WideCharToMultiByte (CP_ACP, 0, msg_w, -1,
8636 NULL, 0, NULL, NULL);
8637 if (needed > 0)
8639 char *msg_a = alloca (needed + 1);
8641 WideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
8642 NULL, NULL);
8643 msg = msg_a;
8646 MessageBox (NULL,
8647 msg,
8648 "Emacs Abort Dialog",
8649 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
8650 /* Use the low-level system abort. */
8651 abort ();
8653 else
8655 _close (fd);
8660 void
8661 term_ntproc (int ignored)
8663 (void)ignored;
8665 term_timers ();
8667 /* shutdown the socket interface if necessary */
8668 term_winsock ();
8670 term_w32select ();
8673 void
8674 init_ntproc (int dumping)
8676 sigset_t initial_mask = 0;
8678 /* Initialize the socket interface now if available and requested by
8679 the user by defining PRELOAD_WINSOCK; otherwise loading will be
8680 delayed until open-network-stream is called (w32-has-winsock can
8681 also be used to dynamically load or reload winsock).
8683 Conveniently, init_environment is called before us, so
8684 PRELOAD_WINSOCK can be set in the registry. */
8686 /* Always initialize this correctly. */
8687 winsock_lib = NULL;
8689 if (getenv ("PRELOAD_WINSOCK") != NULL)
8690 init_winsock (TRUE);
8692 /* Initial preparation for subprocess support: replace our standard
8693 handles with non-inheritable versions. */
8695 HANDLE parent;
8696 HANDLE stdin_save = INVALID_HANDLE_VALUE;
8697 HANDLE stdout_save = INVALID_HANDLE_VALUE;
8698 HANDLE stderr_save = INVALID_HANDLE_VALUE;
8700 parent = GetCurrentProcess ();
8702 /* ignore errors when duplicating and closing; typically the
8703 handles will be invalid when running as a gui program. */
8704 DuplicateHandle (parent,
8705 GetStdHandle (STD_INPUT_HANDLE),
8706 parent,
8707 &stdin_save,
8709 FALSE,
8710 DUPLICATE_SAME_ACCESS);
8712 DuplicateHandle (parent,
8713 GetStdHandle (STD_OUTPUT_HANDLE),
8714 parent,
8715 &stdout_save,
8717 FALSE,
8718 DUPLICATE_SAME_ACCESS);
8720 DuplicateHandle (parent,
8721 GetStdHandle (STD_ERROR_HANDLE),
8722 parent,
8723 &stderr_save,
8725 FALSE,
8726 DUPLICATE_SAME_ACCESS);
8728 fclose (stdin);
8729 fclose (stdout);
8730 fclose (stderr);
8732 if (stdin_save != INVALID_HANDLE_VALUE)
8733 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
8734 else
8735 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
8736 _fdopen (0, "r");
8738 if (stdout_save != INVALID_HANDLE_VALUE)
8739 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
8740 else
8741 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8742 _fdopen (1, "w");
8744 if (stderr_save != INVALID_HANDLE_VALUE)
8745 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
8746 else
8747 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8748 _fdopen (2, "w");
8751 /* unfortunately, atexit depends on implementation of malloc */
8752 /* atexit (term_ntproc); */
8753 if (!dumping)
8755 /* Make sure we start with all signals unblocked. */
8756 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
8757 signal (SIGABRT, term_ntproc);
8759 init_timers ();
8761 /* determine which drives are fixed, for GetCachedVolumeInformation */
8763 /* GetDriveType must have trailing backslash. */
8764 char drive[] = "A:\\";
8766 /* Loop over all possible drive letters */
8767 while (*drive <= 'Z')
8769 /* Record if this drive letter refers to a fixed drive. */
8770 fixed_drives[DRIVE_INDEX (*drive)] =
8771 (GetDriveType (drive) == DRIVE_FIXED);
8773 (*drive)++;
8776 /* Reset the volume info cache. */
8777 volume_cache = NULL;
8782 shutdown_handler ensures that buffers' autosave files are
8783 up to date when the user logs off, or the system shuts down.
8785 static BOOL WINAPI
8786 shutdown_handler (DWORD type)
8788 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
8789 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
8790 || type == CTRL_LOGOFF_EVENT /* User logs off. */
8791 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
8793 /* Shut down cleanly, making sure autosave files are up to date. */
8794 shut_down_emacs (0, Qnil);
8797 /* Allow other handlers to handle this signal. */
8798 return FALSE;
8802 globals_of_w32 is used to initialize those global variables that
8803 must always be initialized on startup even when the global variable
8804 initialized is non zero (see the function main in emacs.c).
8806 void
8807 globals_of_w32 (void)
8809 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
8811 get_process_times_fn = (GetProcessTimes_Proc)
8812 GetProcAddress (kernel32, "GetProcessTimes");
8814 DEFSYM (QCloaded_from, ":loaded-from");
8816 g_b_init_is_windows_9x = 0;
8817 g_b_init_open_process_token = 0;
8818 g_b_init_get_token_information = 0;
8819 g_b_init_lookup_account_sid = 0;
8820 g_b_init_get_sid_sub_authority = 0;
8821 g_b_init_get_sid_sub_authority_count = 0;
8822 g_b_init_get_security_info = 0;
8823 g_b_init_get_file_security_w = 0;
8824 g_b_init_get_file_security_a = 0;
8825 g_b_init_get_security_descriptor_owner = 0;
8826 g_b_init_get_security_descriptor_group = 0;
8827 g_b_init_is_valid_sid = 0;
8828 g_b_init_create_toolhelp32_snapshot = 0;
8829 g_b_init_process32_first = 0;
8830 g_b_init_process32_next = 0;
8831 g_b_init_open_thread_token = 0;
8832 g_b_init_impersonate_self = 0;
8833 g_b_init_revert_to_self = 0;
8834 g_b_init_get_process_memory_info = 0;
8835 g_b_init_get_process_working_set_size = 0;
8836 g_b_init_global_memory_status = 0;
8837 g_b_init_global_memory_status_ex = 0;
8838 g_b_init_equal_sid = 0;
8839 g_b_init_copy_sid = 0;
8840 g_b_init_get_length_sid = 0;
8841 g_b_init_get_native_system_info = 0;
8842 g_b_init_get_system_times = 0;
8843 g_b_init_create_symbolic_link_w = 0;
8844 g_b_init_create_symbolic_link_a = 0;
8845 g_b_init_get_security_descriptor_dacl = 0;
8846 g_b_init_convert_sd_to_sddl = 0;
8847 g_b_init_convert_sddl_to_sd = 0;
8848 g_b_init_is_valid_security_descriptor = 0;
8849 g_b_init_set_file_security_w = 0;
8850 g_b_init_set_file_security_a = 0;
8851 g_b_init_get_adapters_info = 0;
8852 num_of_processors = 0;
8853 /* The following sets a handler for shutdown notifications for
8854 console apps. This actually applies to Emacs in both console and
8855 GUI modes, since we had to fool windows into thinking emacs is a
8856 console application to get console mode to work. */
8857 SetConsoleCtrlHandler (shutdown_handler, TRUE);
8859 /* "None" is the default group name on standalone workstations. */
8860 strcpy (dflt_group_name, "None");
8862 /* Reset, in case it has some value inherited from dump time. */
8863 w32_stat_get_owner_group = 0;
8865 /* If w32_unicode_filenames is non-zero, we will be using Unicode
8866 (a.k.a. "wide") APIs to invoke functions that accept file
8867 names. */
8868 if (is_windows_9x ())
8869 w32_unicode_filenames = 0;
8870 else
8871 w32_unicode_filenames = 1;
8874 /* For make-serial-process */
8876 serial_open (Lisp_Object port_obj)
8878 char *port = SSDATA (port_obj);
8879 HANDLE hnd;
8880 child_process *cp;
8881 int fd = -1;
8883 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
8884 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
8885 if (hnd == INVALID_HANDLE_VALUE)
8886 error ("Could not open %s", port);
8887 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
8888 if (fd == -1)
8889 error ("Could not open %s", port);
8891 cp = new_child ();
8892 if (!cp)
8893 error ("Could not create child process");
8894 cp->fd = fd;
8895 cp->status = STATUS_READ_ACKNOWLEDGED;
8896 fd_info[ fd ].hnd = hnd;
8897 fd_info[ fd ].flags |=
8898 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
8899 if (fd_info[ fd ].cp != NULL)
8901 error ("fd_info[fd = %d] is already in use", fd);
8903 fd_info[ fd ].cp = cp;
8904 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
8905 if (cp->ovl_read.hEvent == NULL)
8906 error ("Could not create read event");
8907 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
8908 if (cp->ovl_write.hEvent == NULL)
8909 error ("Could not create write event");
8911 return fd;
8914 /* For serial-process-configure */
8915 void
8916 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
8918 Lisp_Object childp2 = Qnil;
8919 Lisp_Object tem = Qnil;
8920 HANDLE hnd;
8921 DCB dcb;
8922 COMMTIMEOUTS ct;
8923 char summary[4] = "???"; /* This usually becomes "8N1". */
8925 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
8926 error ("Not a serial process");
8927 hnd = fd_info[ p->outfd ].hnd;
8929 childp2 = Fcopy_sequence (p->childp);
8931 /* Initialize timeouts for blocking read and blocking write. */
8932 if (!GetCommTimeouts (hnd, &ct))
8933 error ("GetCommTimeouts() failed");
8934 ct.ReadIntervalTimeout = 0;
8935 ct.ReadTotalTimeoutMultiplier = 0;
8936 ct.ReadTotalTimeoutConstant = 0;
8937 ct.WriteTotalTimeoutMultiplier = 0;
8938 ct.WriteTotalTimeoutConstant = 0;
8939 if (!SetCommTimeouts (hnd, &ct))
8940 error ("SetCommTimeouts() failed");
8941 /* Read port attributes and prepare default configuration. */
8942 memset (&dcb, 0, sizeof (dcb));
8943 dcb.DCBlength = sizeof (DCB);
8944 if (!GetCommState (hnd, &dcb))
8945 error ("GetCommState() failed");
8946 dcb.fBinary = TRUE;
8947 dcb.fNull = FALSE;
8948 dcb.fAbortOnError = FALSE;
8949 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
8950 dcb.ErrorChar = 0;
8951 dcb.EofChar = 0;
8952 dcb.EvtChar = 0;
8954 /* Configure speed. */
8955 if (!NILP (Fplist_member (contact, QCspeed)))
8956 tem = Fplist_get (contact, QCspeed);
8957 else
8958 tem = Fplist_get (p->childp, QCspeed);
8959 CHECK_NUMBER (tem);
8960 dcb.BaudRate = XINT (tem);
8961 childp2 = Fplist_put (childp2, QCspeed, tem);
8963 /* Configure bytesize. */
8964 if (!NILP (Fplist_member (contact, QCbytesize)))
8965 tem = Fplist_get (contact, QCbytesize);
8966 else
8967 tem = Fplist_get (p->childp, QCbytesize);
8968 if (NILP (tem))
8969 tem = make_number (8);
8970 CHECK_NUMBER (tem);
8971 if (XINT (tem) != 7 && XINT (tem) != 8)
8972 error (":bytesize must be nil (8), 7, or 8");
8973 dcb.ByteSize = XINT (tem);
8974 summary[0] = XINT (tem) + '0';
8975 childp2 = Fplist_put (childp2, QCbytesize, tem);
8977 /* Configure parity. */
8978 if (!NILP (Fplist_member (contact, QCparity)))
8979 tem = Fplist_get (contact, QCparity);
8980 else
8981 tem = Fplist_get (p->childp, QCparity);
8982 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
8983 error (":parity must be nil (no parity), `even', or `odd'");
8984 dcb.fParity = FALSE;
8985 dcb.Parity = NOPARITY;
8986 dcb.fErrorChar = FALSE;
8987 if (NILP (tem))
8989 summary[1] = 'N';
8991 else if (EQ (tem, Qeven))
8993 summary[1] = 'E';
8994 dcb.fParity = TRUE;
8995 dcb.Parity = EVENPARITY;
8996 dcb.fErrorChar = TRUE;
8998 else if (EQ (tem, Qodd))
9000 summary[1] = 'O';
9001 dcb.fParity = TRUE;
9002 dcb.Parity = ODDPARITY;
9003 dcb.fErrorChar = TRUE;
9005 childp2 = Fplist_put (childp2, QCparity, tem);
9007 /* Configure stopbits. */
9008 if (!NILP (Fplist_member (contact, QCstopbits)))
9009 tem = Fplist_get (contact, QCstopbits);
9010 else
9011 tem = Fplist_get (p->childp, QCstopbits);
9012 if (NILP (tem))
9013 tem = make_number (1);
9014 CHECK_NUMBER (tem);
9015 if (XINT (tem) != 1 && XINT (tem) != 2)
9016 error (":stopbits must be nil (1 stopbit), 1, or 2");
9017 summary[2] = XINT (tem) + '0';
9018 if (XINT (tem) == 1)
9019 dcb.StopBits = ONESTOPBIT;
9020 else if (XINT (tem) == 2)
9021 dcb.StopBits = TWOSTOPBITS;
9022 childp2 = Fplist_put (childp2, QCstopbits, tem);
9024 /* Configure flowcontrol. */
9025 if (!NILP (Fplist_member (contact, QCflowcontrol)))
9026 tem = Fplist_get (contact, QCflowcontrol);
9027 else
9028 tem = Fplist_get (p->childp, QCflowcontrol);
9029 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
9030 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
9031 dcb.fOutxCtsFlow = FALSE;
9032 dcb.fOutxDsrFlow = FALSE;
9033 dcb.fDtrControl = DTR_CONTROL_DISABLE;
9034 dcb.fDsrSensitivity = FALSE;
9035 dcb.fTXContinueOnXoff = FALSE;
9036 dcb.fOutX = FALSE;
9037 dcb.fInX = FALSE;
9038 dcb.fRtsControl = RTS_CONTROL_DISABLE;
9039 dcb.XonChar = 17; /* Control-Q */
9040 dcb.XoffChar = 19; /* Control-S */
9041 if (NILP (tem))
9043 /* Already configured. */
9045 else if (EQ (tem, Qhw))
9047 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
9048 dcb.fOutxCtsFlow = TRUE;
9050 else if (EQ (tem, Qsw))
9052 dcb.fOutX = TRUE;
9053 dcb.fInX = TRUE;
9055 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
9057 /* Activate configuration. */
9058 if (!SetCommState (hnd, &dcb))
9059 error ("SetCommState() failed");
9061 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
9062 pset_childp (p, childp2);
9065 #ifdef HAVE_GNUTLS
9067 ssize_t
9068 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
9070 int n, err;
9071 SELECT_TYPE fdset;
9072 struct timespec timeout;
9073 struct Lisp_Process *process = (struct Lisp_Process *)p;
9074 int fd = process->infd;
9076 n = sys_read (fd, (char*)buf, sz);
9078 if (n >= 0)
9079 return n;
9081 err = errno;
9083 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9084 if (err == EWOULDBLOCK)
9085 err = EAGAIN;
9087 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
9089 return -1;
9092 ssize_t
9093 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
9095 struct Lisp_Process *process = (struct Lisp_Process *)p;
9096 int fd = process->outfd;
9097 ssize_t n = sys_write (fd, buf, sz);
9099 /* 0 or more bytes written means everything went fine. */
9100 if (n >= 0)
9101 return n;
9103 /* Negative bytes written means we got an error in errno.
9104 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9105 emacs_gnutls_transport_set_errno (process->gnutls_state,
9106 errno == EWOULDBLOCK ? EAGAIN : errno);
9108 return -1;
9110 #endif /* HAVE_GNUTLS */
9112 /* end of w32.c */