ediff-fixup-patch-map: Improve prompt
[emacs.git] / src / w32.c
blobfa7fec700c6c2b697f6b9a6c1eb5d3ff361c5b2d
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
3 Copyright (C) 1994-1995, 2000-2016 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
24 #define DEFER_MS_W32_H
25 #include <config.h>
27 #include <mingw_time.h>
28 #include <stddef.h> /* for offsetof */
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <float.h> /* for DBL_EPSILON */
32 #include <io.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <ctype.h>
36 #include <signal.h>
37 #include <sys/file.h>
38 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
39 #include <sys/time.h>
40 #include <sys/utime.h>
41 #include <math.h>
43 /* Include (most) CRT headers *before* ms-w32.h. */
44 #include <ms-w32.h>
46 #include <string.h> /* for strerror, needed by sys_strerror */
47 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
49 #undef access
50 #undef chdir
51 #undef chmod
52 #undef creat
53 #undef ctime
54 #undef fopen
55 #undef link
56 #undef mkdir
57 #undef open
58 #undef rename
59 #undef rmdir
60 #undef unlink
62 #undef close
63 #undef dup
64 #undef dup2
65 #undef pipe
66 #undef read
67 #undef write
69 #undef strerror
71 #undef localtime
73 char *sys_ctime (const time_t *);
74 int sys_chdir (const char *);
75 int sys_creat (const char *, int);
76 FILE *sys_fopen (const char *, const char *);
77 int sys_mkdir (const char *);
78 int sys_open (const char *, int, int);
79 int sys_rename (char const *, char const *);
80 int sys_rmdir (const char *);
81 int sys_close (int);
82 int sys_dup2 (int, int);
83 int sys_read (int, char *, unsigned int);
84 int sys_write (int, const void *, unsigned int);
85 struct tm *sys_localtime (const time_t *);
87 #ifdef HAVE_MODULES
88 extern void dynlib_reset_last_error (void);
89 #endif
91 #include "lisp.h"
92 #include "epaths.h" /* for PATH_EXEC */
94 #include <pwd.h>
95 #include <grp.h>
97 #include <windows.h>
98 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
99 use a different name to avoid compilation problems. */
100 typedef struct _MEMORY_STATUS_EX {
101 DWORD dwLength;
102 DWORD dwMemoryLoad;
103 DWORDLONG ullTotalPhys;
104 DWORDLONG ullAvailPhys;
105 DWORDLONG ullTotalPageFile;
106 DWORDLONG ullAvailPageFile;
107 DWORDLONG ullTotalVirtual;
108 DWORDLONG ullAvailVirtual;
109 DWORDLONG ullAvailExtendedVirtual;
110 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
112 /* These are here so that GDB would know about these data types. This
113 allows attaching GDB to Emacs when a fatal exception is triggered
114 and Windows pops up the "application needs to be closed" dialog.
115 At that point, _gnu_exception_handler, the top-level exception
116 handler installed by the MinGW startup code, is somewhere on the
117 call-stack of the main thread, so going to that call frame and
118 looking at the argument to _gnu_exception_handler, which is a
119 PEXCEPTION_POINTERS pointer, can reveal the exception code
120 (excptr->ExceptionRecord->ExceptionCode) and the address where the
121 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
122 well as some additional information specific to the exception. */
123 PEXCEPTION_POINTERS excptr;
124 PEXCEPTION_RECORD excprec;
125 PCONTEXT ctxrec;
127 #include <lmcons.h>
128 #include <shlobj.h>
130 #include <tlhelp32.h>
131 #include <psapi.h>
132 #ifndef _MSC_VER
133 #include <w32api.h>
134 #endif
135 #if _WIN32_WINNT < 0x0500
136 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
137 /* This either is not in psapi.h or guarded by higher value of
138 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
139 defines it in psapi.h */
140 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
141 DWORD cb;
142 DWORD PageFaultCount;
143 SIZE_T PeakWorkingSetSize;
144 SIZE_T WorkingSetSize;
145 SIZE_T QuotaPeakPagedPoolUsage;
146 SIZE_T QuotaPagedPoolUsage;
147 SIZE_T QuotaPeakNonPagedPoolUsage;
148 SIZE_T QuotaNonPagedPoolUsage;
149 SIZE_T PagefileUsage;
150 SIZE_T PeakPagefileUsage;
151 SIZE_T PrivateUsage;
152 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
153 #endif
154 #endif
156 #include <winioctl.h>
157 #include <aclapi.h>
158 #include <sddl.h>
160 #include <sys/acl.h>
161 #include <acl.h>
163 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
164 define them by hand if not already defined. */
165 #ifndef SDDL_REVISION_1
166 #define SDDL_REVISION_1 1
167 #endif /* SDDL_REVISION_1 */
169 #if defined(_MSC_VER) || defined(MINGW_W64)
170 /* MSVC and MinGW64 don't provide the definition of
171 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
172 which cannot be included because it triggers conflicts with other
173 Windows API headers. So we define it here by hand. */
175 typedef struct _REPARSE_DATA_BUFFER {
176 ULONG ReparseTag;
177 USHORT ReparseDataLength;
178 USHORT Reserved;
179 union {
180 struct {
181 USHORT SubstituteNameOffset;
182 USHORT SubstituteNameLength;
183 USHORT PrintNameOffset;
184 USHORT PrintNameLength;
185 ULONG Flags;
186 WCHAR PathBuffer[1];
187 } SymbolicLinkReparseBuffer;
188 struct {
189 USHORT SubstituteNameOffset;
190 USHORT SubstituteNameLength;
191 USHORT PrintNameOffset;
192 USHORT PrintNameLength;
193 WCHAR PathBuffer[1];
194 } MountPointReparseBuffer;
195 struct {
196 UCHAR DataBuffer[1];
197 } GenericReparseBuffer;
198 } DUMMYUNIONNAME;
199 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
201 #ifndef FILE_DEVICE_FILE_SYSTEM
202 #define FILE_DEVICE_FILE_SYSTEM 9
203 #endif
204 #ifndef METHOD_BUFFERED
205 #define METHOD_BUFFERED 0
206 #endif
207 #ifndef FILE_ANY_ACCESS
208 #define FILE_ANY_ACCESS 0x00000000
209 #endif
210 #ifndef CTL_CODE
211 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
212 #endif
213 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
214 #ifndef FSCTL_GET_REPARSE_POINT
215 #define FSCTL_GET_REPARSE_POINT \
216 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
217 #endif
218 #endif
220 /* TCP connection support. */
221 #include <sys/socket.h>
222 #undef socket
223 #undef bind
224 #undef connect
225 #undef htons
226 #undef ntohs
227 #undef inet_addr
228 #undef gethostname
229 #undef gethostbyname
230 #undef getservbyname
231 #undef getpeername
232 #undef shutdown
233 #undef setsockopt
234 #undef listen
235 #undef getsockname
236 #undef accept
237 #undef recvfrom
238 #undef sendto
240 #include <iphlpapi.h> /* should be after winsock2.h */
242 #include <wincrypt.h>
244 #include <c-strcase.h>
245 #include <utimens.h> /* for fdutimens */
247 #include "w32.h"
248 #include <dirent.h>
249 #include "w32common.h"
250 #include "w32select.h"
251 #include "systime.h" /* for current_timespec, struct timespec */
252 #include "dispextern.h" /* for xstrcasecmp */
253 #include "coding.h" /* for Vlocale_coding_system */
255 #include "careadlinkat.h"
256 #include "allocator.h"
258 /* For Lisp_Process, serial_configure and serial_open. */
259 #include "process.h"
260 #include "systty.h"
262 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
263 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
265 static DWORD get_rid (PSID);
266 static int is_symlink (const char *);
267 static char * chase_symlinks (const char *);
268 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
269 static int restore_privilege (TOKEN_PRIVILEGES *);
270 static BOOL WINAPI revert_to_self (void);
272 static int sys_access (const char *, int);
273 extern void *e_malloc (size_t);
274 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
275 struct timespec *, void *);
276 extern int sys_dup (int);
279 /* Initialization states.
281 WARNING: If you add any more such variables for additional APIs,
282 you MUST add initialization for them to globals_of_w32
283 below. This is because these variables might get set
284 to non-NULL values during dumping, but the dumped Emacs
285 cannot reuse those values, because it could be run on a
286 different version of the OS, where API addresses are
287 different. */
288 static BOOL g_b_init_is_windows_9x;
289 static BOOL g_b_init_open_process_token;
290 static BOOL g_b_init_get_token_information;
291 static BOOL g_b_init_lookup_account_sid;
292 static BOOL g_b_init_get_sid_sub_authority;
293 static BOOL g_b_init_get_sid_sub_authority_count;
294 static BOOL g_b_init_get_security_info;
295 static BOOL g_b_init_get_file_security_w;
296 static BOOL g_b_init_get_file_security_a;
297 static BOOL g_b_init_get_security_descriptor_owner;
298 static BOOL g_b_init_get_security_descriptor_group;
299 static BOOL g_b_init_is_valid_sid;
300 static BOOL g_b_init_create_toolhelp32_snapshot;
301 static BOOL g_b_init_process32_first;
302 static BOOL g_b_init_process32_next;
303 static BOOL g_b_init_open_thread_token;
304 static BOOL g_b_init_impersonate_self;
305 static BOOL g_b_init_revert_to_self;
306 static BOOL g_b_init_get_process_memory_info;
307 static BOOL g_b_init_get_process_working_set_size;
308 static BOOL g_b_init_global_memory_status;
309 static BOOL g_b_init_global_memory_status_ex;
310 static BOOL g_b_init_get_length_sid;
311 static BOOL g_b_init_equal_sid;
312 static BOOL g_b_init_copy_sid;
313 static BOOL g_b_init_get_native_system_info;
314 static BOOL g_b_init_get_system_times;
315 static BOOL g_b_init_create_symbolic_link_w;
316 static BOOL g_b_init_create_symbolic_link_a;
317 static BOOL g_b_init_get_security_descriptor_dacl;
318 static BOOL g_b_init_convert_sd_to_sddl;
319 static BOOL g_b_init_convert_sddl_to_sd;
320 static BOOL g_b_init_is_valid_security_descriptor;
321 static BOOL g_b_init_set_file_security_w;
322 static BOOL g_b_init_set_file_security_a;
323 static BOOL g_b_init_set_named_security_info_w;
324 static BOOL g_b_init_set_named_security_info_a;
325 static BOOL g_b_init_get_adapters_info;
327 BOOL g_b_init_compare_string_w;
328 BOOL g_b_init_debug_break_process;
331 BEGIN: Wrapper functions around OpenProcessToken
332 and other functions in advapi32.dll that are only
333 supported in Windows NT / 2k / XP
335 /* ** Function pointer typedefs ** */
336 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
337 HANDLE ProcessHandle,
338 DWORD DesiredAccess,
339 PHANDLE TokenHandle);
340 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
341 HANDLE TokenHandle,
342 TOKEN_INFORMATION_CLASS TokenInformationClass,
343 LPVOID TokenInformation,
344 DWORD TokenInformationLength,
345 PDWORD ReturnLength);
346 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
347 HANDLE process_handle,
348 LPFILETIME creation_time,
349 LPFILETIME exit_time,
350 LPFILETIME kernel_time,
351 LPFILETIME user_time);
353 GetProcessTimes_Proc get_process_times_fn = NULL;
355 #ifdef _UNICODE
356 const char * const LookupAccountSid_Name = "LookupAccountSidW";
357 #else
358 const char * const LookupAccountSid_Name = "LookupAccountSidA";
359 #endif
360 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
361 LPCTSTR lpSystemName,
362 PSID Sid,
363 LPTSTR Name,
364 LPDWORD cbName,
365 LPTSTR DomainName,
366 LPDWORD cbDomainName,
367 PSID_NAME_USE peUse);
368 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
369 PSID pSid,
370 DWORD n);
371 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
372 PSID pSid);
373 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
374 HANDLE handle,
375 SE_OBJECT_TYPE ObjectType,
376 SECURITY_INFORMATION SecurityInfo,
377 PSID *ppsidOwner,
378 PSID *ppsidGroup,
379 PACL *ppDacl,
380 PACL *ppSacl,
381 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
382 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
383 LPCWSTR lpFileName,
384 SECURITY_INFORMATION RequestedInformation,
385 PSECURITY_DESCRIPTOR pSecurityDescriptor,
386 DWORD nLength,
387 LPDWORD lpnLengthNeeded);
388 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
389 LPCSTR lpFileName,
390 SECURITY_INFORMATION RequestedInformation,
391 PSECURITY_DESCRIPTOR pSecurityDescriptor,
392 DWORD nLength,
393 LPDWORD lpnLengthNeeded);
394 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
395 LPCWSTR lpFileName,
396 SECURITY_INFORMATION SecurityInformation,
397 PSECURITY_DESCRIPTOR pSecurityDescriptor);
398 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
399 LPCSTR lpFileName,
400 SECURITY_INFORMATION SecurityInformation,
401 PSECURITY_DESCRIPTOR pSecurityDescriptor);
402 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
403 LPCWSTR lpObjectName,
404 SE_OBJECT_TYPE ObjectType,
405 SECURITY_INFORMATION SecurityInformation,
406 PSID psidOwner,
407 PSID psidGroup,
408 PACL pDacl,
409 PACL pSacl);
410 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
411 LPCSTR lpObjectName,
412 SE_OBJECT_TYPE ObjectType,
413 SECURITY_INFORMATION SecurityInformation,
414 PSID psidOwner,
415 PSID psidGroup,
416 PACL pDacl,
417 PACL pSacl);
418 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
419 PSECURITY_DESCRIPTOR pSecurityDescriptor,
420 PSID *pOwner,
421 LPBOOL lpbOwnerDefaulted);
422 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
423 PSECURITY_DESCRIPTOR pSecurityDescriptor,
424 PSID *pGroup,
425 LPBOOL lpbGroupDefaulted);
426 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
427 PSECURITY_DESCRIPTOR pSecurityDescriptor,
428 LPBOOL lpbDaclPresent,
429 PACL *pDacl,
430 LPBOOL lpbDaclDefaulted);
431 typedef BOOL (WINAPI * IsValidSid_Proc) (
432 PSID sid);
433 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
434 DWORD dwFlags,
435 DWORD th32ProcessID);
436 typedef BOOL (WINAPI * Process32First_Proc) (
437 HANDLE hSnapshot,
438 LPPROCESSENTRY32 lppe);
439 typedef BOOL (WINAPI * Process32Next_Proc) (
440 HANDLE hSnapshot,
441 LPPROCESSENTRY32 lppe);
442 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
443 HANDLE ThreadHandle,
444 DWORD DesiredAccess,
445 BOOL OpenAsSelf,
446 PHANDLE TokenHandle);
447 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
448 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
449 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
450 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
451 HANDLE Process,
452 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
453 DWORD cb);
454 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
455 HANDLE hProcess,
456 PSIZE_T lpMinimumWorkingSetSize,
457 PSIZE_T lpMaximumWorkingSetSize);
458 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
459 LPMEMORYSTATUS lpBuffer);
460 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
461 LPMEMORY_STATUS_EX lpBuffer);
462 typedef BOOL (WINAPI * CopySid_Proc) (
463 DWORD nDestinationSidLength,
464 PSID pDestinationSid,
465 PSID pSourceSid);
466 typedef BOOL (WINAPI * EqualSid_Proc) (
467 PSID pSid1,
468 PSID pSid2);
469 typedef DWORD (WINAPI * GetLengthSid_Proc) (
470 PSID pSid);
471 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
472 LPSYSTEM_INFO lpSystemInfo);
473 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
474 LPFILETIME lpIdleTime,
475 LPFILETIME lpKernelTime,
476 LPFILETIME lpUserTime);
477 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
478 LPCWSTR lpSymlinkFileName,
479 LPCWSTR lpTargetFileName,
480 DWORD dwFlags);
481 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
482 LPCSTR lpSymlinkFileName,
483 LPCSTR lpTargetFileName,
484 DWORD dwFlags);
485 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
486 LPCTSTR StringSecurityDescriptor,
487 DWORD StringSDRevision,
488 PSECURITY_DESCRIPTOR *SecurityDescriptor,
489 PULONG SecurityDescriptorSize);
490 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
491 PSECURITY_DESCRIPTOR SecurityDescriptor,
492 DWORD RequestedStringSDRevision,
493 SECURITY_INFORMATION SecurityInformation,
494 LPTSTR *StringSecurityDescriptor,
495 PULONG StringSecurityDescriptorLen);
496 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
497 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
498 PIP_ADAPTER_INFO pAdapterInfo,
499 PULONG pOutBufLen);
501 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
502 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
503 DWORD multiByteToWideCharFlags;
505 /* ** A utility function ** */
506 static BOOL
507 is_windows_9x (void)
509 static BOOL s_b_ret = 0;
510 OSVERSIONINFO os_ver;
511 if (g_b_init_is_windows_9x == 0)
513 g_b_init_is_windows_9x = 1;
514 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
515 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
516 if (GetVersionEx (&os_ver))
518 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
521 return s_b_ret;
524 static Lisp_Object ltime (ULONGLONG);
526 /* Get total user and system times for get-internal-run-time.
527 Returns a list of integers if the times are provided by the OS
528 (NT derivatives), otherwise it returns the result of current-time. */
529 Lisp_Object w32_get_internal_run_time (void);
531 Lisp_Object
532 w32_get_internal_run_time (void)
534 if (get_process_times_fn)
536 FILETIME create, exit, kernel, user;
537 HANDLE proc = GetCurrentProcess ();
538 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
540 LARGE_INTEGER user_int, kernel_int, total;
541 user_int.LowPart = user.dwLowDateTime;
542 user_int.HighPart = user.dwHighDateTime;
543 kernel_int.LowPart = kernel.dwLowDateTime;
544 kernel_int.HighPart = kernel.dwHighDateTime;
545 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
546 return ltime (total.QuadPart);
550 return Fcurrent_time ();
553 /* ** The wrapper functions ** */
555 static BOOL WINAPI
556 open_process_token (HANDLE ProcessHandle,
557 DWORD DesiredAccess,
558 PHANDLE TokenHandle)
560 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
561 HMODULE hm_advapi32 = NULL;
562 if (is_windows_9x () == TRUE)
564 return FALSE;
566 if (g_b_init_open_process_token == 0)
568 g_b_init_open_process_token = 1;
569 hm_advapi32 = LoadLibrary ("Advapi32.dll");
570 s_pfn_Open_Process_Token =
571 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
573 if (s_pfn_Open_Process_Token == NULL)
575 return FALSE;
577 return (
578 s_pfn_Open_Process_Token (
579 ProcessHandle,
580 DesiredAccess,
581 TokenHandle)
585 static BOOL WINAPI
586 get_token_information (HANDLE TokenHandle,
587 TOKEN_INFORMATION_CLASS TokenInformationClass,
588 LPVOID TokenInformation,
589 DWORD TokenInformationLength,
590 PDWORD ReturnLength)
592 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
593 HMODULE hm_advapi32 = NULL;
594 if (is_windows_9x () == TRUE)
596 return FALSE;
598 if (g_b_init_get_token_information == 0)
600 g_b_init_get_token_information = 1;
601 hm_advapi32 = LoadLibrary ("Advapi32.dll");
602 s_pfn_Get_Token_Information =
603 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
605 if (s_pfn_Get_Token_Information == NULL)
607 return FALSE;
609 return (
610 s_pfn_Get_Token_Information (
611 TokenHandle,
612 TokenInformationClass,
613 TokenInformation,
614 TokenInformationLength,
615 ReturnLength)
619 static BOOL WINAPI
620 lookup_account_sid (LPCTSTR lpSystemName,
621 PSID Sid,
622 LPTSTR Name,
623 LPDWORD cbName,
624 LPTSTR DomainName,
625 LPDWORD cbDomainName,
626 PSID_NAME_USE peUse)
628 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
629 HMODULE hm_advapi32 = NULL;
630 if (is_windows_9x () == TRUE)
632 return FALSE;
634 if (g_b_init_lookup_account_sid == 0)
636 g_b_init_lookup_account_sid = 1;
637 hm_advapi32 = LoadLibrary ("Advapi32.dll");
638 s_pfn_Lookup_Account_Sid =
639 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
641 if (s_pfn_Lookup_Account_Sid == NULL)
643 return FALSE;
645 return (
646 s_pfn_Lookup_Account_Sid (
647 lpSystemName,
648 Sid,
649 Name,
650 cbName,
651 DomainName,
652 cbDomainName,
653 peUse)
657 static PDWORD WINAPI
658 get_sid_sub_authority (PSID pSid, DWORD n)
660 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
661 static DWORD zero = 0U;
662 HMODULE hm_advapi32 = NULL;
663 if (is_windows_9x () == TRUE)
665 return &zero;
667 if (g_b_init_get_sid_sub_authority == 0)
669 g_b_init_get_sid_sub_authority = 1;
670 hm_advapi32 = LoadLibrary ("Advapi32.dll");
671 s_pfn_Get_Sid_Sub_Authority =
672 (GetSidSubAuthority_Proc) GetProcAddress (
673 hm_advapi32, "GetSidSubAuthority");
675 if (s_pfn_Get_Sid_Sub_Authority == NULL)
677 return &zero;
679 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
682 static PUCHAR WINAPI
683 get_sid_sub_authority_count (PSID pSid)
685 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
686 static UCHAR zero = 0U;
687 HMODULE hm_advapi32 = NULL;
688 if (is_windows_9x () == TRUE)
690 return &zero;
692 if (g_b_init_get_sid_sub_authority_count == 0)
694 g_b_init_get_sid_sub_authority_count = 1;
695 hm_advapi32 = LoadLibrary ("Advapi32.dll");
696 s_pfn_Get_Sid_Sub_Authority_Count =
697 (GetSidSubAuthorityCount_Proc) GetProcAddress (
698 hm_advapi32, "GetSidSubAuthorityCount");
700 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
702 return &zero;
704 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
707 static DWORD WINAPI
708 get_security_info (HANDLE handle,
709 SE_OBJECT_TYPE ObjectType,
710 SECURITY_INFORMATION SecurityInfo,
711 PSID *ppsidOwner,
712 PSID *ppsidGroup,
713 PACL *ppDacl,
714 PACL *ppSacl,
715 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
717 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
718 HMODULE hm_advapi32 = NULL;
719 if (is_windows_9x () == TRUE)
721 return FALSE;
723 if (g_b_init_get_security_info == 0)
725 g_b_init_get_security_info = 1;
726 hm_advapi32 = LoadLibrary ("Advapi32.dll");
727 s_pfn_Get_Security_Info =
728 (GetSecurityInfo_Proc) GetProcAddress (
729 hm_advapi32, "GetSecurityInfo");
731 if (s_pfn_Get_Security_Info == NULL)
733 return FALSE;
735 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
736 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
737 ppSecurityDescriptor));
740 static BOOL WINAPI
741 get_file_security (const char *lpFileName,
742 SECURITY_INFORMATION RequestedInformation,
743 PSECURITY_DESCRIPTOR pSecurityDescriptor,
744 DWORD nLength,
745 LPDWORD lpnLengthNeeded)
747 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
748 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
749 HMODULE hm_advapi32 = NULL;
750 if (is_windows_9x () == TRUE)
752 errno = ENOTSUP;
753 return FALSE;
755 if (w32_unicode_filenames)
757 wchar_t filename_w[MAX_PATH];
759 if (g_b_init_get_file_security_w == 0)
761 g_b_init_get_file_security_w = 1;
762 hm_advapi32 = LoadLibrary ("Advapi32.dll");
763 s_pfn_Get_File_SecurityW =
764 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
765 "GetFileSecurityW");
767 if (s_pfn_Get_File_SecurityW == NULL)
769 errno = ENOTSUP;
770 return FALSE;
772 filename_to_utf16 (lpFileName, filename_w);
773 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
774 pSecurityDescriptor, nLength,
775 lpnLengthNeeded));
777 else
779 char filename_a[MAX_PATH];
781 if (g_b_init_get_file_security_a == 0)
783 g_b_init_get_file_security_a = 1;
784 hm_advapi32 = LoadLibrary ("Advapi32.dll");
785 s_pfn_Get_File_SecurityA =
786 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
787 "GetFileSecurityA");
789 if (s_pfn_Get_File_SecurityA == NULL)
791 errno = ENOTSUP;
792 return FALSE;
794 filename_to_ansi (lpFileName, filename_a);
795 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
796 pSecurityDescriptor, nLength,
797 lpnLengthNeeded));
801 static BOOL WINAPI
802 set_file_security (const char *lpFileName,
803 SECURITY_INFORMATION SecurityInformation,
804 PSECURITY_DESCRIPTOR pSecurityDescriptor)
806 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
807 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
808 HMODULE hm_advapi32 = NULL;
809 if (is_windows_9x () == TRUE)
811 errno = ENOTSUP;
812 return FALSE;
814 if (w32_unicode_filenames)
816 wchar_t filename_w[MAX_PATH];
818 if (g_b_init_set_file_security_w == 0)
820 g_b_init_set_file_security_w = 1;
821 hm_advapi32 = LoadLibrary ("Advapi32.dll");
822 s_pfn_Set_File_SecurityW =
823 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
824 "SetFileSecurityW");
826 if (s_pfn_Set_File_SecurityW == NULL)
828 errno = ENOTSUP;
829 return FALSE;
831 filename_to_utf16 (lpFileName, filename_w);
832 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
833 pSecurityDescriptor));
835 else
837 char filename_a[MAX_PATH];
839 if (g_b_init_set_file_security_a == 0)
841 g_b_init_set_file_security_a = 1;
842 hm_advapi32 = LoadLibrary ("Advapi32.dll");
843 s_pfn_Set_File_SecurityA =
844 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
845 "SetFileSecurityA");
847 if (s_pfn_Set_File_SecurityA == NULL)
849 errno = ENOTSUP;
850 return FALSE;
852 filename_to_ansi (lpFileName, filename_a);
853 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
854 pSecurityDescriptor));
858 static DWORD WINAPI
859 set_named_security_info (LPCTSTR lpObjectName,
860 SE_OBJECT_TYPE ObjectType,
861 SECURITY_INFORMATION SecurityInformation,
862 PSID psidOwner,
863 PSID psidGroup,
864 PACL pDacl,
865 PACL pSacl)
867 static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
868 static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
869 HMODULE hm_advapi32 = NULL;
870 if (is_windows_9x () == TRUE)
872 errno = ENOTSUP;
873 return ENOTSUP;
875 if (w32_unicode_filenames)
877 wchar_t filename_w[MAX_PATH];
879 if (g_b_init_set_named_security_info_w == 0)
881 g_b_init_set_named_security_info_w = 1;
882 hm_advapi32 = LoadLibrary ("Advapi32.dll");
883 s_pfn_Set_Named_Security_InfoW =
884 (SetNamedSecurityInfoW_Proc) GetProcAddress (hm_advapi32,
885 "SetNamedSecurityInfoW");
887 if (s_pfn_Set_Named_Security_InfoW == NULL)
889 errno = ENOTSUP;
890 return ENOTSUP;
892 filename_to_utf16 (lpObjectName, filename_w);
893 return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
894 SecurityInformation, psidOwner,
895 psidGroup, pDacl, pSacl));
897 else
899 char filename_a[MAX_PATH];
901 if (g_b_init_set_named_security_info_a == 0)
903 g_b_init_set_named_security_info_a = 1;
904 hm_advapi32 = LoadLibrary ("Advapi32.dll");
905 s_pfn_Set_Named_Security_InfoA =
906 (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
907 "SetNamedSecurityInfoA");
909 if (s_pfn_Set_Named_Security_InfoA == NULL)
911 errno = ENOTSUP;
912 return ENOTSUP;
914 filename_to_ansi (lpObjectName, filename_a);
915 return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
916 SecurityInformation, psidOwner,
917 psidGroup, pDacl, pSacl));
921 static BOOL WINAPI
922 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
923 PSID *pOwner,
924 LPBOOL lpbOwnerDefaulted)
926 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
927 HMODULE hm_advapi32 = NULL;
928 if (is_windows_9x () == TRUE)
930 errno = ENOTSUP;
931 return FALSE;
933 if (g_b_init_get_security_descriptor_owner == 0)
935 g_b_init_get_security_descriptor_owner = 1;
936 hm_advapi32 = LoadLibrary ("Advapi32.dll");
937 s_pfn_Get_Security_Descriptor_Owner =
938 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
939 hm_advapi32, "GetSecurityDescriptorOwner");
941 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
943 errno = ENOTSUP;
944 return FALSE;
946 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
947 lpbOwnerDefaulted));
950 static BOOL WINAPI
951 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
952 PSID *pGroup,
953 LPBOOL lpbGroupDefaulted)
955 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
956 HMODULE hm_advapi32 = NULL;
957 if (is_windows_9x () == TRUE)
959 errno = ENOTSUP;
960 return FALSE;
962 if (g_b_init_get_security_descriptor_group == 0)
964 g_b_init_get_security_descriptor_group = 1;
965 hm_advapi32 = LoadLibrary ("Advapi32.dll");
966 s_pfn_Get_Security_Descriptor_Group =
967 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
968 hm_advapi32, "GetSecurityDescriptorGroup");
970 if (s_pfn_Get_Security_Descriptor_Group == NULL)
972 errno = ENOTSUP;
973 return FALSE;
975 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
976 lpbGroupDefaulted));
979 static BOOL WINAPI
980 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
981 LPBOOL lpbDaclPresent,
982 PACL *pDacl,
983 LPBOOL lpbDaclDefaulted)
985 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
986 HMODULE hm_advapi32 = NULL;
987 if (is_windows_9x () == TRUE)
989 errno = ENOTSUP;
990 return FALSE;
992 if (g_b_init_get_security_descriptor_dacl == 0)
994 g_b_init_get_security_descriptor_dacl = 1;
995 hm_advapi32 = LoadLibrary ("Advapi32.dll");
996 s_pfn_Get_Security_Descriptor_Dacl =
997 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
998 hm_advapi32, "GetSecurityDescriptorDacl");
1000 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
1002 errno = ENOTSUP;
1003 return FALSE;
1005 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
1006 lpbDaclPresent, pDacl,
1007 lpbDaclDefaulted));
1010 static BOOL WINAPI
1011 is_valid_sid (PSID sid)
1013 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
1014 HMODULE hm_advapi32 = NULL;
1015 if (is_windows_9x () == TRUE)
1017 return FALSE;
1019 if (g_b_init_is_valid_sid == 0)
1021 g_b_init_is_valid_sid = 1;
1022 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1023 s_pfn_Is_Valid_Sid =
1024 (IsValidSid_Proc) GetProcAddress (
1025 hm_advapi32, "IsValidSid");
1027 if (s_pfn_Is_Valid_Sid == NULL)
1029 return FALSE;
1031 return (s_pfn_Is_Valid_Sid (sid));
1034 static BOOL WINAPI
1035 equal_sid (PSID sid1, PSID sid2)
1037 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
1038 HMODULE hm_advapi32 = NULL;
1039 if (is_windows_9x () == TRUE)
1041 return FALSE;
1043 if (g_b_init_equal_sid == 0)
1045 g_b_init_equal_sid = 1;
1046 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1047 s_pfn_Equal_Sid =
1048 (EqualSid_Proc) GetProcAddress (
1049 hm_advapi32, "EqualSid");
1051 if (s_pfn_Equal_Sid == NULL)
1053 return FALSE;
1055 return (s_pfn_Equal_Sid (sid1, sid2));
1058 static DWORD WINAPI
1059 get_length_sid (PSID sid)
1061 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
1062 HMODULE hm_advapi32 = NULL;
1063 if (is_windows_9x () == TRUE)
1065 return 0;
1067 if (g_b_init_get_length_sid == 0)
1069 g_b_init_get_length_sid = 1;
1070 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1071 s_pfn_Get_Length_Sid =
1072 (GetLengthSid_Proc) GetProcAddress (
1073 hm_advapi32, "GetLengthSid");
1075 if (s_pfn_Get_Length_Sid == NULL)
1077 return 0;
1079 return (s_pfn_Get_Length_Sid (sid));
1082 static BOOL WINAPI
1083 copy_sid (DWORD destlen, PSID dest, PSID src)
1085 static CopySid_Proc s_pfn_Copy_Sid = NULL;
1086 HMODULE hm_advapi32 = NULL;
1087 if (is_windows_9x () == TRUE)
1089 return FALSE;
1091 if (g_b_init_copy_sid == 0)
1093 g_b_init_copy_sid = 1;
1094 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1095 s_pfn_Copy_Sid =
1096 (CopySid_Proc) GetProcAddress (
1097 hm_advapi32, "CopySid");
1099 if (s_pfn_Copy_Sid == NULL)
1101 return FALSE;
1103 return (s_pfn_Copy_Sid (destlen, dest, src));
1107 END: Wrapper functions around OpenProcessToken
1108 and other functions in advapi32.dll that are only
1109 supported in Windows NT / 2k / XP
1112 static void WINAPI
1113 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1115 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1116 if (is_windows_9x () != TRUE)
1118 if (g_b_init_get_native_system_info == 0)
1120 g_b_init_get_native_system_info = 1;
1121 s_pfn_Get_Native_System_Info =
1122 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1123 "GetNativeSystemInfo");
1125 if (s_pfn_Get_Native_System_Info != NULL)
1126 s_pfn_Get_Native_System_Info (lpSystemInfo);
1128 else
1129 lpSystemInfo->dwNumberOfProcessors = -1;
1132 static BOOL WINAPI
1133 get_system_times (LPFILETIME lpIdleTime,
1134 LPFILETIME lpKernelTime,
1135 LPFILETIME lpUserTime)
1137 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1138 if (is_windows_9x () == TRUE)
1140 return FALSE;
1142 if (g_b_init_get_system_times == 0)
1144 g_b_init_get_system_times = 1;
1145 s_pfn_Get_System_times =
1146 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1147 "GetSystemTimes");
1149 if (s_pfn_Get_System_times == NULL)
1150 return FALSE;
1151 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1154 static BOOLEAN WINAPI
1155 create_symbolic_link (LPCSTR lpSymlinkFilename,
1156 LPCSTR lpTargetFileName,
1157 DWORD dwFlags)
1159 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1160 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1161 BOOLEAN retval;
1163 if (is_windows_9x () == TRUE)
1165 errno = ENOSYS;
1166 return 0;
1168 if (w32_unicode_filenames)
1170 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1172 if (g_b_init_create_symbolic_link_w == 0)
1174 g_b_init_create_symbolic_link_w = 1;
1175 s_pfn_Create_Symbolic_LinkW =
1176 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1177 "CreateSymbolicLinkW");
1179 if (s_pfn_Create_Symbolic_LinkW == NULL)
1181 errno = ENOSYS;
1182 return 0;
1185 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1186 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1187 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1188 /* If we were denied creation of the symlink, try again after
1189 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1190 if (!retval)
1192 TOKEN_PRIVILEGES priv_current;
1194 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1195 &priv_current))
1197 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1198 restore_privilege (&priv_current);
1199 revert_to_self ();
1203 else
1205 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1207 if (g_b_init_create_symbolic_link_a == 0)
1209 g_b_init_create_symbolic_link_a = 1;
1210 s_pfn_Create_Symbolic_LinkA =
1211 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1212 "CreateSymbolicLinkA");
1214 if (s_pfn_Create_Symbolic_LinkA == NULL)
1216 errno = ENOSYS;
1217 return 0;
1220 filename_to_ansi (lpSymlinkFilename, symfn_a);
1221 filename_to_ansi (lpTargetFileName, tgtfn_a);
1222 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1223 /* If we were denied creation of the symlink, try again after
1224 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1225 if (!retval)
1227 TOKEN_PRIVILEGES priv_current;
1229 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1230 &priv_current))
1232 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1233 restore_privilege (&priv_current);
1234 revert_to_self ();
1238 return retval;
1241 static BOOL WINAPI
1242 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1244 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1246 if (is_windows_9x () == TRUE)
1248 errno = ENOTSUP;
1249 return FALSE;
1252 if (g_b_init_is_valid_security_descriptor == 0)
1254 g_b_init_is_valid_security_descriptor = 1;
1255 s_pfn_Is_Valid_Security_Descriptor_Proc =
1256 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1257 "IsValidSecurityDescriptor");
1259 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1261 errno = ENOTSUP;
1262 return FALSE;
1265 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1268 static BOOL WINAPI
1269 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1270 DWORD RequestedStringSDRevision,
1271 SECURITY_INFORMATION SecurityInformation,
1272 LPTSTR *StringSecurityDescriptor,
1273 PULONG StringSecurityDescriptorLen)
1275 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1276 BOOL retval;
1278 if (is_windows_9x () == TRUE)
1280 errno = ENOTSUP;
1281 return FALSE;
1284 if (g_b_init_convert_sd_to_sddl == 0)
1286 g_b_init_convert_sd_to_sddl = 1;
1287 #ifdef _UNICODE
1288 s_pfn_Convert_SD_To_SDDL =
1289 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1290 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1291 #else
1292 s_pfn_Convert_SD_To_SDDL =
1293 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1294 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1295 #endif
1297 if (s_pfn_Convert_SD_To_SDDL == NULL)
1299 errno = ENOTSUP;
1300 return FALSE;
1303 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1304 RequestedStringSDRevision,
1305 SecurityInformation,
1306 StringSecurityDescriptor,
1307 StringSecurityDescriptorLen);
1309 return retval;
1312 static BOOL WINAPI
1313 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1314 DWORD StringSDRevision,
1315 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1316 PULONG SecurityDescriptorSize)
1318 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1319 BOOL retval;
1321 if (is_windows_9x () == TRUE)
1323 errno = ENOTSUP;
1324 return FALSE;
1327 if (g_b_init_convert_sddl_to_sd == 0)
1329 g_b_init_convert_sddl_to_sd = 1;
1330 #ifdef _UNICODE
1331 s_pfn_Convert_SDDL_To_SD =
1332 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1333 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1334 #else
1335 s_pfn_Convert_SDDL_To_SD =
1336 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1337 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1338 #endif
1340 if (s_pfn_Convert_SDDL_To_SD == NULL)
1342 errno = ENOTSUP;
1343 return FALSE;
1346 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1347 StringSDRevision,
1348 SecurityDescriptor,
1349 SecurityDescriptorSize);
1351 return retval;
1354 static DWORD WINAPI
1355 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1357 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1358 HMODULE hm_iphlpapi = NULL;
1360 if (is_windows_9x () == TRUE)
1361 return ERROR_NOT_SUPPORTED;
1363 if (g_b_init_get_adapters_info == 0)
1365 g_b_init_get_adapters_info = 1;
1366 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1367 if (hm_iphlpapi)
1368 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1369 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1371 if (s_pfn_Get_Adapters_Info == NULL)
1372 return ERROR_NOT_SUPPORTED;
1373 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1378 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1379 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1381 This is called from alloc.c:valid_pointer_p. */
1383 w32_valid_pointer_p (void *p, int size)
1385 SIZE_T done;
1386 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1388 if (h)
1390 unsigned char *buf = alloca (size);
1391 int retval = ReadProcessMemory (h, p, buf, size, &done);
1393 CloseHandle (h);
1394 return retval;
1396 else
1397 return -1;
1402 /* Here's an overview of how the Windows build supports file names
1403 that cannot be encoded by the current system codepage.
1405 From the POV of Lisp and layers of C code above the functions here,
1406 Emacs on Windows pretends that its file names are encoded in UTF-8;
1407 see encode_file and decode_file on coding.c. Any file name that is
1408 passed as a unibyte string to C functions defined here is assumed
1409 to be in UTF-8 encoding. Any file name returned by functions
1410 defined here must be in UTF-8 encoding, with only a few exceptions
1411 reserved for a couple of special cases. (Be sure to use
1412 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1413 as they can be much longer than MAX_PATH!)
1415 The UTF-8 encoded file names cannot be passed to system APIs, as
1416 Windows does not support that. Therefore, they are converted
1417 either to UTF-16 or to the ANSI codepage, depending on the value of
1418 w32-unicode-filenames, before calling any system APIs or CRT library
1419 functions. The default value of that variable is determined by the
1420 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1421 user can change that default (although I don't see why would she
1422 want to).
1424 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1425 filename_from_utf16, and filename_from_ansi, are the workhorses of
1426 these conversions. They rely on Windows native APIs
1427 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1428 functions from coding.c here, because they allocate memory, which
1429 is a bad idea on the level of libc, which is what the functions
1430 here emulate. (If you worry about performance due to constant
1431 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1432 it was measured to take only a few microseconds on a not-so-fast
1433 machine, and second, that's exactly what the ANSI APIs we used
1434 before did anyway, because they are just thin wrappers around the
1435 Unicode APIs.)
1437 The variables file-name-coding-system and default-file-name-coding-system
1438 still exist, but are actually used only when a file name needs to
1439 be converted to the ANSI codepage. This happens all the time when
1440 w32-unicode-filenames is nil, but can also happen from time to time
1441 when it is t. Otherwise, these variables have no effect on file-name
1442 encoding when w32-unicode-filenames is t; this is similar to
1443 selection-coding-system.
1445 This arrangement works very well, but it has a few gotchas and
1446 limitations:
1448 . Lisp code that encodes or decodes file names manually should
1449 normally use 'utf-8' as the coding-system on Windows,
1450 disregarding file-name-coding-system. This is a somewhat
1451 unpleasant consequence, but it cannot be avoided. Fortunately,
1452 very few Lisp packages need to do that.
1454 More generally, passing to library functions (e.g., fopen or
1455 opendir) file names already encoded in the ANSI codepage is
1456 explicitly *verboten*, as all those functions, as shadowed and
1457 emulated here, assume they will receive UTF-8 encoded file names.
1459 For the same reasons, no CRT function or Win32 API can be called
1460 directly in Emacs sources, without either converting the file
1461 names from UTF-8 to UTF-16 or ANSI codepage, or going through
1462 some shadowing function defined here.
1464 . Environment variables stored in Vprocess_environment are encoded
1465 in the ANSI codepage, so if getenv/egetenv is used for a variable
1466 whose value is a file name or a list of directories, it needs to
1467 be converted to UTF-8, before it is used as argument to functions
1468 or decoded into a Lisp string.
1470 . File names passed to external libraries, like the image libraries
1471 and GnuTLS, need special handling. These libraries generally
1472 don't support UTF-16 or UTF-8 file names, so they must get file
1473 names encoded in the ANSI codepage. To facilitate using these
1474 libraries with file names that are not encodable in the ANSI
1475 codepage, use the function ansi_encode_filename, which will try
1476 to use the short 8+3 alias of a file name if that file name is
1477 not encodable in the ANSI codepage. See image.c and gnutls.c for
1478 examples of how this should be done.
1480 . Running subprocesses in non-ASCII directories and with non-ASCII
1481 file arguments is limited to the current codepage (even though
1482 Emacs is perfectly capable of finding an executable program file
1483 in a directory whose name cannot be encoded in the current
1484 codepage). This is because the command-line arguments are
1485 encoded _before_ they get to the w32-specific level, and the
1486 encoding is not known in advance (it doesn't have to be the
1487 current ANSI codepage), so w32proc.c functions cannot re-encode
1488 them in UTF-16. This should be fixed, but will also require
1489 changes in cmdproxy. The current limitation is not terribly bad
1490 anyway, since very few, if any, Windows console programs that are
1491 likely to be invoked by Emacs support UTF-16 encoded command
1492 lines.
1494 . For similar reasons, server.el and emacsclient are also limited
1495 to the current ANSI codepage for now.
1497 . Emacs itself can only handle command-line arguments encoded in
1498 the current codepage.
1500 . Turning on w32-unicode-filename on Windows 9X (if it at all
1501 works) requires UNICOWS.DLL, which is thus a requirement even in
1502 non-GUI sessions, something the we previously avoided. */
1506 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1507 codepage defined by file-name-coding-system. */
1509 /* Current codepage for encoding file names. */
1510 static int file_name_codepage;
1512 /* Initialize the codepage used for decoding file names. This is
1513 needed to undo the value recorded during dumping, which might not
1514 be correct when we run the dumped Emacs. */
1515 void
1516 w32_init_file_name_codepage (void)
1518 file_name_codepage = CP_ACP;
1519 w32_ansi_code_page = CP_ACP;
1522 /* Produce a Windows ANSI codepage suitable for encoding file names.
1523 Return the information about that codepage in CP_INFO. */
1525 codepage_for_filenames (CPINFO *cp_info)
1527 /* A simple cache to avoid calling GetCPInfo every time we need to
1528 encode/decode a file name. The file-name encoding is not
1529 supposed to be changed too frequently, if ever. */
1530 static Lisp_Object last_file_name_encoding;
1531 static CPINFO cp;
1532 Lisp_Object current_encoding;
1534 current_encoding = Vfile_name_coding_system;
1535 if (NILP (current_encoding))
1536 current_encoding = Vdefault_file_name_coding_system;
1538 if (!EQ (last_file_name_encoding, current_encoding)
1539 || NILP (last_file_name_encoding))
1541 /* Default to the current ANSI codepage. */
1542 file_name_codepage = w32_ansi_code_page;
1544 if (!NILP (current_encoding))
1546 char *cpname = SSDATA (SYMBOL_NAME (current_encoding));
1547 char *cp = NULL, *end;
1548 int cpnum;
1550 if (strncmp (cpname, "cp", 2) == 0)
1551 cp = cpname + 2;
1552 else if (strncmp (cpname, "windows-", 8) == 0)
1553 cp = cpname + 8;
1555 if (cp)
1557 end = cp;
1558 cpnum = strtol (cp, &end, 10);
1559 if (cpnum && *end == '\0' && end - cp >= 2)
1560 file_name_codepage = cpnum;
1564 if (!file_name_codepage)
1565 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1567 if (!GetCPInfo (file_name_codepage, &cp))
1569 file_name_codepage = CP_ACP;
1570 if (!GetCPInfo (file_name_codepage, &cp))
1571 emacs_abort ();
1574 /* Cache the new value. */
1575 last_file_name_encoding = current_encoding;
1577 if (cp_info)
1578 *cp_info = cp;
1580 return file_name_codepage;
1584 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1586 int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
1587 -1, fn_out, MAX_PATH);
1589 if (!result)
1591 DWORD err = GetLastError ();
1593 switch (err)
1595 case ERROR_INVALID_FLAGS:
1596 case ERROR_INVALID_PARAMETER:
1597 errno = EINVAL;
1598 break;
1599 case ERROR_INSUFFICIENT_BUFFER:
1600 case ERROR_NO_UNICODE_TRANSLATION:
1601 default:
1602 errno = ENOENT;
1603 break;
1605 return -1;
1607 return 0;
1611 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1613 int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1614 fn_out, MAX_UTF8_PATH, NULL, NULL);
1616 if (!result)
1618 DWORD err = GetLastError ();
1620 switch (err)
1622 case ERROR_INVALID_FLAGS:
1623 case ERROR_INVALID_PARAMETER:
1624 errno = EINVAL;
1625 break;
1626 case ERROR_INSUFFICIENT_BUFFER:
1627 case ERROR_NO_UNICODE_TRANSLATION:
1628 default:
1629 errno = ENOENT;
1630 break;
1632 return -1;
1634 return 0;
1638 filename_to_ansi (const char *fn_in, char *fn_out)
1640 wchar_t fn_utf16[MAX_PATH];
1642 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1644 int result;
1645 int codepage = codepage_for_filenames (NULL);
1647 result = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
1648 fn_out, MAX_PATH, NULL, NULL);
1649 if (!result)
1651 DWORD err = GetLastError ();
1653 switch (err)
1655 case ERROR_INVALID_FLAGS:
1656 case ERROR_INVALID_PARAMETER:
1657 errno = EINVAL;
1658 break;
1659 case ERROR_INSUFFICIENT_BUFFER:
1660 case ERROR_NO_UNICODE_TRANSLATION:
1661 default:
1662 errno = ENOENT;
1663 break;
1665 return -1;
1667 return 0;
1669 return -1;
1673 filename_from_ansi (const char *fn_in, char *fn_out)
1675 wchar_t fn_utf16[MAX_PATH];
1676 int codepage = codepage_for_filenames (NULL);
1677 int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
1678 -1, fn_utf16, MAX_PATH);
1680 if (!result)
1682 DWORD err = GetLastError ();
1684 switch (err)
1686 case ERROR_INVALID_FLAGS:
1687 case ERROR_INVALID_PARAMETER:
1688 errno = EINVAL;
1689 break;
1690 case ERROR_INSUFFICIENT_BUFFER:
1691 case ERROR_NO_UNICODE_TRANSLATION:
1692 default:
1693 errno = ENOENT;
1694 break;
1696 return -1;
1698 return filename_from_utf16 (fn_utf16, fn_out);
1703 /* The directory where we started, in UTF-8. */
1704 static char startup_dir[MAX_UTF8_PATH];
1706 /* Get the current working directory. */
1707 char *
1708 getcwd (char *dir, int dirsize)
1710 if (!dirsize)
1712 errno = EINVAL;
1713 return NULL;
1715 if (dirsize <= strlen (startup_dir))
1717 errno = ERANGE;
1718 return NULL;
1720 #if 0
1721 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1722 return dir;
1723 return NULL;
1724 #else
1725 /* Emacs doesn't actually change directory itself, it stays in the
1726 same directory where it was started. */
1727 strcpy (dir, startup_dir);
1728 return dir;
1729 #endif
1732 /* Emulate getloadavg. */
1734 struct load_sample {
1735 time_t sample_time;
1736 ULONGLONG idle;
1737 ULONGLONG kernel;
1738 ULONGLONG user;
1741 /* Number of processors on this machine. */
1742 static unsigned num_of_processors;
1744 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1745 static struct load_sample samples[16*60];
1746 static int first_idx = -1, last_idx = -1;
1747 static int max_idx = ARRAYELTS (samples);
1749 static int
1750 buf_next (int from)
1752 int next_idx = from + 1;
1754 if (next_idx >= max_idx)
1755 next_idx = 0;
1757 return next_idx;
1760 static int
1761 buf_prev (int from)
1763 int prev_idx = from - 1;
1765 if (prev_idx < 0)
1766 prev_idx = max_idx - 1;
1768 return prev_idx;
1771 static void
1772 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1774 SYSTEM_INFO sysinfo;
1775 FILETIME ft_idle, ft_user, ft_kernel;
1777 /* Initialize the number of processors on this machine. */
1778 if (num_of_processors <= 0)
1780 get_native_system_info (&sysinfo);
1781 num_of_processors = sysinfo.dwNumberOfProcessors;
1782 if (num_of_processors <= 0)
1784 GetSystemInfo (&sysinfo);
1785 num_of_processors = sysinfo.dwNumberOfProcessors;
1787 if (num_of_processors <= 0)
1788 num_of_processors = 1;
1791 /* TODO: Take into account threads that are ready to run, by
1792 sampling the "\System\Processor Queue Length" performance
1793 counter. The code below accounts only for threads that are
1794 actually running. */
1796 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1798 ULARGE_INTEGER uidle, ukernel, uuser;
1800 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1801 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1802 memcpy (&uuser, &ft_user, sizeof (ft_user));
1803 *idle = uidle.QuadPart;
1804 *kernel = ukernel.QuadPart;
1805 *user = uuser.QuadPart;
1807 else
1809 *idle = 0;
1810 *kernel = 0;
1811 *user = 0;
1815 /* Produce the load average for a given time interval, using the
1816 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1817 1-minute, 5-minute, or 15-minute average, respectively. */
1818 static double
1819 getavg (int which)
1821 double retval = -1.0;
1822 double tdiff;
1823 int idx;
1824 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1825 time_t now = samples[last_idx].sample_time;
1827 if (first_idx != last_idx)
1829 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1831 tdiff = difftime (now, samples[idx].sample_time);
1832 if (tdiff >= span - 2*DBL_EPSILON*now)
1834 long double sys =
1835 samples[last_idx].kernel + samples[last_idx].user
1836 - (samples[idx].kernel + samples[idx].user);
1837 long double idl = samples[last_idx].idle - samples[idx].idle;
1839 retval = (1.0 - idl / sys) * num_of_processors;
1840 break;
1842 if (idx == first_idx)
1843 break;
1847 return retval;
1851 getloadavg (double loadavg[], int nelem)
1853 int elem;
1854 ULONGLONG idle, kernel, user;
1855 time_t now = time (NULL);
1857 /* If system time jumped back for some reason, delete all samples
1858 whose time is later than the current wall-clock time. This
1859 prevents load average figures from becoming frozen for prolonged
1860 periods of time, when system time is reset backwards. */
1861 if (last_idx >= 0)
1863 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1865 if (last_idx == first_idx)
1867 first_idx = last_idx = -1;
1868 break;
1870 last_idx = buf_prev (last_idx);
1874 /* Store another sample. We ignore samples that are less than 1 sec
1875 apart. */
1876 if (last_idx < 0
1877 || (difftime (now, samples[last_idx].sample_time)
1878 >= 1.0 - 2*DBL_EPSILON*now))
1880 sample_system_load (&idle, &kernel, &user);
1881 last_idx = buf_next (last_idx);
1882 samples[last_idx].sample_time = now;
1883 samples[last_idx].idle = idle;
1884 samples[last_idx].kernel = kernel;
1885 samples[last_idx].user = user;
1886 /* If the buffer has more that 15 min worth of samples, discard
1887 the old ones. */
1888 if (first_idx == -1)
1889 first_idx = last_idx;
1890 while (first_idx != last_idx
1891 && (difftime (now, samples[first_idx].sample_time)
1892 >= 15.0*60 + 2*DBL_EPSILON*now))
1893 first_idx = buf_next (first_idx);
1896 for (elem = 0; elem < nelem; elem++)
1898 double avg = getavg (elem);
1900 if (avg < 0)
1901 break;
1902 loadavg[elem] = avg;
1905 return elem;
1908 /* Emulate getpwuid, getpwnam and others. */
1910 #define PASSWD_FIELD_SIZE 256
1912 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1913 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1914 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1915 static char dflt_passwd_dir[MAX_UTF8_PATH];
1916 static char dflt_passwd_shell[MAX_UTF8_PATH];
1918 static struct passwd dflt_passwd =
1920 dflt_passwd_name,
1921 dflt_passwd_passwd,
1925 dflt_passwd_gecos,
1926 dflt_passwd_dir,
1927 dflt_passwd_shell,
1930 static char dflt_group_name[GNLEN+1];
1932 static struct group dflt_group =
1934 /* When group information is not available, we return this as the
1935 group for all files. */
1936 dflt_group_name,
1940 unsigned
1941 getuid (void)
1943 return dflt_passwd.pw_uid;
1946 unsigned
1947 geteuid (void)
1949 /* I could imagine arguing for checking to see whether the user is
1950 in the Administrators group and returning a UID of 0 for that
1951 case, but I don't know how wise that would be in the long run. */
1952 return getuid ();
1955 unsigned
1956 getgid (void)
1958 return dflt_passwd.pw_gid;
1961 unsigned
1962 getegid (void)
1964 return getgid ();
1967 struct passwd *
1968 getpwuid (unsigned uid)
1970 if (uid == dflt_passwd.pw_uid)
1971 return &dflt_passwd;
1972 return NULL;
1975 struct group *
1976 getgrgid (gid_t gid)
1978 return &dflt_group;
1981 struct passwd *
1982 getpwnam (char *name)
1984 struct passwd *pw;
1986 pw = getpwuid (getuid ());
1987 if (!pw)
1988 return pw;
1990 if (xstrcasecmp (name, pw->pw_name))
1991 return NULL;
1993 return pw;
1996 static void
1997 init_user_info (void)
1999 /* Find the user's real name by opening the process token and
2000 looking up the name associated with the user-sid in that token.
2002 Use the relative portion of the identifier authority value from
2003 the user-sid as the user id value (same for group id using the
2004 primary group sid from the process token). */
2006 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
2007 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
2008 DWORD glength = sizeof (gname);
2009 HANDLE token = NULL;
2010 SID_NAME_USE user_type;
2011 unsigned char *buf = NULL;
2012 DWORD blen = 0;
2013 TOKEN_USER user_token;
2014 TOKEN_PRIMARY_GROUP group_token;
2015 BOOL result;
2017 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
2018 if (result)
2020 result = get_token_information (token, TokenUser, NULL, 0, &blen);
2021 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2023 buf = xmalloc (blen);
2024 result = get_token_information (token, TokenUser,
2025 (LPVOID)buf, blen, &needed);
2026 if (result)
2028 memcpy (&user_token, buf, sizeof (user_token));
2029 result = lookup_account_sid (NULL, user_token.User.Sid,
2030 uname, &ulength,
2031 domain, &dlength, &user_type);
2034 else
2035 result = FALSE;
2037 if (result)
2039 strcpy (dflt_passwd.pw_name, uname);
2040 /* Determine a reasonable uid value. */
2041 if (xstrcasecmp ("administrator", uname) == 0)
2043 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
2044 dflt_passwd.pw_gid = 513; /* well-known None gid */
2046 else
2048 /* Use the last sub-authority value of the RID, the relative
2049 portion of the SID, as user/group ID. */
2050 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
2052 /* Get group id and name. */
2053 result = get_token_information (token, TokenPrimaryGroup,
2054 (LPVOID)buf, blen, &needed);
2055 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2057 buf = xrealloc (buf, blen = needed);
2058 result = get_token_information (token, TokenPrimaryGroup,
2059 (LPVOID)buf, blen, &needed);
2061 if (result)
2063 memcpy (&group_token, buf, sizeof (group_token));
2064 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
2065 dlength = sizeof (domain);
2066 /* If we can get at the real Primary Group name, use that.
2067 Otherwise, the default group name was already set to
2068 "None" in globals_of_w32. */
2069 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
2070 gname, &glength, NULL, &dlength,
2071 &user_type))
2072 strcpy (dflt_group_name, gname);
2074 else
2075 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2078 /* If security calls are not supported (presumably because we
2079 are running under Windows 9X), fallback to this: */
2080 else if (GetUserName (uname, &ulength))
2082 strcpy (dflt_passwd.pw_name, uname);
2083 if (xstrcasecmp ("administrator", uname) == 0)
2084 dflt_passwd.pw_uid = 0;
2085 else
2086 dflt_passwd.pw_uid = 123;
2087 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2089 else
2091 strcpy (dflt_passwd.pw_name, "unknown");
2092 dflt_passwd.pw_uid = 123;
2093 dflt_passwd.pw_gid = 123;
2095 dflt_group.gr_gid = dflt_passwd.pw_gid;
2097 /* Set dir and shell from environment variables. */
2098 if (w32_unicode_filenames)
2100 wchar_t *home = _wgetenv (L"HOME");
2101 wchar_t *shell = _wgetenv (L"SHELL");
2103 /* Ensure HOME and SHELL are defined. */
2104 if (home == NULL)
2105 emacs_abort ();
2106 if (shell == NULL)
2107 emacs_abort ();
2108 filename_from_utf16 (home, dflt_passwd.pw_dir);
2109 filename_from_utf16 (shell, dflt_passwd.pw_shell);
2111 else
2113 char *home = getenv ("HOME");
2114 char *shell = getenv ("SHELL");
2116 if (home == NULL)
2117 emacs_abort ();
2118 if (shell == NULL)
2119 emacs_abort ();
2120 filename_from_ansi (home, dflt_passwd.pw_dir);
2121 filename_from_ansi (shell, dflt_passwd.pw_shell);
2124 xfree (buf);
2125 if (token)
2126 CloseHandle (token);
2129 static HCRYPTPROV w32_crypto_hprov;
2130 static int
2131 w32_init_crypt_random (void)
2133 if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL,
2134 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2136 DebPrint (("CryptAcquireContext failed with error %x\n",
2137 GetLastError ()));
2138 w32_crypto_hprov = 0;
2139 return -1;
2141 return 0;
2145 w32_init_random (void *buf, ptrdiff_t buflen)
2147 if (!w32_crypto_hprov)
2148 w32_init_crypt_random ();
2149 if (w32_crypto_hprov)
2151 if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf))
2152 return 0;
2154 return -1;
2158 random (void)
2160 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
2161 return ((rand () << 15) | rand ());
2164 void
2165 srandom (int seed)
2167 srand (seed);
2170 /* Return the maximum length in bytes of a multibyte character
2171 sequence encoded in the current ANSI codepage. This is required to
2172 correctly walk the encoded file names one character at a time. */
2173 static int
2174 max_filename_mbslen (void)
2176 CPINFO cp_info;
2178 codepage_for_filenames (&cp_info);
2179 return cp_info.MaxCharSize;
2182 /* Normalize filename by converting in-place all of its path
2183 separators to the separator specified by PATH_SEP. */
2185 static void
2186 normalize_filename (register char *fp, char path_sep)
2188 char *p2;
2190 /* Always lower-case drive letters a-z, even if the filesystem
2191 preserves case in filenames.
2192 This is so filenames can be compared by string comparison
2193 functions that are case-sensitive. Even case-preserving filesystems
2194 do not distinguish case in drive letters. */
2195 p2 = fp + 1;
2197 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2199 *fp += 'a' - 'A';
2200 fp += 2;
2203 while (*fp)
2205 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2206 *fp = path_sep;
2207 fp++;
2211 /* Destructively turn backslashes into slashes. */
2212 void
2213 dostounix_filename (register char *p)
2215 normalize_filename (p, '/');
2218 /* Destructively turn slashes into backslashes. */
2219 void
2220 unixtodos_filename (register char *p)
2222 normalize_filename (p, '\\');
2225 /* Remove all CR's that are followed by a LF.
2226 (From msdos.c...probably should figure out a way to share it,
2227 although this code isn't going to ever change.) */
2228 static int
2229 crlf_to_lf (register int n, register char *buf)
2231 unsigned char *np = (unsigned char *)buf;
2232 unsigned char *startp = np;
2233 char *endp = buf + n;
2235 if (n == 0)
2236 return n;
2237 while (buf < endp - 1)
2239 if (*buf == 0x0d)
2241 if (*(++buf) != 0x0a)
2242 *np++ = 0x0d;
2244 else
2245 *np++ = *buf++;
2247 if (buf < endp)
2248 *np++ = *buf++;
2249 return np - startp;
2252 /* Parse the root part of file name, if present. Return length and
2253 optionally store pointer to char after root. */
2254 static int
2255 parse_root (const char * name, const char ** pPath)
2257 const char * start = name;
2259 if (name == NULL)
2260 return 0;
2262 /* find the root name of the volume if given */
2263 if (isalpha (name[0]) && name[1] == ':')
2265 /* skip past drive specifier */
2266 name += 2;
2267 if (IS_DIRECTORY_SEP (name[0]))
2268 name++;
2270 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2272 int slashes = 2;
2274 name += 2;
2277 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2278 break;
2279 name++;
2281 while ( *name );
2282 if (IS_DIRECTORY_SEP (name[0]))
2283 name++;
2286 if (pPath)
2287 *pPath = name;
2289 return name - start;
2292 /* Get long base name for name; name is assumed to be absolute. */
2293 static int
2294 get_long_basename (char * name, char * buf, int size)
2296 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2297 char fname_utf8[MAX_UTF8_PATH];
2298 int len = 0;
2299 int cstatus = -1;
2301 /* Must be valid filename, no wild cards or other invalid characters. */
2302 if (strpbrk (name, "*?|<>\""))
2303 return 0;
2305 if (w32_unicode_filenames)
2307 wchar_t fname_utf16[MAX_PATH];
2308 WIN32_FIND_DATAW find_data_wide;
2310 filename_to_utf16 (name, fname_utf16);
2311 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2312 if (dir_handle != INVALID_HANDLE_VALUE)
2313 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2315 else
2317 char fname_ansi[MAX_PATH];
2318 WIN32_FIND_DATAA find_data_ansi;
2320 filename_to_ansi (name, fname_ansi);
2321 /* If the ANSI name includes ? characters, it is not encodable
2322 in the ANSI codepage. In that case, we deliver the question
2323 marks to the caller; calling FindFirstFileA in this case
2324 could return some unrelated file name in the same
2325 directory. */
2326 if (_mbspbrk (fname_ansi, "?"))
2328 /* Find the basename of fname_ansi. */
2329 char *p = strrchr (fname_ansi, '\\');
2331 if (!p)
2332 p = fname_ansi;
2333 else
2334 p++;
2335 cstatus = filename_from_ansi (p, fname_utf8);
2337 else
2339 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2340 if (dir_handle != INVALID_HANDLE_VALUE)
2341 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2345 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2346 memcpy (buf, fname_utf8, len + 1);
2347 else
2348 len = 0;
2350 if (dir_handle != INVALID_HANDLE_VALUE)
2351 FindClose (dir_handle);
2353 return len;
2356 /* Get long name for file, if possible (assumed to be absolute). */
2357 BOOL
2358 w32_get_long_filename (const char * name, char * buf, int size)
2360 char * o = buf;
2361 char * p;
2362 const char * q;
2363 char full[ MAX_UTF8_PATH ];
2364 int len;
2366 len = strlen (name);
2367 if (len >= MAX_UTF8_PATH)
2368 return FALSE;
2370 /* Use local copy for destructive modification. */
2371 memcpy (full, name, len+1);
2372 unixtodos_filename (full);
2374 /* Copy root part verbatim. */
2375 len = parse_root (full, (const char **)&p);
2376 memcpy (o, full, len);
2377 o += len;
2378 *o = '\0';
2379 size -= len;
2381 while (p != NULL && *p)
2383 q = p;
2384 p = strchr (q, '\\');
2385 if (p) *p = '\0';
2386 len = get_long_basename (full, o, size);
2387 if (len > 0)
2389 o += len;
2390 size -= len;
2391 if (p != NULL)
2393 *p++ = '\\';
2394 if (size < 2)
2395 return FALSE;
2396 *o++ = '\\';
2397 size--;
2398 *o = '\0';
2401 else
2402 return FALSE;
2405 return TRUE;
2408 unsigned int
2409 w32_get_short_filename (const char * name, char * buf, int size)
2411 if (w32_unicode_filenames)
2413 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2414 unsigned int retval;
2416 filename_to_utf16 (name, name_utf16);
2417 retval = GetShortPathNameW (name_utf16, short_name, size);
2418 if (retval && retval < size)
2419 filename_from_utf16 (short_name, buf);
2420 return retval;
2422 else
2424 char name_ansi[MAX_PATH];
2426 filename_to_ansi (name, name_ansi);
2427 return GetShortPathNameA (name_ansi, buf, size);
2431 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2432 MS-Windows ANSI codepage. If FILENAME includes characters not
2433 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2434 if it exists. This is needed because the w32 build wants to
2435 support file names outside of the system locale, but image
2436 libraries typically don't support wide (a.k.a. "Unicode") APIs
2437 required for that. */
2439 Lisp_Object
2440 ansi_encode_filename (Lisp_Object filename)
2442 Lisp_Object encoded_filename;
2443 char fname[MAX_PATH];
2445 filename_to_ansi (SSDATA (filename), fname);
2446 if (_mbspbrk (fname, "?"))
2448 char shortname[MAX_PATH];
2450 if (w32_get_short_filename (SSDATA (filename), shortname, MAX_PATH))
2452 dostounix_filename (shortname);
2453 encoded_filename = build_string (shortname);
2455 else
2456 encoded_filename = build_unibyte_string (fname);
2458 else
2459 encoded_filename = build_unibyte_string (fname);
2460 return encoded_filename;
2463 static int
2464 is_unc_volume (const char *filename)
2466 const char *ptr = filename;
2468 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2469 return 0;
2471 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2472 return 0;
2474 return 1;
2477 /* Emulate the Posix unsetenv. */
2479 unsetenv (const char *name)
2481 char *var;
2482 size_t name_len;
2484 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2486 errno = EINVAL;
2487 return -1;
2489 name_len = strlen (name);
2490 /* MS docs says an environment variable cannot be longer than 32K. */
2491 if (name_len > 32767)
2493 errno = ENOMEM;
2494 return 0;
2496 /* It is safe to use 'alloca' with 32K size, since the stack is at
2497 least 2MB, and we set it to 8MB in the link command line. */
2498 var = alloca (name_len + 2);
2499 strncpy (var, name, name_len);
2500 var[name_len++] = '=';
2501 var[name_len] = '\0';
2502 return _putenv (var);
2505 /* MS _putenv doesn't support removing a variable when the argument
2506 does not include the '=' character, so we fix that here. */
2508 sys_putenv (char *str)
2510 const char *const name_end = strchr (str, '=');
2512 if (name_end == NULL)
2514 /* Remove the variable from the environment. */
2515 return unsetenv (str);
2518 if (strncmp (str, "TZ=<", 4) == 0)
2520 /* MS-Windows does not support POSIX.1-2001 angle-bracket TZ
2521 abbreviation syntax. Convert to POSIX.1-1988 syntax if possible,
2522 and to the undocumented placeholder "ZZZ" otherwise. */
2523 bool supported_abbr = true;
2524 for (char *p = str + 4; *p; p++)
2526 if (('0' <= *p && *p <= '9') || *p == '-' || *p == '+')
2527 supported_abbr = false;
2528 else if (*p == '>')
2530 ptrdiff_t abbrlen;
2531 if (supported_abbr)
2533 abbrlen = p - (str + 4);
2534 memmove (str + 3, str + 4, abbrlen);
2536 else
2538 abbrlen = 3;
2539 memset (str + 3, 'Z', abbrlen);
2541 memmove (str + 3 + abbrlen, p + 1, strlen (p));
2542 break;
2547 return _putenv (str);
2550 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2552 LPBYTE
2553 w32_get_resource (const char *key, LPDWORD lpdwtype)
2555 LPBYTE lpvalue;
2556 HKEY hrootkey = NULL;
2557 DWORD cbData;
2559 /* Check both the current user and the local machine to see if
2560 we have any resources. */
2562 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2564 lpvalue = NULL;
2566 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2567 && (lpvalue = xmalloc (cbData)) != NULL
2568 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2570 RegCloseKey (hrootkey);
2571 return (lpvalue);
2574 xfree (lpvalue);
2576 RegCloseKey (hrootkey);
2579 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2581 lpvalue = NULL;
2583 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2584 && (lpvalue = xmalloc (cbData)) != NULL
2585 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2587 RegCloseKey (hrootkey);
2588 return (lpvalue);
2591 xfree (lpvalue);
2593 RegCloseKey (hrootkey);
2596 return (NULL);
2599 /* The argv[] array holds ANSI-encoded strings, and so this function
2600 works with ANS_encoded strings. */
2601 void
2602 init_environment (char ** argv)
2604 static const char * const tempdirs[] = {
2605 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2608 int i;
2610 const int imax = ARRAYELTS (tempdirs);
2612 /* Implementation note: This function explicitly works with ANSI
2613 file names, not with UTF-8 encoded file names. This is because
2614 this function pushes variables into the Emacs's environment, and
2615 the environment variables are always assumed to be in the
2616 locale-specific encoding. Do NOT call any functions that accept
2617 UTF-8 file names from this function! */
2619 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2620 temporary files and assume "/tmp" if $TMPDIR is unset, which
2621 will break on DOS/Windows. Refuse to work if we cannot find
2622 a directory, not even "c:/", usable for that purpose. */
2623 for (i = 0; i < imax ; i++)
2625 const char *tmp = tempdirs[i];
2627 if (*tmp == '$')
2628 tmp = getenv (tmp + 1);
2629 /* Note that `access' can lie to us if the directory resides on a
2630 read-only filesystem, like CD-ROM or a write-protected floppy.
2631 The only way to be really sure is to actually create a file and
2632 see if it succeeds. But I think that's too much to ask. */
2634 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2635 if (tmp && sys_access (tmp, D_OK) == 0)
2637 char * var = alloca (strlen (tmp) + 8);
2638 sprintf (var, "TMPDIR=%s", tmp);
2639 _putenv (strdup (var));
2640 break;
2643 if (i >= imax)
2644 cmd_error_internal
2645 (Fcons (Qerror,
2646 Fcons (build_string ("no usable temporary directories found!!"),
2647 Qnil)),
2648 "While setting TMPDIR: ");
2650 /* Check for environment variables and use registry settings if they
2651 don't exist. Fallback on default values where applicable. */
2653 int i;
2654 LPBYTE lpval;
2655 DWORD dwType;
2656 char locale_name[32];
2657 char default_home[MAX_PATH];
2658 int appdata = 0;
2660 static const struct env_entry
2662 const char * name;
2663 const char * def_value;
2664 } dflt_envvars[] =
2666 /* If the default value is NULL, we will use the value from the
2667 outside environment or the Registry, but will not push the
2668 variable into the Emacs environment if it is defined neither
2669 in the Registry nor in the outside environment. */
2670 {"HOME", "C:/"},
2671 {"PRELOAD_WINSOCK", NULL},
2672 {"emacs_dir", "C:/emacs"},
2673 {"EMACSLOADPATH", NULL},
2674 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2675 {"EMACSDATA", NULL},
2676 {"EMACSPATH", NULL},
2677 {"INFOPATH", NULL},
2678 {"EMACSDOC", NULL},
2679 {"TERM", "cmd"},
2680 {"LANG", NULL},
2683 #define N_ENV_VARS ARRAYELTS (dflt_envvars)
2685 /* We need to copy dflt_envvars[] and work on the copy because we
2686 don't want the dumped Emacs to inherit the values of
2687 environment variables we saw during dumping (which could be on
2688 a different system). The defaults above must be left intact. */
2689 struct env_entry env_vars[N_ENV_VARS];
2691 for (i = 0; i < N_ENV_VARS; i++)
2692 env_vars[i] = dflt_envvars[i];
2694 /* For backwards compatibility, check if a .emacs file exists in C:/
2695 If not, then we can try to default to the appdata directory under the
2696 user's profile, which is more likely to be writable. */
2697 if (sys_access ("C:/.emacs", F_OK) != 0)
2699 HRESULT profile_result;
2700 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2701 of Windows 95 and NT4 that have not been updated to include
2702 MSIE 5. */
2703 ShGetFolderPath_fn get_folder_path;
2704 get_folder_path = (ShGetFolderPath_fn)
2705 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2707 if (get_folder_path != NULL)
2709 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2710 0, default_home);
2712 /* If we can't get the appdata dir, revert to old behavior. */
2713 if (profile_result == S_OK)
2715 env_vars[0].def_value = default_home;
2716 appdata = 1;
2721 /* Get default locale info and use it for LANG. */
2722 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2723 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2724 locale_name, sizeof (locale_name)))
2726 for (i = 0; i < N_ENV_VARS; i++)
2728 if (strcmp (env_vars[i].name, "LANG") == 0)
2730 env_vars[i].def_value = locale_name;
2731 break;
2736 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2738 /* Treat emacs_dir specially: set it unconditionally based on our
2739 location. */
2741 char *p;
2742 char modname[MAX_PATH];
2744 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2745 emacs_abort ();
2746 if ((p = _mbsrchr (modname, '\\')) == NULL)
2747 emacs_abort ();
2748 *p = 0;
2750 if ((p = _mbsrchr (modname, '\\'))
2751 /* From bin means installed Emacs, from src means uninstalled. */
2752 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2754 char buf[SET_ENV_BUF_SIZE];
2755 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2757 *p = 0;
2758 for (p = modname; *p; p = CharNext (p))
2759 if (*p == '\\') *p = '/';
2761 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2762 _putenv (strdup (buf));
2763 /* If we are running from the Posix-like build tree, define
2764 SHELL to point to our own cmdproxy. The loop below will
2765 then disregard PATH_EXEC and the default value. */
2766 if (within_build_tree)
2768 _snprintf (buf, sizeof (buf) - 1,
2769 "SHELL=%s/nt/cmdproxy.exe", modname);
2770 _putenv (strdup (buf));
2775 for (i = 0; i < N_ENV_VARS; i++)
2777 if (!getenv (env_vars[i].name))
2779 int dont_free = 0;
2780 char bufc[SET_ENV_BUF_SIZE];
2782 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2783 /* Also ignore empty environment variables. */
2784 || *lpval == 0)
2786 xfree (lpval);
2787 dont_free = 1;
2788 if (strcmp (env_vars[i].name, "SHELL") == 0)
2790 /* Look for cmdproxy.exe in every directory in
2791 PATH_EXEC. FIXME: This does not find cmdproxy
2792 in nt/ when we run uninstalled. */
2793 char fname[MAX_PATH];
2794 const char *pstart = PATH_EXEC, *pend;
2796 do {
2797 pend = _mbschr (pstart, ';');
2798 if (!pend)
2799 pend = pstart + strlen (pstart);
2800 /* Be defensive against series of ;;; characters. */
2801 if (pend > pstart)
2803 strncpy (fname, pstart, pend - pstart);
2804 fname[pend - pstart] = '/';
2805 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2806 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2807 sizeof (bufc));
2808 if (sys_access (bufc, F_OK) == 0)
2810 lpval = bufc;
2811 dwType = REG_SZ;
2812 break;
2815 if (*pend)
2816 pstart = pend + 1;
2817 else
2818 pstart = pend;
2819 if (!*pstart)
2821 /* If not found in any directory, use the
2822 default as the last resort. */
2823 lpval = (char *)env_vars[i].def_value;
2824 dwType = REG_EXPAND_SZ;
2826 } while (*pstart);
2828 else
2830 lpval = (char *)env_vars[i].def_value;
2831 dwType = REG_EXPAND_SZ;
2833 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2834 Vdelayed_warnings_list
2835 = Fcons
2836 (listn (CONSTYPE_HEAP, 2,
2837 intern ("initialization"), build_string
2838 ("Use of `C:\\.emacs' without defining `HOME'\n"
2839 "in the environment is deprecated, "
2840 "see `Windows HOME' in the Emacs manual.")),
2841 Vdelayed_warnings_list);
2844 if (lpval)
2846 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2848 if (dwType == REG_EXPAND_SZ)
2849 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2850 else if (dwType == REG_SZ)
2851 strcpy (buf1, (char *)lpval);
2852 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2854 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2855 buf1);
2856 _putenv (strdup (buf2));
2859 if (!dont_free)
2860 xfree (lpval);
2866 /* Rebuild system configuration to reflect invoking system. */
2867 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2869 /* Another special case: on NT, the PATH variable is actually named
2870 "Path" although cmd.exe (perhaps NT itself) arranges for
2871 environment variable lookup and setting to be case insensitive.
2872 However, Emacs assumes a fully case sensitive environment, so we
2873 need to change "Path" to "PATH" to match the expectations of
2874 various elisp packages. We do this by the sneaky method of
2875 modifying the string in the C runtime environ entry.
2877 The same applies to COMSPEC. */
2879 char ** envp;
2880 const char *path = "PATH=";
2881 int path_len = strlen (path);
2882 const char *comspec = "COMSPEC=";
2883 int comspec_len = strlen (comspec);
2885 for (envp = environ; *envp; envp++)
2886 if (_strnicmp (*envp, path, path_len) == 0)
2887 memcpy (*envp, path, path_len);
2888 else if (_strnicmp (*envp, comspec, comspec_len) == 0)
2889 memcpy (*envp, comspec, comspec_len);
2891 /* Make the same modification to `process-environment' which has
2892 already been initialized in set_initial_environment. */
2893 for (Lisp_Object env = Vprocess_environment; CONSP (env); env = XCDR (env))
2895 Lisp_Object entry = XCAR (env);
2896 if (_strnicmp (SDATA (entry), path, path_len) == 0)
2897 for (int i = 0; i < path_len; i++)
2898 SSET (entry, i, path[i]);
2899 else if (_strnicmp (SDATA (entry), comspec, comspec_len) == 0)
2900 for (int i = 0; i < comspec_len; i++)
2901 SSET (entry, i, comspec[i]);
2905 /* Remember the initial working directory for getcwd. */
2906 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2907 Does it matter anywhere in Emacs? */
2908 if (w32_unicode_filenames)
2910 wchar_t wstartup_dir[MAX_PATH];
2912 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2913 emacs_abort ();
2914 filename_from_utf16 (wstartup_dir, startup_dir);
2916 else
2918 char astartup_dir[MAX_PATH];
2920 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2921 emacs_abort ();
2922 filename_from_ansi (astartup_dir, startup_dir);
2926 static char modname[MAX_PATH];
2928 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2929 emacs_abort ();
2930 argv[0] = modname;
2933 /* Determine if there is a middle mouse button, to allow parse_button
2934 to decide whether right mouse events should be mouse-2 or
2935 mouse-3. */
2936 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2938 init_user_info ();
2941 /* Called from expand-file-name when default-directory is not a string. */
2943 char *
2944 emacs_root_dir (void)
2946 static char root_dir[MAX_UTF8_PATH];
2947 const char *p;
2949 p = getenv ("emacs_dir");
2950 if (p == NULL)
2951 emacs_abort ();
2952 filename_from_ansi (p, root_dir);
2953 root_dir[parse_root (root_dir, NULL)] = '\0';
2954 dostounix_filename (root_dir);
2955 return root_dir;
2958 #include <sys/timeb.h>
2960 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2962 gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
2964 struct _timeb tb;
2965 _ftime (&tb);
2967 tv->tv_sec = tb.time;
2968 tv->tv_usec = tb.millitm * 1000L;
2969 /* Implementation note: _ftime sometimes doesn't update the dstflag
2970 according to the new timezone when the system timezone is
2971 changed. We could fix that by using GetSystemTime and
2972 GetTimeZoneInformation, but that doesn't seem necessary, since
2973 Emacs always calls gettimeofday with the 2nd argument NULL (see
2974 current_emacs_time). */
2975 if (tz)
2977 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2978 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2980 return 0;
2983 /* Emulate fdutimens. */
2985 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2986 TIMESPEC[0] and TIMESPEC[1], respectively.
2987 FD must be either negative -- in which case it is ignored --
2988 or a file descriptor that is open on FILE.
2989 If FD is nonnegative, then FILE can be NULL, which means
2990 use just futimes instead of utimes.
2991 If TIMESPEC is null, FAIL.
2992 Return 0 on success, -1 (setting errno) on failure. */
2995 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2997 if (!timespec)
2999 errno = ENOSYS;
3000 return -1;
3002 if (fd < 0 && !file)
3004 errno = EBADF;
3005 return -1;
3007 /* _futime's prototype defines 2nd arg as having the type 'struct
3008 _utimbuf', while utime needs to accept 'struct utimbuf' for
3009 compatibility with Posix. So we need to use 2 different (but
3010 equivalent) types to avoid compiler warnings, sigh. */
3011 if (fd >= 0)
3013 struct _utimbuf _ut;
3015 _ut.actime = timespec[0].tv_sec;
3016 _ut.modtime = timespec[1].tv_sec;
3017 return _futime (fd, &_ut);
3019 else
3021 struct utimbuf ut;
3023 ut.actime = timespec[0].tv_sec;
3024 ut.modtime = timespec[1].tv_sec;
3025 /* Call 'utime', which is implemented below, not the MS library
3026 function, which fails on directories. */
3027 return utime (file, &ut);
3032 /* ------------------------------------------------------------------------- */
3033 /* IO support and wrapper functions for the Windows API. */
3034 /* ------------------------------------------------------------------------- */
3036 /* Place a wrapper around the MSVC version of ctime. It returns NULL
3037 on network directories, so we handle that case here.
3038 (Ulrich Leodolter, 1/11/95). */
3039 char *
3040 sys_ctime (const time_t *t)
3042 char *str = (char *) ctime (t);
3043 return (str ? str : (char *)"Sun Jan 01 00:00:00 1970");
3046 /* Emulate sleep...we could have done this with a define, but that
3047 would necessitate including windows.h in the files that used it.
3048 This is much easier. */
3049 void
3050 sys_sleep (int seconds)
3052 Sleep (seconds * 1000);
3055 /* Internal MSVC functions for low-level descriptor munging */
3056 extern int __cdecl _set_osfhnd (int fd, long h);
3057 extern int __cdecl _free_osfhnd (int fd);
3059 /* parallel array of private info on file handles */
3060 filedesc fd_info [ MAXDESC ];
3062 typedef struct volume_info_data {
3063 struct volume_info_data * next;
3065 /* time when info was obtained */
3066 DWORD timestamp;
3068 /* actual volume info */
3069 char * root_dir;
3070 DWORD serialnum;
3071 DWORD maxcomp;
3072 DWORD flags;
3073 char * name;
3074 char * type;
3075 } volume_info_data;
3077 /* Global referenced by various functions. */
3078 static volume_info_data volume_info;
3080 /* Vector to indicate which drives are local and fixed (for which cached
3081 data never expires). */
3082 static BOOL fixed_drives[26];
3084 /* Consider cached volume information to be stale if older than 10s,
3085 at least for non-local drives. Info for fixed drives is never stale. */
3086 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
3087 #define VOLINFO_STILL_VALID( root_dir, info ) \
3088 ( ( isalpha (root_dir[0]) && \
3089 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
3090 || GetTickCount () - info->timestamp < 10000 )
3092 /* Cache support functions. */
3094 /* Simple linked list with linear search is sufficient. */
3095 static volume_info_data *volume_cache = NULL;
3097 static volume_info_data *
3098 lookup_volume_info (char * root_dir)
3100 volume_info_data * info;
3102 for (info = volume_cache; info; info = info->next)
3103 if (xstrcasecmp (info->root_dir, root_dir) == 0)
3104 break;
3105 return info;
3108 static void
3109 add_volume_info (char * root_dir, volume_info_data * info)
3111 info->root_dir = xstrdup (root_dir);
3112 unixtodos_filename (info->root_dir);
3113 info->next = volume_cache;
3114 volume_cache = info;
3118 /* Wrapper for GetVolumeInformation, which uses caching to avoid
3119 performance penalty (~2ms on 486 for local drives, 7.5ms for local
3120 cdrom drive, ~5-10ms or more for remote drives on LAN). */
3121 static volume_info_data *
3122 GetCachedVolumeInformation (char * root_dir)
3124 volume_info_data * info;
3125 char default_root[ MAX_UTF8_PATH ];
3126 char name[MAX_PATH+1];
3127 char type[MAX_PATH+1];
3129 /* NULL for root_dir means use root from current directory. */
3130 if (root_dir == NULL)
3132 if (w32_unicode_filenames)
3134 wchar_t curdirw[MAX_PATH];
3136 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
3137 return NULL;
3138 filename_from_utf16 (curdirw, default_root);
3140 else
3142 char curdira[MAX_PATH];
3144 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
3145 return NULL;
3146 filename_from_ansi (curdira, default_root);
3148 parse_root (default_root, (const char **)&root_dir);
3149 *root_dir = 0;
3150 root_dir = default_root;
3153 /* Local fixed drives can be cached permanently. Removable drives
3154 cannot be cached permanently, since the volume name and serial
3155 number (if nothing else) can change. Remote drives should be
3156 treated as if they are removable, since there is no sure way to
3157 tell whether they are or not. Also, the UNC association of drive
3158 letters mapped to remote volumes can be changed at any time (even
3159 by other processes) without notice.
3161 As a compromise, so we can benefit from caching info for remote
3162 volumes, we use a simple expiry mechanism to invalidate cache
3163 entries that are more than ten seconds old. */
3165 #if 0
3166 /* No point doing this, because WNetGetConnection is even slower than
3167 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
3168 GetDriveType is about the only call of this type which does not
3169 involve network access, and so is extremely quick). */
3171 /* Map drive letter to UNC if remote. */
3172 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
3174 char remote_name[ 256 ];
3175 char drive[3] = { root_dir[0], ':' };
3177 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
3178 == NO_ERROR)
3179 /* do something */ ;
3181 #endif
3183 info = lookup_volume_info (root_dir);
3185 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
3187 DWORD serialnum;
3188 DWORD maxcomp;
3189 DWORD flags;
3191 /* Info is not cached, or is stale. */
3192 if (w32_unicode_filenames)
3194 wchar_t root_w[MAX_PATH];
3195 wchar_t name_w[MAX_PATH+1];
3196 wchar_t type_w[MAX_PATH+1];
3198 filename_to_utf16 (root_dir, root_w);
3199 if (!GetVolumeInformationW (root_w,
3200 name_w, sizeof (name_w),
3201 &serialnum,
3202 &maxcomp,
3203 &flags,
3204 type_w, sizeof (type_w)))
3205 return NULL;
3206 /* Hmm... not really 100% correct, as these 2 are not file
3207 names... */
3208 filename_from_utf16 (name_w, name);
3209 filename_from_utf16 (type_w, type);
3211 else
3213 char root_a[MAX_PATH];
3214 char name_a[MAX_PATH+1];
3215 char type_a[MAX_PATH+1];
3217 filename_to_ansi (root_dir, root_a);
3218 if (!GetVolumeInformationA (root_a,
3219 name_a, sizeof (name_a),
3220 &serialnum,
3221 &maxcomp,
3222 &flags,
3223 type_a, sizeof (type_a)))
3224 return NULL;
3225 filename_from_ansi (name_a, name);
3226 filename_from_ansi (type_a, type);
3229 /* Cache the volume information for future use, overwriting existing
3230 entry if present. */
3231 if (info == NULL)
3233 info = xmalloc (sizeof (volume_info_data));
3234 add_volume_info (root_dir, info);
3236 else
3238 xfree (info->name);
3239 xfree (info->type);
3242 info->name = xstrdup (name);
3243 unixtodos_filename (info->name);
3244 info->serialnum = serialnum;
3245 info->maxcomp = maxcomp;
3246 info->flags = flags;
3247 info->type = xstrdup (type);
3248 info->timestamp = GetTickCount ();
3251 return info;
3254 /* Get information on the volume where NAME is held; set path pointer to
3255 start of pathname in NAME (past UNC header\volume header if present),
3256 if pPath is non-NULL.
3258 Note: if NAME includes symlinks, the information is for the volume
3259 of the symlink, not of its target. That's because, even though
3260 GetVolumeInformation returns information about the symlink target
3261 of its argument, we only pass the root directory to
3262 GetVolumeInformation, not the full NAME. */
3263 static int
3264 get_volume_info (const char * name, const char ** pPath)
3266 char temp[MAX_UTF8_PATH];
3267 char *rootname = NULL; /* default to current volume */
3268 volume_info_data * info;
3269 int root_len = parse_root (name, pPath);
3271 if (name == NULL)
3272 return FALSE;
3274 /* Copy the root name of the volume, if given. */
3275 if (root_len)
3277 strncpy (temp, name, root_len);
3278 temp[root_len] = '\0';
3279 unixtodos_filename (temp);
3280 rootname = temp;
3283 info = GetCachedVolumeInformation (rootname);
3284 if (info != NULL)
3286 /* Set global referenced by other functions. */
3287 volume_info = *info;
3288 return TRUE;
3290 return FALSE;
3293 /* Determine if volume is FAT format (ie. only supports short 8.3
3294 names); also set path pointer to start of pathname in name, if
3295 pPath is non-NULL. */
3296 static int
3297 is_fat_volume (const char * name, const char ** pPath)
3299 if (get_volume_info (name, pPath))
3300 return (volume_info.maxcomp == 12);
3301 return FALSE;
3304 /* Convert all slashes in a filename to backslashes, and map filename
3305 to a valid 8.3 name if necessary. The result is a pointer to a
3306 static buffer, so CAVEAT EMPTOR! */
3307 const char *map_w32_filename (const char *, const char **);
3309 const char *
3310 map_w32_filename (const char * name, const char ** pPath)
3312 static char shortname[MAX_UTF8_PATH];
3313 char * str = shortname;
3314 char c;
3315 char * path;
3316 const char * save_name = name;
3318 if (strlen (name) >= sizeof (shortname))
3320 /* Return a filename which will cause callers to fail. */
3321 strcpy (shortname, "?");
3322 return shortname;
3325 if (!fatal_error_in_progress /* disable fancy processing during crash */
3326 && is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3328 register int left = 8; /* maximum number of chars in part */
3329 register int extn = 0; /* extension added? */
3330 register int dots = 2; /* maximum number of dots allowed */
3332 while (name < path)
3333 *str++ = *name++; /* skip past UNC header */
3335 while ((c = *name++))
3337 switch ( c )
3339 case ':':
3340 case '\\':
3341 case '/':
3342 *str++ = (c == ':' ? ':' : '\\');
3343 extn = 0; /* reset extension flags */
3344 dots = 2; /* max 2 dots */
3345 left = 8; /* max length 8 for main part */
3346 break;
3347 case '.':
3348 if ( dots )
3350 /* Convert path components of the form .xxx to _xxx,
3351 but leave . and .. as they are. This allows .emacs
3352 to be read as _emacs, for example. */
3354 if (! *name ||
3355 *name == '.' ||
3356 IS_DIRECTORY_SEP (*name))
3358 *str++ = '.';
3359 dots--;
3361 else
3363 *str++ = '_';
3364 left--;
3365 dots = 0;
3368 else if ( !extn )
3370 *str++ = '.';
3371 extn = 1; /* we've got an extension */
3372 left = 3; /* 3 chars in extension */
3374 else
3376 /* any embedded dots after the first are converted to _ */
3377 *str++ = '_';
3379 break;
3380 case '~':
3381 case '#': /* don't lose these, they're important */
3382 if ( ! left )
3383 str[-1] = c; /* replace last character of part */
3384 /* FALLTHRU */
3385 default:
3386 if ( left && 'A' <= c && c <= 'Z' )
3388 *str++ = tolower (c); /* map to lower case (looks nicer) */
3389 left--;
3390 dots = 0; /* started a path component */
3392 break;
3395 *str = '\0';
3397 else
3399 strcpy (shortname, name);
3400 unixtodos_filename (shortname);
3403 if (pPath)
3404 *pPath = shortname + (path - save_name);
3406 return shortname;
3409 static int
3410 is_exec (const char * name)
3412 char * p = strrchr (name, '.');
3413 return
3414 (p != NULL
3415 && (xstrcasecmp (p, ".exe") == 0 ||
3416 xstrcasecmp (p, ".com") == 0 ||
3417 xstrcasecmp (p, ".bat") == 0 ||
3418 xstrcasecmp (p, ".cmd") == 0));
3421 /* Emulate the Unix directory procedures opendir, closedir, and
3422 readdir. We rename them to sys_* names because some versions of
3423 MinGW startup code call opendir and readdir to glob wildcards, and
3424 the code that calls them doesn't grok UTF-8 encoded file names we
3425 produce in dirent->d_name[]. */
3427 struct dirent dir_static; /* simulated directory contents */
3428 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3429 static int dir_is_fat;
3430 static char dir_pathname[MAX_UTF8_PATH];
3431 static WIN32_FIND_DATAW dir_find_data_w;
3432 static WIN32_FIND_DATAA dir_find_data_a;
3433 #define DIR_FIND_DATA_W 1
3434 #define DIR_FIND_DATA_A 2
3435 static int last_dir_find_data = -1;
3437 /* Support shares on a network resource as subdirectories of a read-only
3438 root directory. */
3439 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3440 static HANDLE open_unc_volume (const char *);
3441 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3442 static void close_unc_volume (HANDLE);
3444 DIR *
3445 sys_opendir (const char *filename)
3447 DIR *dirp;
3449 /* Opening is done by FindFirstFile. However, a read is inherent to
3450 this operation, so we defer the open until read time. */
3452 if (dir_find_handle != INVALID_HANDLE_VALUE)
3453 return NULL;
3454 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3455 return NULL;
3457 /* Note: We don't support traversal of UNC volumes via symlinks.
3458 Doing so would mean punishing 99.99% of use cases by resolving
3459 all the possible symlinks in FILENAME, recursively. */
3460 if (is_unc_volume (filename))
3462 wnet_enum_handle = open_unc_volume (filename);
3463 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3464 return NULL;
3467 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3468 return NULL;
3470 dirp->dd_fd = 0;
3471 dirp->dd_loc = 0;
3472 dirp->dd_size = 0;
3474 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3475 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3476 /* Note: We don't support symlinks to file names on FAT volumes.
3477 Doing so would mean punishing 99.99% of use cases by resolving
3478 all the possible symlinks in FILENAME, recursively. */
3479 dir_is_fat = is_fat_volume (filename, NULL);
3481 return dirp;
3484 void
3485 sys_closedir (DIR *dirp)
3487 /* If we have a find-handle open, close it. */
3488 if (dir_find_handle != INVALID_HANDLE_VALUE)
3490 FindClose (dir_find_handle);
3491 dir_find_handle = INVALID_HANDLE_VALUE;
3493 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3495 close_unc_volume (wnet_enum_handle);
3496 wnet_enum_handle = INVALID_HANDLE_VALUE;
3498 xfree ((char *) dirp);
3501 struct dirent *
3502 sys_readdir (DIR *dirp)
3504 int downcase = !NILP (Vw32_downcase_file_names);
3506 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3508 if (!read_unc_volume (wnet_enum_handle,
3509 dir_find_data_w.cFileName,
3510 dir_find_data_a.cFileName,
3511 MAX_PATH))
3512 return NULL;
3514 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3515 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3517 char filename[MAX_UTF8_PATH];
3518 int ln;
3519 bool last_slash = true;
3521 /* Note: We don't need to worry about dir_pathname being longer
3522 than MAX_UTF8_PATH, as sys_opendir already took care of that
3523 when it called map_w32_filename: that function will put a "?"
3524 in its return value in that case, thus failing all the calls
3525 below. */
3526 strcpy (filename, dir_pathname);
3527 ln = strlen (filename);
3528 if (!IS_DIRECTORY_SEP (filename[ln - 1]))
3529 last_slash = false;
3531 /* Note: No need to resolve symlinks in FILENAME, because
3532 FindFirst opens the directory that is the target of a
3533 symlink. */
3534 if (w32_unicode_filenames)
3536 wchar_t fnw[MAX_PATH + 2];
3538 filename_to_utf16 (filename, fnw);
3539 if (!last_slash)
3540 wcscat (fnw, L"\\");
3541 wcscat (fnw, L"*");
3542 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3544 else
3546 char fna[MAX_PATH + 2];
3548 filename_to_ansi (filename, fna);
3549 if (!last_slash)
3550 strcat (fna, "\\");
3551 strcat (fna, "*");
3552 /* If FILENAME is not representable by the current ANSI
3553 codepage, we don't want FindFirstFileA to interpret the
3554 '?' characters as a wildcard. */
3555 if (_mbspbrk (fna, "?"))
3556 dir_find_handle = INVALID_HANDLE_VALUE;
3557 else
3558 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3561 if (dir_find_handle == INVALID_HANDLE_VALUE)
3563 /* Any changes in the value of errno here should be in sync
3564 with what directory_files_internal does when it calls
3565 readdir. */
3566 switch (GetLastError ())
3568 /* Windows uses this value when FindFirstFile finds no
3569 files that match the wildcard. This is not supposed
3570 to happen, since our wildcard is "*", but just in
3571 case, if there's some weird empty directory with not
3572 even "." and ".." entries... */
3573 case ERROR_FILE_NOT_FOUND:
3574 errno = 0;
3575 /* FALLTHRU */
3576 default:
3577 break;
3578 case ERROR_ACCESS_DENIED:
3579 case ERROR_NETWORK_ACCESS_DENIED:
3580 errno = EACCES;
3581 break;
3582 case ERROR_PATH_NOT_FOUND:
3583 case ERROR_INVALID_DRIVE:
3584 case ERROR_NOT_READY:
3585 case ERROR_BAD_NETPATH:
3586 case ERROR_BAD_NET_NAME:
3587 errno = ENOENT;
3588 break;
3590 return NULL;
3593 else if (w32_unicode_filenames)
3595 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3597 errno = 0;
3598 return NULL;
3601 else
3603 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3605 errno = 0;
3606 return NULL;
3610 /* Emacs never uses this value, so don't bother making it match
3611 value returned by stat(). */
3612 dir_static.d_ino = 1;
3614 if (w32_unicode_filenames)
3616 if (downcase || dir_is_fat)
3618 wchar_t tem[MAX_PATH];
3620 wcscpy (tem, dir_find_data_w.cFileName);
3621 CharLowerW (tem);
3622 filename_from_utf16 (tem, dir_static.d_name);
3624 else
3625 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3626 last_dir_find_data = DIR_FIND_DATA_W;
3628 else
3630 char tem[MAX_PATH];
3632 /* If the file name in cFileName[] includes `?' characters, it
3633 means the original file name used characters that cannot be
3634 represented by the current ANSI codepage. To avoid total
3635 lossage, retrieve the short 8+3 alias of the long file
3636 name. */
3637 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3639 strcpy (tem, dir_find_data_a.cAlternateFileName);
3640 /* 8+3 aliases are returned in all caps, which could break
3641 various alists that look at filenames' extensions. */
3642 downcase = 1;
3644 else if (downcase || dir_is_fat)
3645 strcpy (tem, dir_find_data_a.cFileName);
3646 else
3647 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3648 if (downcase || dir_is_fat)
3650 _mbslwr (tem);
3651 filename_from_ansi (tem, dir_static.d_name);
3653 last_dir_find_data = DIR_FIND_DATA_A;
3656 dir_static.d_namlen = strlen (dir_static.d_name);
3657 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3658 dir_static.d_namlen - dir_static.d_namlen % 4;
3660 return &dir_static;
3663 static HANDLE
3664 open_unc_volume (const char *path)
3666 const char *fn = map_w32_filename (path, NULL);
3667 DWORD result;
3668 HANDLE henum;
3670 if (w32_unicode_filenames)
3672 NETRESOURCEW nrw;
3673 wchar_t fnw[MAX_PATH];
3675 nrw.dwScope = RESOURCE_GLOBALNET;
3676 nrw.dwType = RESOURCETYPE_DISK;
3677 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3678 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3679 nrw.lpLocalName = NULL;
3680 filename_to_utf16 (fn, fnw);
3681 nrw.lpRemoteName = fnw;
3682 nrw.lpComment = NULL;
3683 nrw.lpProvider = NULL;
3685 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3686 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3688 else
3690 NETRESOURCEA nra;
3691 char fna[MAX_PATH];
3693 nra.dwScope = RESOURCE_GLOBALNET;
3694 nra.dwType = RESOURCETYPE_DISK;
3695 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3696 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3697 nra.lpLocalName = NULL;
3698 filename_to_ansi (fn, fna);
3699 nra.lpRemoteName = fna;
3700 nra.lpComment = NULL;
3701 nra.lpProvider = NULL;
3703 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3704 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3706 if (result == NO_ERROR)
3707 return henum;
3708 else
3710 /* Make sure directory_files_internal reports a sensible error. */
3711 errno = ENOENT;
3712 return INVALID_HANDLE_VALUE;
3716 static void *
3717 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3719 DWORD count;
3720 int result;
3721 char *buffer;
3722 DWORD bufsize = 512;
3723 void *retval;
3725 count = 1;
3726 if (w32_unicode_filenames)
3728 wchar_t *ptrw;
3730 bufsize *= 2;
3731 buffer = alloca (bufsize);
3732 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3733 if (result != NO_ERROR)
3734 return NULL;
3735 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3736 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3737 ptrw += 2;
3738 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3739 ptrw++;
3740 wcsncpy (fname_w, ptrw, size);
3741 retval = fname_w;
3743 else
3745 int dbcs_p = max_filename_mbslen () > 1;
3746 char *ptra;
3748 buffer = alloca (bufsize);
3749 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3750 if (result != NO_ERROR)
3751 return NULL;
3752 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3753 ptra += 2;
3754 if (!dbcs_p)
3755 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3756 else
3758 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3759 ptra = CharNextExA (file_name_codepage, ptra, 0);
3761 ptra++;
3762 strncpy (fname_a, ptra, size);
3763 retval = fname_a;
3766 return retval;
3769 static void
3770 close_unc_volume (HANDLE henum)
3772 if (henum != INVALID_HANDLE_VALUE)
3773 WNetCloseEnum (henum);
3776 static DWORD
3777 unc_volume_file_attributes (const char *path)
3779 HANDLE henum;
3780 DWORD attrs;
3782 henum = open_unc_volume (path);
3783 if (henum == INVALID_HANDLE_VALUE)
3784 return -1;
3786 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3788 close_unc_volume (henum);
3790 return attrs;
3793 /* Ensure a network connection is authenticated. */
3794 static void
3795 logon_network_drive (const char *path)
3797 char share[MAX_UTF8_PATH];
3798 int n_slashes;
3799 char drive[4];
3800 UINT drvtype;
3801 char *p;
3802 DWORD val;
3804 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3805 drvtype = DRIVE_REMOTE;
3806 else if (path[0] == '\0' || path[1] != ':')
3807 drvtype = GetDriveType (NULL);
3808 else
3810 drive[0] = path[0];
3811 drive[1] = ':';
3812 drive[2] = '\\';
3813 drive[3] = '\0';
3814 drvtype = GetDriveType (drive);
3817 /* Only logon to networked drives. */
3818 if (drvtype != DRIVE_REMOTE)
3819 return;
3821 n_slashes = 2;
3822 strncpy (share, path, MAX_UTF8_PATH);
3823 /* Truncate to just server and share name. */
3824 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3826 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3828 *p = '\0';
3829 break;
3833 if (w32_unicode_filenames)
3835 NETRESOURCEW resourcew;
3836 wchar_t share_w[MAX_PATH];
3838 resourcew.dwScope = RESOURCE_GLOBALNET;
3839 resourcew.dwType = RESOURCETYPE_DISK;
3840 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3841 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3842 resourcew.lpLocalName = NULL;
3843 filename_to_utf16 (share, share_w);
3844 resourcew.lpRemoteName = share_w;
3845 resourcew.lpProvider = NULL;
3847 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3849 else
3851 NETRESOURCEA resourcea;
3852 char share_a[MAX_PATH];
3854 resourcea.dwScope = RESOURCE_GLOBALNET;
3855 resourcea.dwType = RESOURCETYPE_DISK;
3856 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3857 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3858 resourcea.lpLocalName = NULL;
3859 filename_to_ansi (share, share_a);
3860 resourcea.lpRemoteName = share_a;
3861 resourcea.lpProvider = NULL;
3863 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3866 switch (val)
3868 case NO_ERROR:
3869 case ERROR_ALREADY_ASSIGNED:
3870 break;
3871 case ERROR_ACCESS_DENIED:
3872 case ERROR_LOGON_FAILURE:
3873 errno = EACCES;
3874 break;
3875 case ERROR_BUSY:
3876 errno = EAGAIN;
3877 break;
3878 case ERROR_BAD_NET_NAME:
3879 case ERROR_NO_NET_OR_BAD_PATH:
3880 case ERROR_NO_NETWORK:
3881 case ERROR_CANCELLED:
3882 default:
3883 errno = ENOENT;
3884 break;
3888 /* Emulate faccessat(2). */
3890 faccessat (int dirfd, const char * path, int mode, int flags)
3892 DWORD attributes;
3894 if (dirfd != AT_FDCWD
3895 && !(IS_DIRECTORY_SEP (path[0])
3896 || IS_DEVICE_SEP (path[1])))
3898 errno = EBADF;
3899 return -1;
3902 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3903 newer versions blow up when passed D_OK. */
3904 path = map_w32_filename (path, NULL);
3905 /* If the last element of PATH is a symlink, we need to resolve it
3906 to get the attributes of its target file. Note: any symlinks in
3907 PATH elements other than the last one are transparently resolved
3908 by GetFileAttributes below. */
3909 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3910 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3911 path = chase_symlinks (path);
3913 if (w32_unicode_filenames)
3915 wchar_t path_w[MAX_PATH];
3917 filename_to_utf16 (path, path_w);
3918 attributes = GetFileAttributesW (path_w);
3920 else
3922 char path_a[MAX_PATH];
3924 filename_to_ansi (path, path_a);
3925 attributes = GetFileAttributesA (path_a);
3928 if (attributes == -1)
3930 DWORD w32err = GetLastError ();
3932 switch (w32err)
3934 case ERROR_INVALID_NAME:
3935 case ERROR_BAD_PATHNAME:
3936 if (is_unc_volume (path))
3938 attributes = unc_volume_file_attributes (path);
3939 if (attributes == -1)
3941 errno = EACCES;
3942 return -1;
3944 goto check_attrs;
3946 /* FALLTHROUGH */
3947 case ERROR_FILE_NOT_FOUND:
3948 case ERROR_BAD_NETPATH:
3949 errno = ENOENT;
3950 break;
3951 default:
3952 errno = EACCES;
3953 break;
3955 return -1;
3958 check_attrs:
3959 if ((mode & X_OK) != 0
3960 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3962 errno = EACCES;
3963 return -1;
3965 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3967 errno = EACCES;
3968 return -1;
3970 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3972 errno = EACCES;
3973 return -1;
3975 return 0;
3978 /* A special test for DIRNAME being a directory accessible by the
3979 current user. This is needed because the security permissions in
3980 directory's ACLs are not visible in the Posix-style mode bits
3981 returned by 'stat' and in attributes returned by GetFileAttributes.
3982 So a directory would seem like it's readable by the current user,
3983 but will in fact error out with EACCES when they actually try. */
3985 w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
3987 char pattern[MAX_UTF8_PATH];
3988 bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
3989 HANDLE dh;
3991 /* Network volumes need a different reading method. */
3992 if (is_unc_volume (dirname))
3994 void *read_result = NULL;
3995 wchar_t fnw[MAX_PATH];
3996 char fna[MAX_PATH];
3998 dh = open_unc_volume (dirname);
3999 if (dh != INVALID_HANDLE_VALUE)
4001 read_result = read_unc_volume (dh, fnw, fna, MAX_PATH);
4002 close_unc_volume (dh);
4004 /* Treat empty volumes as accessible. */
4005 return read_result != NULL || GetLastError () == ERROR_NO_MORE_ITEMS;
4008 /* Note: map_w32_filename makes sure DIRNAME is not longer than
4009 MAX_UTF8_PATH. */
4010 strcpy (pattern, map_w32_filename (dirname, NULL));
4012 /* Note: No need to resolve symlinks in FILENAME, because FindFirst
4013 opens the directory that is the target of a symlink. */
4014 if (w32_unicode_filenames)
4016 wchar_t pat_w[MAX_PATH + 2];
4017 WIN32_FIND_DATAW dfd_w;
4019 filename_to_utf16 (pattern, pat_w);
4020 if (!last_slash)
4021 wcscat (pat_w, L"\\");
4022 wcscat (pat_w, L"*");
4023 dh = FindFirstFileW (pat_w, &dfd_w);
4025 else
4027 char pat_a[MAX_PATH + 2];
4028 WIN32_FIND_DATAA dfd_a;
4030 filename_to_ansi (pattern, pat_a);
4031 if (!last_slash)
4032 strcpy (pat_a, "\\");
4033 strcat (pat_a, "*");
4034 /* In case DIRNAME cannot be expressed in characters from the
4035 current ANSI codepage. */
4036 if (_mbspbrk (pat_a, "?"))
4037 dh = INVALID_HANDLE_VALUE;
4038 else
4039 dh = FindFirstFileA (pat_a, &dfd_a);
4042 if (dh == INVALID_HANDLE_VALUE)
4043 return 0;
4044 FindClose (dh);
4045 return 1;
4048 /* A version of 'access' to be used locally with file names in
4049 locale-specific encoding. Does not resolve symlinks and does not
4050 support file names on FAT12 and FAT16 volumes, but that's OK, since
4051 we only invoke this function for files inside the Emacs source or
4052 installation tree, on directories (so any symlinks should have the
4053 directory bit set), and on short file names such as "C:/.emacs". */
4054 static int
4055 sys_access (const char *fname, int mode)
4057 char fname_copy[MAX_PATH], *p;
4058 DWORD attributes;
4060 strcpy (fname_copy, fname);
4061 /* Do the equivalent of unixtodos_filename. */
4062 for (p = fname_copy; *p; p = CharNext (p))
4063 if (*p == '/')
4064 *p = '\\';
4066 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
4068 DWORD w32err = GetLastError ();
4070 switch (w32err)
4072 case ERROR_INVALID_NAME:
4073 case ERROR_BAD_PATHNAME:
4074 case ERROR_FILE_NOT_FOUND:
4075 case ERROR_BAD_NETPATH:
4076 errno = ENOENT;
4077 break;
4078 default:
4079 errno = EACCES;
4080 break;
4082 return -1;
4084 if ((mode & X_OK) != 0
4085 && !(is_exec (fname_copy)
4086 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
4088 errno = EACCES;
4089 return -1;
4091 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
4093 errno = EACCES;
4094 return -1;
4096 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
4098 errno = EACCES;
4099 return -1;
4101 return 0;
4104 /* Shadow some MSVC runtime functions to map requests for long filenames
4105 to reasonable short names if necessary. This was originally added to
4106 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
4107 long file names. */
4110 sys_chdir (const char * path)
4112 path = map_w32_filename (path, NULL);
4113 if (w32_unicode_filenames)
4115 wchar_t newdir_w[MAX_PATH];
4117 if (filename_to_utf16 (path, newdir_w) == 0)
4118 return _wchdir (newdir_w);
4119 return -1;
4121 else
4123 char newdir_a[MAX_PATH];
4125 if (filename_to_ansi (path, newdir_a) == 0)
4126 return _chdir (newdir_a);
4127 return -1;
4132 sys_chmod (const char * path, int mode)
4134 path = chase_symlinks (map_w32_filename (path, NULL));
4135 if (w32_unicode_filenames)
4137 wchar_t path_w[MAX_PATH];
4139 filename_to_utf16 (path, path_w);
4140 return _wchmod (path_w, mode);
4142 else
4144 char path_a[MAX_PATH];
4146 filename_to_ansi (path, path_a);
4147 return _chmod (path_a, mode);
4152 sys_creat (const char * path, int mode)
4154 path = map_w32_filename (path, NULL);
4155 if (w32_unicode_filenames)
4157 wchar_t path_w[MAX_PATH];
4159 filename_to_utf16 (path, path_w);
4160 return _wcreat (path_w, mode);
4162 else
4164 char path_a[MAX_PATH];
4166 filename_to_ansi (path, path_a);
4167 return _creat (path_a, mode);
4171 FILE *
4172 sys_fopen (const char * path, const char * mode)
4174 int fd;
4175 int oflag;
4176 const char * mode_save = mode;
4178 /* Force all file handles to be non-inheritable. This is necessary to
4179 ensure child processes don't unwittingly inherit handles that might
4180 prevent future file access. */
4182 if (mode[0] == 'r')
4183 oflag = O_RDONLY;
4184 else if (mode[0] == 'w' || mode[0] == 'a')
4185 oflag = O_WRONLY | O_CREAT | O_TRUNC;
4186 else
4187 return NULL;
4189 /* Only do simplistic option parsing. */
4190 while (*++mode)
4191 if (mode[0] == '+')
4193 oflag &= ~(O_RDONLY | O_WRONLY);
4194 oflag |= O_RDWR;
4196 else if (mode[0] == 'b')
4198 oflag &= ~O_TEXT;
4199 oflag |= O_BINARY;
4201 else if (mode[0] == 't')
4203 oflag &= ~O_BINARY;
4204 oflag |= O_TEXT;
4206 else break;
4208 path = map_w32_filename (path, NULL);
4209 if (w32_unicode_filenames)
4211 wchar_t path_w[MAX_PATH];
4213 filename_to_utf16 (path, path_w);
4214 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
4216 else
4218 char path_a[MAX_PATH];
4220 filename_to_ansi (path, path_a);
4221 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
4223 if (fd < 0)
4224 return NULL;
4226 return _fdopen (fd, mode_save);
4229 /* This only works on NTFS volumes, but is useful to have. */
4231 sys_link (const char * old, const char * new)
4233 HANDLE fileh;
4234 int result = -1;
4235 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
4236 wchar_t oldname_w[MAX_PATH];
4237 char oldname_a[MAX_PATH];
4239 if (old == NULL || new == NULL)
4241 errno = ENOENT;
4242 return -1;
4245 strcpy (oldname, map_w32_filename (old, NULL));
4246 strcpy (newname, map_w32_filename (new, NULL));
4248 if (w32_unicode_filenames)
4250 filename_to_utf16 (oldname, oldname_w);
4251 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
4252 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4254 else
4256 filename_to_ansi (oldname, oldname_a);
4257 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
4258 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4260 if (fileh != INVALID_HANDLE_VALUE)
4262 int wlen;
4264 /* Confusingly, the "alternate" stream name field does not apply
4265 when restoring a hard link, and instead contains the actual
4266 stream data for the link (ie. the name of the link to create).
4267 The WIN32_STREAM_ID structure before the cStreamName field is
4268 the stream header, which is then immediately followed by the
4269 stream data. */
4271 struct {
4272 WIN32_STREAM_ID wid;
4273 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
4274 } data;
4276 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
4277 indicates that flag is unsupported for CP_UTF8, and OTOH says
4278 it is the default anyway. */
4279 wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
4280 data.wid.cStreamName, MAX_PATH);
4281 if (wlen > 0)
4283 LPVOID context = NULL;
4284 DWORD wbytes = 0;
4286 data.wid.dwStreamId = BACKUP_LINK;
4287 data.wid.dwStreamAttributes = 0;
4288 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
4289 data.wid.Size.HighPart = 0;
4290 data.wid.dwStreamNameSize = 0;
4292 if (BackupWrite (fileh, (LPBYTE)&data,
4293 offsetof (WIN32_STREAM_ID, cStreamName)
4294 + data.wid.Size.LowPart,
4295 &wbytes, FALSE, FALSE, &context)
4296 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
4298 /* succeeded */
4299 result = 0;
4301 else
4303 DWORD err = GetLastError ();
4304 DWORD attributes;
4306 switch (err)
4308 case ERROR_ACCESS_DENIED:
4309 /* This is what happens when OLDNAME is a directory,
4310 since Windows doesn't support hard links to
4311 directories. Posix says to set errno to EPERM in
4312 that case. */
4313 if (w32_unicode_filenames)
4314 attributes = GetFileAttributesW (oldname_w);
4315 else
4316 attributes = GetFileAttributesA (oldname_a);
4317 if (attributes != -1
4318 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
4319 errno = EPERM;
4320 else if (attributes == -1
4321 && is_unc_volume (oldname)
4322 && unc_volume_file_attributes (oldname) != -1)
4323 errno = EPERM;
4324 else
4325 errno = EACCES;
4326 break;
4327 case ERROR_TOO_MANY_LINKS:
4328 errno = EMLINK;
4329 break;
4330 case ERROR_NOT_SAME_DEVICE:
4331 errno = EXDEV;
4332 break;
4333 default:
4334 errno = EINVAL;
4335 break;
4340 CloseHandle (fileh);
4342 else
4343 errno = ENOENT;
4345 return result;
4349 sys_mkdir (const char * path)
4351 path = map_w32_filename (path, NULL);
4353 if (w32_unicode_filenames)
4355 wchar_t path_w[MAX_PATH];
4357 filename_to_utf16 (path, path_w);
4358 return _wmkdir (path_w);
4360 else
4362 char path_a[MAX_PATH];
4364 filename_to_ansi (path, path_a);
4365 return _mkdir (path_a);
4370 sys_open (const char * path, int oflag, int mode)
4372 const char* mpath = map_w32_filename (path, NULL);
4373 int res = -1;
4375 if (w32_unicode_filenames)
4377 wchar_t mpath_w[MAX_PATH];
4379 filename_to_utf16 (mpath, mpath_w);
4380 /* If possible, try to open file without _O_CREAT, to be able to
4381 write to existing hidden and system files. Force all file
4382 handles to be non-inheritable. */
4383 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4384 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4385 if (res < 0)
4386 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4388 else
4390 char mpath_a[MAX_PATH];
4392 filename_to_ansi (mpath, mpath_a);
4393 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4394 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4395 if (res < 0)
4396 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4399 return res;
4402 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
4403 when using mktemp.
4405 Standard algorithm for generating a temporary file name seems to be
4406 use pid or tid with a letter on the front (in place of the 6 X's)
4407 and cycle through the letters to find a unique name. We extend
4408 that to allow any reasonable character as the first of the 6 X's,
4409 so that the number of simultaneously used temporary files will be
4410 greater. */
4413 mkostemp (char * template, int flags)
4415 char * p;
4416 int i, fd = -1;
4417 unsigned uid = GetCurrentThreadId ();
4418 int save_errno = errno;
4419 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
4421 errno = EINVAL;
4422 if (template == NULL)
4423 return -1;
4425 p = template + strlen (template);
4426 i = 5;
4427 /* replace up to the last 5 X's with uid in decimal */
4428 while (--p >= template && p[0] == 'X' && --i >= 0)
4430 p[0] = '0' + uid % 10;
4431 uid /= 10;
4434 if (i < 0 && p[0] == 'X')
4436 i = 0;
4439 p[0] = first_char[i];
4440 if ((fd = sys_open (template,
4441 flags | _O_CREAT | _O_EXCL | _O_RDWR,
4442 S_IRUSR | S_IWUSR)) >= 0
4443 || errno != EEXIST)
4445 if (fd >= 0)
4446 errno = save_errno;
4447 return fd;
4450 while (++i < sizeof (first_char));
4453 /* Template is badly formed or else we can't generate a unique name. */
4454 return -1;
4458 fchmod (int fd, mode_t mode)
4460 return 0;
4464 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4466 BOOL result;
4467 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4468 int newname_dev;
4469 int oldname_dev;
4470 bool have_temp_a = false;
4472 /* MoveFile on Windows 95 doesn't correctly change the short file name
4473 alias in a number of circumstances (it is not easy to predict when
4474 just by looking at oldname and newname, unfortunately). In these
4475 cases, renaming through a temporary name avoids the problem.
4477 A second problem on Windows 95 is that renaming through a temp name when
4478 newname is uppercase fails (the final long name ends up in
4479 lowercase, although the short alias might be uppercase) UNLESS the
4480 long temp name is not 8.3.
4482 So, on Windows 95 we always rename through a temp name, and we make sure
4483 the temp name has a long extension to ensure correct renaming. */
4485 strcpy (temp, map_w32_filename (oldname, NULL));
4487 /* volume_info is set indirectly by map_w32_filename. */
4488 oldname_dev = volume_info.serialnum;
4490 if (os_subtype == OS_9X)
4492 char * o;
4493 char * p;
4494 int i = 0;
4495 char oldname_a[MAX_PATH];
4497 oldname = map_w32_filename (oldname, NULL);
4498 filename_to_ansi (oldname, oldname_a);
4499 filename_to_ansi (temp, temp_a);
4500 if ((o = strrchr (oldname_a, '\\')))
4501 o++;
4502 else
4503 o = (char *) oldname_a;
4505 if ((p = strrchr (temp_a, '\\')))
4506 p++;
4507 else
4508 p = temp_a;
4512 /* Force temp name to require a manufactured 8.3 alias - this
4513 seems to make the second rename work properly. */
4514 sprintf (p, "_.%s.%d", o, i);
4515 i++;
4516 result = rename (oldname_a, temp_a);
4518 /* This loop must surely terminate! */
4519 while (result < 0 && errno == EEXIST);
4520 if (result < 0)
4521 return -1;
4522 have_temp_a = true;
4525 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4526 (at least if it is a file; don't do this for directories).
4528 Since we mustn't do this if we are just changing the case of the
4529 file name (we would end up deleting the file we are trying to
4530 rename!), we let rename detect if the destination file already
4531 exists - that way we avoid the possible pitfalls of trying to
4532 determine ourselves whether two names really refer to the same
4533 file, which is not always possible in the general case. (Consider
4534 all the permutations of shared or subst'd drives, etc.) */
4536 newname = map_w32_filename (newname, NULL);
4538 /* volume_info is set indirectly by map_w32_filename. */
4539 newname_dev = volume_info.serialnum;
4541 if (w32_unicode_filenames)
4543 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4545 filename_to_utf16 (temp, temp_w);
4546 filename_to_utf16 (newname, newname_w);
4547 result = _wrename (temp_w, newname_w);
4548 if (result < 0 && force)
4550 DWORD w32err = GetLastError ();
4552 if (errno == EACCES
4553 && newname_dev != oldname_dev)
4555 /* The implementation of `rename' on Windows does not return
4556 errno = EXDEV when you are moving a directory to a
4557 different storage device (ex. logical disk). It returns
4558 EACCES instead. So here we handle such situations and
4559 return EXDEV. */
4560 DWORD attributes;
4562 if ((attributes = GetFileAttributesW (temp_w)) != -1
4563 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4564 errno = EXDEV;
4566 else if (errno == EEXIST)
4568 if (_wchmod (newname_w, 0666) != 0)
4569 return result;
4570 if (_wunlink (newname_w) != 0)
4571 return result;
4572 result = _wrename (temp_w, newname_w);
4574 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4575 && is_symlink (temp))
4577 /* This is Windows prohibiting the user from creating a
4578 symlink in another place, since that requires
4579 privileges. */
4580 errno = EPERM;
4584 else
4586 char newname_a[MAX_PATH];
4588 if (!have_temp_a)
4589 filename_to_ansi (temp, temp_a);
4590 filename_to_ansi (newname, newname_a);
4591 result = rename (temp_a, newname_a);
4592 if (result < 0 && force)
4594 DWORD w32err = GetLastError ();
4596 if (errno == EACCES
4597 && newname_dev != oldname_dev)
4599 DWORD attributes;
4601 if ((attributes = GetFileAttributesA (temp_a)) != -1
4602 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4603 errno = EXDEV;
4605 else if (errno == EEXIST)
4607 if (_chmod (newname_a, 0666) != 0)
4608 return result;
4609 if (_unlink (newname_a) != 0)
4610 return result;
4611 result = rename (temp_a, newname_a);
4613 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4614 && is_symlink (temp))
4615 errno = EPERM;
4619 return result;
4623 sys_rename (char const *old, char const *new)
4625 return sys_rename_replace (old, new, TRUE);
4629 sys_rmdir (const char * path)
4631 path = map_w32_filename (path, NULL);
4633 if (w32_unicode_filenames)
4635 wchar_t path_w[MAX_PATH];
4637 filename_to_utf16 (path, path_w);
4638 return _wrmdir (path_w);
4640 else
4642 char path_a[MAX_PATH];
4644 filename_to_ansi (path, path_a);
4645 return _rmdir (path_a);
4650 sys_unlink (const char * path)
4652 int rmstatus, e;
4654 path = map_w32_filename (path, NULL);
4656 if (w32_unicode_filenames)
4658 wchar_t path_w[MAX_PATH];
4660 filename_to_utf16 (path, path_w);
4661 /* On Unix, unlink works without write permission. */
4662 _wchmod (path_w, 0666);
4663 rmstatus = _wunlink (path_w);
4664 e = errno;
4665 /* Symlinks to directories can only be deleted by _rmdir;
4666 _unlink returns EACCES. */
4667 if (rmstatus != 0
4668 && errno == EACCES
4669 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4670 rmstatus = _wrmdir (path_w);
4671 else
4672 errno = e;
4674 else
4676 char path_a[MAX_PATH];
4678 filename_to_ansi (path, path_a);
4679 _chmod (path_a, 0666);
4680 rmstatus = _unlink (path_a);
4681 e = errno;
4682 if (rmstatus != 0
4683 && errno == EACCES
4684 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4685 rmstatus = _rmdir (path_a);
4686 else
4687 errno = e;
4690 return rmstatus;
4693 static FILETIME utc_base_ft;
4694 static ULONGLONG utc_base; /* In 100ns units */
4695 static int init = 0;
4697 #define FILETIME_TO_U64(result, ft) \
4698 do { \
4699 ULARGE_INTEGER uiTemp; \
4700 uiTemp.LowPart = (ft).dwLowDateTime; \
4701 uiTemp.HighPart = (ft).dwHighDateTime; \
4702 result = uiTemp.QuadPart; \
4703 } while (0)
4705 static void
4706 initialize_utc_base (void)
4708 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4709 SYSTEMTIME st;
4711 st.wYear = 1970;
4712 st.wMonth = 1;
4713 st.wDay = 1;
4714 st.wHour = 0;
4715 st.wMinute = 0;
4716 st.wSecond = 0;
4717 st.wMilliseconds = 0;
4719 SystemTimeToFileTime (&st, &utc_base_ft);
4720 FILETIME_TO_U64 (utc_base, utc_base_ft);
4723 static time_t
4724 convert_time (FILETIME ft)
4726 ULONGLONG tmp;
4728 if (!init)
4730 initialize_utc_base ();
4731 init = 1;
4734 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4735 return 0;
4737 FILETIME_TO_U64 (tmp, ft);
4738 return (time_t) ((tmp - utc_base) / 10000000L);
4741 static void
4742 convert_from_time_t (time_t time, FILETIME * pft)
4744 ULARGE_INTEGER tmp;
4746 if (!init)
4748 initialize_utc_base ();
4749 init = 1;
4752 /* time in 100ns units since 1-Jan-1601 */
4753 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4754 pft->dwHighDateTime = tmp.HighPart;
4755 pft->dwLowDateTime = tmp.LowPart;
4758 static PSECURITY_DESCRIPTOR
4759 get_file_security_desc_by_handle (HANDLE h)
4761 PSECURITY_DESCRIPTOR psd = NULL;
4762 DWORD err;
4763 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4764 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4766 err = get_security_info (h, SE_FILE_OBJECT, si,
4767 NULL, NULL, NULL, NULL, &psd);
4768 if (err != ERROR_SUCCESS)
4769 return NULL;
4771 return psd;
4774 static PSECURITY_DESCRIPTOR
4775 get_file_security_desc_by_name (const char *fname)
4777 PSECURITY_DESCRIPTOR psd = NULL;
4778 DWORD sd_len, err;
4779 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4780 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4782 if (!get_file_security (fname, si, psd, 0, &sd_len))
4784 err = GetLastError ();
4785 if (err != ERROR_INSUFFICIENT_BUFFER)
4786 return NULL;
4789 psd = xmalloc (sd_len);
4790 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4792 xfree (psd);
4793 return NULL;
4796 return psd;
4799 static DWORD
4800 get_rid (PSID sid)
4802 unsigned n_subauthorities;
4804 /* Use the last sub-authority value of the RID, the relative
4805 portion of the SID, as user/group ID. */
4806 n_subauthorities = *get_sid_sub_authority_count (sid);
4807 if (n_subauthorities < 1)
4808 return 0; /* the "World" RID */
4809 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4812 /* Caching SID and account values for faster lokup. */
4814 struct w32_id {
4815 unsigned rid;
4816 struct w32_id *next;
4817 char name[GNLEN+1];
4818 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4821 static struct w32_id *w32_idlist;
4823 static int
4824 w32_cached_id (PSID sid, unsigned *id, char *name)
4826 struct w32_id *tail, *found;
4828 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4830 if (equal_sid ((PSID)tail->sid, sid))
4832 found = tail;
4833 break;
4836 if (found)
4838 *id = found->rid;
4839 strcpy (name, found->name);
4840 return 1;
4842 else
4843 return 0;
4846 static void
4847 w32_add_to_cache (PSID sid, unsigned id, char *name)
4849 DWORD sid_len;
4850 struct w32_id *new_entry;
4852 /* We don't want to leave behind stale cache from when Emacs was
4853 dumped. */
4854 if (initialized)
4856 sid_len = get_length_sid (sid);
4857 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4858 if (new_entry)
4860 new_entry->rid = id;
4861 strcpy (new_entry->name, name);
4862 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4863 new_entry->next = w32_idlist;
4864 w32_idlist = new_entry;
4869 #define UID 1
4870 #define GID 2
4872 static int
4873 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4875 PSID sid = NULL;
4876 BOOL dflt;
4877 SID_NAME_USE ignore;
4878 char name[UNLEN+1];
4879 DWORD name_len = sizeof (name);
4880 char domain[1024];
4881 DWORD domain_len = sizeof (domain);
4882 int use_dflt = 0;
4883 int result;
4885 if (what == UID)
4886 result = get_security_descriptor_owner (psd, &sid, &dflt);
4887 else if (what == GID)
4888 result = get_security_descriptor_group (psd, &sid, &dflt);
4889 else
4890 result = 0;
4892 if (!result || !is_valid_sid (sid))
4893 use_dflt = 1;
4894 else if (!w32_cached_id (sid, id, nm))
4896 if (!lookup_account_sid (NULL, sid, name, &name_len,
4897 domain, &domain_len, &ignore)
4898 || name_len > UNLEN+1)
4899 use_dflt = 1;
4900 else
4902 *id = get_rid (sid);
4903 strcpy (nm, name);
4904 w32_add_to_cache (sid, *id, name);
4907 return use_dflt;
4910 static void
4911 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4913 int dflt_usr = 0, dflt_grp = 0;
4915 if (!psd)
4917 dflt_usr = 1;
4918 dflt_grp = 1;
4920 else
4922 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4923 dflt_usr = 1;
4924 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4925 dflt_grp = 1;
4927 /* Consider files to belong to current user/group, if we cannot get
4928 more accurate information. */
4929 if (dflt_usr)
4931 st->st_uid = dflt_passwd.pw_uid;
4932 strcpy (st->st_uname, dflt_passwd.pw_name);
4934 if (dflt_grp)
4936 st->st_gid = dflt_passwd.pw_gid;
4937 strcpy (st->st_gname, dflt_group.gr_name);
4941 /* Return non-zero if NAME is a potentially slow filesystem. */
4942 int is_slow_fs (const char *);
4945 is_slow_fs (const char *name)
4947 char drive_root[4];
4948 UINT devtype;
4950 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4951 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4952 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4953 devtype = GetDriveType (NULL); /* use root of current drive */
4954 else
4956 /* GetDriveType needs the root directory of the drive. */
4957 strncpy (drive_root, name, 2);
4958 drive_root[2] = '\\';
4959 drive_root[3] = '\0';
4960 devtype = GetDriveType (drive_root);
4962 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4965 /* If this is non-zero, the caller wants accurate information about
4966 file's owner and group, which could be expensive to get. dired.c
4967 uses this flag when needed for the job at hand. */
4968 int w32_stat_get_owner_group;
4970 /* MSVC stat function can't cope with UNC names and has other bugs, so
4971 replace it with our own. This also allows us to calculate consistent
4972 inode values and owner/group without hacks in the main Emacs code,
4973 and support file names encoded in UTF-8. */
4975 static int
4976 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4978 char *name, *save_name, *r;
4979 WIN32_FIND_DATAW wfd_w;
4980 WIN32_FIND_DATAA wfd_a;
4981 HANDLE fh;
4982 unsigned __int64 fake_inode = 0;
4983 int permission;
4984 int len;
4985 int rootdir = FALSE;
4986 PSECURITY_DESCRIPTOR psd = NULL;
4987 int is_a_symlink = 0;
4988 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4989 DWORD access_rights = 0;
4990 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4991 FILETIME ctime, atime, wtime;
4992 wchar_t name_w[MAX_PATH];
4993 char name_a[MAX_PATH];
4995 if (path == NULL || buf == NULL)
4997 errno = EFAULT;
4998 return -1;
5001 save_name = name = (char *) map_w32_filename (path, &path);
5002 /* Must be valid filename, no wild cards or other invalid
5003 characters. */
5004 if (strpbrk (name, "*?|<>\""))
5006 errno = ENOENT;
5007 return -1;
5010 len = strlen (name);
5011 /* Allocate 1 extra byte so that we could append a slash to a root
5012 directory, down below. */
5013 name = strcpy (alloca (len + 2), name);
5015 /* Avoid a somewhat costly call to is_symlink if the filesystem
5016 doesn't support symlinks. */
5017 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5018 is_a_symlink = is_symlink (name);
5020 /* Plan A: Open the file and get all the necessary information via
5021 the resulting handle. This solves several issues in one blow:
5023 . retrieves attributes for the target of a symlink, if needed
5024 . gets attributes of root directories and symlinks pointing to
5025 root directories, thus avoiding the need for special-casing
5026 these and detecting them by examining the file-name format
5027 . retrieves more accurate attributes (e.g., non-zero size for
5028 some directories, esp. directories that are junction points)
5029 . correctly resolves "c:/..", "/.." and similar file names
5030 . avoids run-time penalties for 99% of use cases
5032 Plan A is always tried first, unless the user asked not to (but
5033 if the file is a symlink and we need to follow links, we try Plan
5034 A even if the user asked not to).
5036 If Plan A fails, we go to Plan B (below), where various
5037 potentially expensive techniques must be used to handle "special"
5038 files such as UNC volumes etc. */
5039 if (!(NILP (Vw32_get_true_file_attributes)
5040 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
5041 /* Following symlinks requires getting the info by handle. */
5042 || (is_a_symlink && follow_symlinks))
5044 BY_HANDLE_FILE_INFORMATION info;
5046 if (is_a_symlink && !follow_symlinks)
5047 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
5048 /* READ_CONTROL access rights are required to get security info
5049 by handle. But if the OS doesn't support security in the
5050 first place, we don't need to try. */
5051 if (is_windows_9x () != TRUE)
5052 access_rights |= READ_CONTROL;
5054 if (w32_unicode_filenames)
5056 filename_to_utf16 (name, name_w);
5057 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
5058 file_flags, NULL);
5059 /* If CreateFile fails with READ_CONTROL, try again with
5060 zero as access rights. */
5061 if (fh == INVALID_HANDLE_VALUE && access_rights)
5062 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
5063 file_flags, NULL);
5065 else
5067 filename_to_ansi (name, name_a);
5068 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
5069 file_flags, NULL);
5070 if (fh == INVALID_HANDLE_VALUE && access_rights)
5071 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
5072 file_flags, NULL);
5074 if (fh == INVALID_HANDLE_VALUE)
5075 goto no_true_file_attributes;
5077 /* This is more accurate in terms of getting the correct number
5078 of links, but is quite slow (it is noticeable when Emacs is
5079 making a list of file name completions). */
5080 if (GetFileInformationByHandle (fh, &info))
5082 nlinks = info.nNumberOfLinks;
5083 /* Might as well use file index to fake inode values, but this
5084 is not guaranteed to be unique unless we keep a handle open
5085 all the time (even then there are situations where it is
5086 not unique). Reputedly, there are at most 48 bits of info
5087 (on NTFS, presumably less on FAT). */
5088 fake_inode = info.nFileIndexHigh;
5089 fake_inode <<= 32;
5090 fake_inode += info.nFileIndexLow;
5091 serialnum = info.dwVolumeSerialNumber;
5092 fs_high = info.nFileSizeHigh;
5093 fs_low = info.nFileSizeLow;
5094 ctime = info.ftCreationTime;
5095 atime = info.ftLastAccessTime;
5096 wtime = info.ftLastWriteTime;
5097 fattrs = info.dwFileAttributes;
5099 else
5101 /* We don't go to Plan B here, because it's not clear that
5102 it's a good idea. The only known use case where
5103 CreateFile succeeds, but GetFileInformationByHandle fails
5104 (with ERROR_INVALID_FUNCTION) is for character devices
5105 such as NUL, PRN, etc. For these, switching to Plan B is
5106 a net loss, because we lose the character device
5107 attribute returned by GetFileType below (FindFirstFile
5108 doesn't set that bit in the attributes), and the other
5109 fields don't make sense for character devices anyway.
5110 Emacs doesn't really care for non-file entities in the
5111 context of l?stat, so neither do we. */
5113 /* w32err is assigned so one could put a breakpoint here and
5114 examine its value, when GetFileInformationByHandle
5115 fails. */
5116 DWORD w32err = GetLastError ();
5118 switch (w32err)
5120 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
5121 errno = ENOENT;
5122 return -1;
5126 /* Test for a symlink before testing for a directory, since
5127 symlinks to directories have the directory bit set, but we
5128 don't want them to appear as directories. */
5129 if (is_a_symlink && !follow_symlinks)
5130 buf->st_mode = S_IFLNK;
5131 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5132 buf->st_mode = S_IFDIR;
5133 else
5135 DWORD ftype = GetFileType (fh);
5137 switch (ftype)
5139 case FILE_TYPE_DISK:
5140 buf->st_mode = S_IFREG;
5141 break;
5142 case FILE_TYPE_PIPE:
5143 buf->st_mode = S_IFIFO;
5144 break;
5145 case FILE_TYPE_CHAR:
5146 case FILE_TYPE_UNKNOWN:
5147 default:
5148 buf->st_mode = S_IFCHR;
5151 /* We produce the fallback owner and group data, based on the
5152 current user that runs Emacs, in the following cases:
5154 . caller didn't request owner and group info
5155 . this is Windows 9X
5156 . getting security by handle failed, and we need to produce
5157 information for the target of a symlink (this is better
5158 than producing a potentially misleading info about the
5159 symlink itself)
5161 If getting security by handle fails, and we don't need to
5162 resolve symlinks, we try getting security by name. */
5163 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5164 get_file_owner_and_group (NULL, buf);
5165 else
5167 psd = get_file_security_desc_by_handle (fh);
5168 if (psd)
5170 get_file_owner_and_group (psd, buf);
5171 LocalFree (psd);
5173 else if (!(is_a_symlink && follow_symlinks))
5175 psd = get_file_security_desc_by_name (name);
5176 get_file_owner_and_group (psd, buf);
5177 xfree (psd);
5179 else
5180 get_file_owner_and_group (NULL, buf);
5182 CloseHandle (fh);
5184 else
5186 no_true_file_attributes:
5187 /* Plan B: Either getting a handle on the file failed, or the
5188 caller explicitly asked us to not bother making this
5189 information more accurate.
5191 Implementation note: In Plan B, we never bother to resolve
5192 symlinks, even if we got here because we tried Plan A and
5193 failed. That's because, even if the caller asked for extra
5194 precision by setting Vw32_get_true_file_attributes to t,
5195 resolving symlinks requires acquiring a file handle to the
5196 symlink, which we already know will fail. And if the user
5197 did not ask for extra precision, resolving symlinks will fly
5198 in the face of that request, since the user then wants the
5199 lightweight version of the code. */
5200 rootdir = (path >= save_name + len - 1
5201 && (IS_DIRECTORY_SEP (*path) || *path == 0));
5203 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
5204 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
5205 if (IS_DIRECTORY_SEP (r[0])
5206 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
5207 r[1] = r[2] = '\0';
5209 /* Note: If NAME is a symlink to the root of a UNC volume
5210 (i.e. "\\SERVER"), we will not detect that here, and we will
5211 return data about the symlink as result of FindFirst below.
5212 This is unfortunate, but that marginal use case does not
5213 justify a call to chase_symlinks which would impose a penalty
5214 on all the other use cases. (We get here for symlinks to
5215 roots of UNC volumes because CreateFile above fails for them,
5216 unlike with symlinks to root directories X:\ of drives.) */
5217 if (is_unc_volume (name))
5219 fattrs = unc_volume_file_attributes (name);
5220 if (fattrs == -1)
5221 return -1;
5223 ctime = atime = wtime = utc_base_ft;
5225 else if (rootdir)
5227 /* Make sure root directories end in a slash. */
5228 if (!IS_DIRECTORY_SEP (name[len-1]))
5229 strcpy (name + len, "\\");
5230 if (GetDriveType (name) < 2)
5232 errno = ENOENT;
5233 return -1;
5236 fattrs = FILE_ATTRIBUTE_DIRECTORY;
5237 ctime = atime = wtime = utc_base_ft;
5239 else
5241 int have_wfd = -1;
5243 /* Make sure non-root directories do NOT end in a slash,
5244 otherwise FindFirstFile might fail. */
5245 if (IS_DIRECTORY_SEP (name[len-1]))
5246 name[len - 1] = 0;
5248 /* (This is hacky, but helps when doing file completions on
5249 network drives.) Optimize by using information available from
5250 active readdir if possible. */
5251 len = strlen (dir_pathname);
5252 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
5253 len--;
5254 if (dir_find_handle != INVALID_HANDLE_VALUE
5255 && last_dir_find_data != -1
5256 && !(is_a_symlink && follow_symlinks)
5257 /* The 2 file-name comparisons below support only ASCII
5258 characters, and will lose (compare not equal) when
5259 the file names include non-ASCII characters that are
5260 the same but for the case. However, doing this
5261 properly involves: (a) converting both file names to
5262 UTF-16, (b) lower-casing both names using CharLowerW,
5263 and (c) comparing the results; this would be quite a
5264 bit slower, whereas Plan B is for users who want
5265 lightweight albeit inaccurate version of 'stat'. */
5266 && c_strncasecmp (save_name, dir_pathname, len) == 0
5267 && IS_DIRECTORY_SEP (name[len])
5268 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
5270 have_wfd = last_dir_find_data;
5271 /* This was the last entry returned by readdir. */
5272 if (last_dir_find_data == DIR_FIND_DATA_W)
5273 wfd_w = dir_find_data_w;
5274 else
5275 wfd_a = dir_find_data_a;
5277 else
5279 logon_network_drive (name);
5281 if (w32_unicode_filenames)
5283 filename_to_utf16 (name, name_w);
5284 fh = FindFirstFileW (name_w, &wfd_w);
5285 have_wfd = DIR_FIND_DATA_W;
5287 else
5289 filename_to_ansi (name, name_a);
5290 /* If NAME includes characters not representable by
5291 the current ANSI codepage, filename_to_ansi
5292 usually replaces them with a '?'. We don't want
5293 to let FindFirstFileA interpret those as wildcards,
5294 and "succeed", returning us data from some random
5295 file in the same directory. */
5296 if (_mbspbrk (name_a, "?"))
5297 fh = INVALID_HANDLE_VALUE;
5298 else
5299 fh = FindFirstFileA (name_a, &wfd_a);
5300 have_wfd = DIR_FIND_DATA_A;
5302 if (fh == INVALID_HANDLE_VALUE)
5304 errno = ENOENT;
5305 return -1;
5307 FindClose (fh);
5309 /* Note: if NAME is a symlink, the information we get from
5310 FindFirstFile is for the symlink, not its target. */
5311 if (have_wfd == DIR_FIND_DATA_W)
5313 fattrs = wfd_w.dwFileAttributes;
5314 ctime = wfd_w.ftCreationTime;
5315 atime = wfd_w.ftLastAccessTime;
5316 wtime = wfd_w.ftLastWriteTime;
5317 fs_high = wfd_w.nFileSizeHigh;
5318 fs_low = wfd_w.nFileSizeLow;
5320 else
5322 fattrs = wfd_a.dwFileAttributes;
5323 ctime = wfd_a.ftCreationTime;
5324 atime = wfd_a.ftLastAccessTime;
5325 wtime = wfd_a.ftLastWriteTime;
5326 fs_high = wfd_a.nFileSizeHigh;
5327 fs_low = wfd_a.nFileSizeLow;
5329 fake_inode = 0;
5330 nlinks = 1;
5331 serialnum = volume_info.serialnum;
5333 if (is_a_symlink && !follow_symlinks)
5334 buf->st_mode = S_IFLNK;
5335 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5336 buf->st_mode = S_IFDIR;
5337 else
5338 buf->st_mode = S_IFREG;
5340 get_file_owner_and_group (NULL, buf);
5343 buf->st_ino = fake_inode;
5345 buf->st_dev = serialnum;
5346 buf->st_rdev = serialnum;
5348 buf->st_size = fs_high;
5349 buf->st_size <<= 32;
5350 buf->st_size += fs_low;
5351 buf->st_nlink = nlinks;
5353 /* Convert timestamps to Unix format. */
5354 buf->st_mtime = convert_time (wtime);
5355 buf->st_atime = convert_time (atime);
5356 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5357 buf->st_ctime = convert_time (ctime);
5358 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5360 /* determine rwx permissions */
5361 if (is_a_symlink && !follow_symlinks)
5362 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5363 else
5365 if (fattrs & FILE_ATTRIBUTE_READONLY)
5366 permission = S_IREAD;
5367 else
5368 permission = S_IREAD | S_IWRITE;
5370 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5371 permission |= S_IEXEC;
5372 else if (is_exec (name))
5373 permission |= S_IEXEC;
5376 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5378 return 0;
5382 stat (const char * path, struct stat * buf)
5384 return stat_worker (path, buf, 1);
5388 lstat (const char * path, struct stat * buf)
5390 return stat_worker (path, buf, 0);
5394 fstatat (int fd, char const *name, struct stat *st, int flags)
5396 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5397 This is good enough for the current usage in Emacs, but is fragile.
5399 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5400 Gnulib does this and can serve as a model. */
5401 char fullname[MAX_UTF8_PATH];
5403 if (fd != AT_FDCWD)
5405 char lastc = dir_pathname[strlen (dir_pathname) - 1];
5407 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
5408 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
5409 < 0)
5411 errno = ENAMETOOLONG;
5412 return -1;
5414 name = fullname;
5417 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5420 /* Provide fstat and utime as well as stat for consistent handling of
5421 file timestamps. */
5423 fstat (int desc, struct stat * buf)
5425 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5426 BY_HANDLE_FILE_INFORMATION info;
5427 unsigned __int64 fake_inode;
5428 int permission;
5430 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5432 case FILE_TYPE_DISK:
5433 buf->st_mode = S_IFREG;
5434 if (!GetFileInformationByHandle (fh, &info))
5436 errno = EACCES;
5437 return -1;
5439 break;
5440 case FILE_TYPE_PIPE:
5441 buf->st_mode = S_IFIFO;
5442 goto non_disk;
5443 case FILE_TYPE_CHAR:
5444 case FILE_TYPE_UNKNOWN:
5445 default:
5446 buf->st_mode = S_IFCHR;
5447 non_disk:
5448 memset (&info, 0, sizeof (info));
5449 info.dwFileAttributes = 0;
5450 info.ftCreationTime = utc_base_ft;
5451 info.ftLastAccessTime = utc_base_ft;
5452 info.ftLastWriteTime = utc_base_ft;
5455 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5456 buf->st_mode = S_IFDIR;
5458 buf->st_nlink = info.nNumberOfLinks;
5459 /* Might as well use file index to fake inode values, but this
5460 is not guaranteed to be unique unless we keep a handle open
5461 all the time (even then there are situations where it is
5462 not unique). Reputedly, there are at most 48 bits of info
5463 (on NTFS, presumably less on FAT). */
5464 fake_inode = info.nFileIndexHigh;
5465 fake_inode <<= 32;
5466 fake_inode += info.nFileIndexLow;
5468 /* MSVC defines _ino_t to be short; other libc's might not. */
5469 if (sizeof (buf->st_ino) == 2)
5470 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5471 else
5472 buf->st_ino = fake_inode;
5474 /* If the caller so requested, get the true file owner and group.
5475 Otherwise, consider the file to belong to the current user. */
5476 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5477 get_file_owner_and_group (NULL, buf);
5478 else
5480 PSECURITY_DESCRIPTOR psd = NULL;
5482 psd = get_file_security_desc_by_handle (fh);
5483 if (psd)
5485 get_file_owner_and_group (psd, buf);
5486 LocalFree (psd);
5488 else
5489 get_file_owner_and_group (NULL, buf);
5492 buf->st_dev = info.dwVolumeSerialNumber;
5493 buf->st_rdev = info.dwVolumeSerialNumber;
5495 buf->st_size = info.nFileSizeHigh;
5496 buf->st_size <<= 32;
5497 buf->st_size += info.nFileSizeLow;
5499 /* Convert timestamps to Unix format. */
5500 buf->st_mtime = convert_time (info.ftLastWriteTime);
5501 buf->st_atime = convert_time (info.ftLastAccessTime);
5502 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5503 buf->st_ctime = convert_time (info.ftCreationTime);
5504 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5506 /* determine rwx permissions */
5507 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5508 permission = S_IREAD;
5509 else
5510 permission = S_IREAD | S_IWRITE;
5512 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5513 permission |= S_IEXEC;
5514 else
5516 #if 0 /* no way of knowing the filename */
5517 char * p = strrchr (name, '.');
5518 if (p != NULL &&
5519 (xstrcasecmp (p, ".exe") == 0 ||
5520 xstrcasecmp (p, ".com") == 0 ||
5521 xstrcasecmp (p, ".bat") == 0 ||
5522 xstrcasecmp (p, ".cmd") == 0))
5523 permission |= S_IEXEC;
5524 #endif
5527 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5529 return 0;
5532 /* A version of 'utime' which handles directories as well as
5533 files. */
5536 utime (const char *name, struct utimbuf *times)
5538 struct utimbuf deftime;
5539 HANDLE fh;
5540 FILETIME mtime;
5541 FILETIME atime;
5543 if (times == NULL)
5545 deftime.modtime = deftime.actime = time (NULL);
5546 times = &deftime;
5549 if (w32_unicode_filenames)
5551 wchar_t name_utf16[MAX_PATH];
5553 if (filename_to_utf16 (name, name_utf16) != 0)
5554 return -1; /* errno set by filename_to_utf16 */
5556 /* Need write access to set times. */
5557 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5558 /* If NAME specifies a directory, FILE_SHARE_DELETE
5559 allows other processes to delete files inside it,
5560 while we have the directory open. */
5561 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5562 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5564 else
5566 char name_ansi[MAX_PATH];
5568 if (filename_to_ansi (name, name_ansi) != 0)
5569 return -1; /* errno set by filename_to_ansi */
5571 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5572 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5573 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5575 if (fh != INVALID_HANDLE_VALUE)
5577 convert_from_time_t (times->actime, &atime);
5578 convert_from_time_t (times->modtime, &mtime);
5579 if (!SetFileTime (fh, NULL, &atime, &mtime))
5581 CloseHandle (fh);
5582 errno = EACCES;
5583 return -1;
5585 CloseHandle (fh);
5587 else
5589 DWORD err = GetLastError ();
5591 switch (err)
5593 case ERROR_FILE_NOT_FOUND:
5594 case ERROR_PATH_NOT_FOUND:
5595 case ERROR_INVALID_DRIVE:
5596 case ERROR_BAD_NETPATH:
5597 case ERROR_DEV_NOT_EXIST:
5598 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5599 file name includes ?s, i.e. translation to ANSI failed. */
5600 case ERROR_INVALID_NAME:
5601 errno = ENOENT;
5602 break;
5603 case ERROR_TOO_MANY_OPEN_FILES:
5604 errno = ENFILE;
5605 break;
5606 case ERROR_ACCESS_DENIED:
5607 case ERROR_SHARING_VIOLATION:
5608 errno = EACCES;
5609 break;
5610 default:
5611 errno = EINVAL;
5612 break;
5614 return -1;
5616 return 0;
5620 sys_umask (int mode)
5622 static int current_mask;
5623 int retval, arg = 0;
5625 /* The only bit we really support is the write bit. Files are
5626 always readable on MS-Windows, and the execute bit does not exist
5627 at all. */
5628 /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
5629 to prevent access by other users on NTFS. */
5630 if ((mode & S_IWRITE) != 0)
5631 arg |= S_IWRITE;
5633 retval = _umask (arg);
5634 /* Merge into the return value the bits they've set the last time,
5635 which msvcrt.dll ignores and never returns. Emacs insists on its
5636 notion of mask being identical to what we return. */
5637 retval |= (current_mask & ~S_IWRITE);
5638 current_mask = mode;
5640 return retval;
5644 /* Symlink-related functions. */
5645 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5646 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5647 #endif
5650 symlink (char const *filename, char const *linkname)
5652 char linkfn[MAX_UTF8_PATH], *tgtfn;
5653 DWORD flags = 0;
5654 int dir_access, filename_ends_in_slash;
5656 /* Diagnostics follows Posix as much as possible. */
5657 if (filename == NULL || linkname == NULL)
5659 errno = EFAULT;
5660 return -1;
5662 if (!*filename)
5664 errno = ENOENT;
5665 return -1;
5667 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5669 errno = ENAMETOOLONG;
5670 return -1;
5673 strcpy (linkfn, map_w32_filename (linkname, NULL));
5674 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5676 errno = EPERM;
5677 return -1;
5680 /* Note: since empty FILENAME was already rejected, we can safely
5681 refer to FILENAME[1]. */
5682 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5684 /* Non-absolute FILENAME is understood as being relative to
5685 LINKNAME's directory. We need to prepend that directory to
5686 FILENAME to get correct results from faccessat below, since
5687 otherwise it will interpret FILENAME relative to the
5688 directory where the Emacs process runs. Note that
5689 make-symbolic-link always makes sure LINKNAME is a fully
5690 expanded file name. */
5691 char tem[MAX_UTF8_PATH];
5692 char *p = linkfn + strlen (linkfn);
5694 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5695 p--;
5696 if (p > linkfn)
5697 strncpy (tem, linkfn, p - linkfn);
5698 strcpy (tem + (p - linkfn), filename);
5699 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5701 else
5702 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5704 /* Since Windows distinguishes between symlinks to directories and
5705 to files, we provide a kludgy feature: if FILENAME doesn't
5706 exist, but ends in a slash, we create a symlink to directory. If
5707 FILENAME exists and is a directory, we always create a symlink to
5708 directory. */
5709 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5710 if (dir_access == 0 || filename_ends_in_slash)
5711 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5713 tgtfn = (char *)map_w32_filename (filename, NULL);
5714 if (filename_ends_in_slash)
5715 tgtfn[strlen (tgtfn) - 1] = '\0';
5717 errno = 0;
5718 if (!create_symbolic_link (linkfn, tgtfn, flags))
5720 /* ENOSYS is set by create_symbolic_link, when it detects that
5721 the OS doesn't support the CreateSymbolicLink API. */
5722 if (errno != ENOSYS)
5724 DWORD w32err = GetLastError ();
5726 switch (w32err)
5728 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5729 TGTFN point to the same file name, go figure. */
5730 case ERROR_SUCCESS:
5731 case ERROR_FILE_EXISTS:
5732 errno = EEXIST;
5733 break;
5734 case ERROR_ACCESS_DENIED:
5735 errno = EACCES;
5736 break;
5737 case ERROR_FILE_NOT_FOUND:
5738 case ERROR_PATH_NOT_FOUND:
5739 case ERROR_BAD_NETPATH:
5740 case ERROR_INVALID_REPARSE_DATA:
5741 errno = ENOENT;
5742 break;
5743 case ERROR_DIRECTORY:
5744 errno = EISDIR;
5745 break;
5746 case ERROR_PRIVILEGE_NOT_HELD:
5747 case ERROR_NOT_ALL_ASSIGNED:
5748 errno = EPERM;
5749 break;
5750 case ERROR_DISK_FULL:
5751 errno = ENOSPC;
5752 break;
5753 default:
5754 errno = EINVAL;
5755 break;
5758 return -1;
5760 return 0;
5763 /* A quick inexpensive test of whether FILENAME identifies a file that
5764 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5765 must already be in the normalized form returned by
5766 map_w32_filename. If the symlink is to a directory, the
5767 FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
5769 Note: for repeated operations on many files, it is best to test
5770 whether the underlying volume actually supports symlinks, by
5771 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5772 avoid the call to this function if it doesn't. That's because the
5773 call to GetFileAttributes takes a non-negligible time, especially
5774 on non-local or removable filesystems. See stat_worker for an
5775 example of how to do that. */
5776 static int
5777 is_symlink (const char *filename)
5779 DWORD attrs;
5780 wchar_t filename_w[MAX_PATH];
5781 char filename_a[MAX_PATH];
5782 WIN32_FIND_DATAW wfdw;
5783 WIN32_FIND_DATAA wfda;
5784 HANDLE fh;
5785 int attrs_mean_symlink;
5787 if (w32_unicode_filenames)
5789 filename_to_utf16 (filename, filename_w);
5790 attrs = GetFileAttributesW (filename_w);
5792 else
5794 filename_to_ansi (filename, filename_a);
5795 attrs = GetFileAttributesA (filename_a);
5797 if (attrs == -1)
5799 DWORD w32err = GetLastError ();
5801 switch (w32err)
5803 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5804 break;
5805 case ERROR_ACCESS_DENIED:
5806 errno = EACCES;
5807 break;
5808 case ERROR_FILE_NOT_FOUND:
5809 case ERROR_PATH_NOT_FOUND:
5810 default:
5811 errno = ENOENT;
5812 break;
5814 return 0;
5816 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5817 return 0;
5818 logon_network_drive (filename);
5819 if (w32_unicode_filenames)
5821 fh = FindFirstFileW (filename_w, &wfdw);
5822 attrs_mean_symlink =
5823 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5824 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5825 if (attrs_mean_symlink)
5826 attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5828 else if (_mbspbrk (filename_a, "?"))
5830 /* filename_to_ansi failed to convert the file name. */
5831 errno = ENOENT;
5832 return 0;
5834 else
5836 fh = FindFirstFileA (filename_a, &wfda);
5837 attrs_mean_symlink =
5838 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5839 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5840 if (attrs_mean_symlink)
5841 attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5843 if (fh == INVALID_HANDLE_VALUE)
5844 return 0;
5845 FindClose (fh);
5846 return attrs_mean_symlink;
5849 /* If NAME identifies a symbolic link, copy into BUF the file name of
5850 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5851 null-terminate the target name, even if it fits. Return the number
5852 of bytes copied, or -1 if NAME is not a symlink or any error was
5853 encountered while resolving it. The file name copied into BUF is
5854 encoded in the current ANSI codepage. */
5855 ssize_t
5856 readlink (const char *name, char *buf, size_t buf_size)
5858 const char *path;
5859 TOKEN_PRIVILEGES privs;
5860 int restore_privs = 0;
5861 HANDLE sh;
5862 ssize_t retval;
5863 char resolved[MAX_UTF8_PATH];
5865 if (name == NULL)
5867 errno = EFAULT;
5868 return -1;
5870 if (!*name)
5872 errno = ENOENT;
5873 return -1;
5876 path = map_w32_filename (name, NULL);
5878 if (strlen (path) > MAX_UTF8_PATH)
5880 errno = ENAMETOOLONG;
5881 return -1;
5884 errno = 0;
5885 if (is_windows_9x () == TRUE
5886 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5887 || !is_symlink (path))
5889 if (!errno)
5890 errno = EINVAL; /* not a symlink */
5891 return -1;
5894 /* Done with simple tests, now we're in for some _real_ work. */
5895 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5896 restore_privs = 1;
5897 /* Implementation note: From here and onward, don't return early,
5898 since that will fail to restore the original set of privileges of
5899 the calling thread. */
5901 retval = -1; /* not too optimistic, are we? */
5903 /* Note: In the next call to CreateFile, we use zero as the 2nd
5904 argument because, when the symlink is a hidden/system file,
5905 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5906 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5907 and directory symlinks. */
5908 if (w32_unicode_filenames)
5910 wchar_t path_w[MAX_PATH];
5912 filename_to_utf16 (path, path_w);
5913 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5914 FILE_FLAG_OPEN_REPARSE_POINT
5915 | FILE_FLAG_BACKUP_SEMANTICS,
5916 NULL);
5918 else
5920 char path_a[MAX_PATH];
5922 filename_to_ansi (path, path_a);
5923 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5924 FILE_FLAG_OPEN_REPARSE_POINT
5925 | FILE_FLAG_BACKUP_SEMANTICS,
5926 NULL);
5928 if (sh != INVALID_HANDLE_VALUE)
5930 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5931 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5932 DWORD retbytes;
5934 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5935 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5936 &retbytes, NULL))
5937 errno = EIO;
5938 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5939 errno = EINVAL;
5940 else
5942 /* Copy the link target name, in wide characters, from
5943 reparse_data, then convert it to multibyte encoding in
5944 the current locale's codepage. */
5945 WCHAR *lwname;
5946 size_t lname_size;
5947 USHORT lwname_len =
5948 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5949 WCHAR *lwname_src =
5950 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5951 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5952 size_t size_to_copy = buf_size;
5954 /* According to MSDN, PrintNameLength does not include the
5955 terminating null character. */
5956 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5957 memcpy (lwname, lwname_src, lwname_len);
5958 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5959 filename_from_utf16 (lwname, resolved);
5960 dostounix_filename (resolved);
5961 lname_size = strlen (resolved) + 1;
5962 if (lname_size <= buf_size)
5963 size_to_copy = lname_size;
5964 strncpy (buf, resolved, size_to_copy);
5965 /* Success! */
5966 retval = size_to_copy;
5968 CloseHandle (sh);
5970 else
5972 /* CreateFile failed. */
5973 DWORD w32err2 = GetLastError ();
5975 switch (w32err2)
5977 case ERROR_FILE_NOT_FOUND:
5978 case ERROR_PATH_NOT_FOUND:
5979 errno = ENOENT;
5980 break;
5981 case ERROR_ACCESS_DENIED:
5982 case ERROR_TOO_MANY_OPEN_FILES:
5983 errno = EACCES;
5984 break;
5985 default:
5986 errno = EPERM;
5987 break;
5990 if (restore_privs)
5992 restore_privilege (&privs);
5993 revert_to_self ();
5996 return retval;
5999 ssize_t
6000 readlinkat (int fd, char const *name, char *buffer,
6001 size_t buffer_size)
6003 /* Rely on a hack: an open directory is modeled as file descriptor 0,
6004 as in fstatat. FIXME: Add proper support for readlinkat. */
6005 char fullname[MAX_UTF8_PATH];
6007 if (fd != AT_FDCWD)
6009 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
6010 < 0)
6012 errno = ENAMETOOLONG;
6013 return -1;
6015 name = fullname;
6018 return readlink (name, buffer, buffer_size);
6021 /* If FILE is a symlink, return its target (stored in a static
6022 buffer); otherwise return FILE.
6024 This function repeatedly resolves symlinks in the last component of
6025 a chain of symlink file names, as in foo -> bar -> baz -> ...,
6026 until it arrives at a file whose last component is not a symlink,
6027 or some error occurs. It returns the target of the last
6028 successfully resolved symlink in the chain. If it succeeds to
6029 resolve even a single symlink, the value returned is an absolute
6030 file name with backslashes (result of GetFullPathName). By
6031 contrast, if the original FILE is returned, it is unaltered.
6033 Note: This function can set errno even if it succeeds.
6035 Implementation note: we only resolve the last portion ("basename")
6036 of the argument FILE and of each following file in the chain,
6037 disregarding any possible symlinks in its leading directories.
6038 This is because Windows system calls and library functions
6039 transparently resolve symlinks in leading directories and return
6040 correct information, as long as the basename is not a symlink. */
6041 static char *
6042 chase_symlinks (const char *file)
6044 static char target[MAX_UTF8_PATH];
6045 char link[MAX_UTF8_PATH];
6046 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
6047 char target_a[MAX_PATH], link_a[MAX_PATH];
6048 ssize_t res, link_len;
6049 int loop_count = 0;
6051 if (is_windows_9x () == TRUE || !is_symlink (file))
6052 return (char *)file;
6054 if (w32_unicode_filenames)
6056 wchar_t file_w[MAX_PATH];
6058 filename_to_utf16 (file, file_w);
6059 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
6060 return (char *)file;
6061 filename_from_utf16 (link_w, link);
6063 else
6065 char file_a[MAX_PATH];
6067 filename_to_ansi (file, file_a);
6068 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
6069 return (char *)file;
6070 filename_from_ansi (link_a, link);
6072 link_len = strlen (link);
6074 target[0] = '\0';
6075 do {
6077 /* Remove trailing slashes, as we want to resolve the last
6078 non-trivial part of the link name. */
6079 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
6080 link[link_len--] = '\0';
6082 res = readlink (link, target, MAX_UTF8_PATH);
6083 if (res > 0)
6085 target[res] = '\0';
6086 if (!(IS_DEVICE_SEP (target[1])
6087 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
6089 /* Target is relative. Append it to the directory part of
6090 the symlink, then copy the result back to target. */
6091 char *p = link + link_len;
6093 while (p > link && !IS_ANY_SEP (p[-1]))
6094 p--;
6095 strcpy (p, target);
6096 strcpy (target, link);
6098 /* Resolve any "." and ".." to get a fully-qualified file name
6099 in link[] again. */
6100 if (w32_unicode_filenames)
6102 filename_to_utf16 (target, target_w);
6103 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
6104 if (link_len > 0)
6105 filename_from_utf16 (link_w, link);
6107 else
6109 filename_to_ansi (target, target_a);
6110 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
6111 if (link_len > 0)
6112 filename_from_ansi (link_a, link);
6114 link_len = strlen (link);
6116 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
6118 if (loop_count > 100)
6119 errno = ELOOP;
6121 if (target[0] == '\0') /* not a single call to readlink succeeded */
6122 return (char *)file;
6123 return target;
6127 /* Posix ACL emulation. */
6130 acl_valid (acl_t acl)
6132 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
6135 char *
6136 acl_to_text (acl_t acl, ssize_t *size)
6138 LPTSTR str_acl;
6139 SECURITY_INFORMATION flags =
6140 OWNER_SECURITY_INFORMATION |
6141 GROUP_SECURITY_INFORMATION |
6142 DACL_SECURITY_INFORMATION;
6143 char *retval = NULL;
6144 ULONG local_size;
6145 int e = errno;
6147 errno = 0;
6149 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
6151 errno = e;
6152 /* We don't want to mix heaps, so we duplicate the string in our
6153 heap and free the one allocated by the API. */
6154 retval = xstrdup (str_acl);
6155 if (size)
6156 *size = local_size;
6157 LocalFree (str_acl);
6159 else if (errno != ENOTSUP)
6160 errno = EINVAL;
6162 return retval;
6165 acl_t
6166 acl_from_text (const char *acl_str)
6168 PSECURITY_DESCRIPTOR psd, retval = NULL;
6169 ULONG sd_size;
6170 int e = errno;
6172 errno = 0;
6174 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
6176 errno = e;
6177 retval = xmalloc (sd_size);
6178 memcpy (retval, psd, sd_size);
6179 LocalFree (psd);
6181 else if (errno != ENOTSUP)
6182 errno = EINVAL;
6184 return retval;
6188 acl_free (void *ptr)
6190 xfree (ptr);
6191 return 0;
6194 acl_t
6195 acl_get_file (const char *fname, acl_type_t type)
6197 PSECURITY_DESCRIPTOR psd = NULL;
6198 const char *filename;
6200 if (type == ACL_TYPE_ACCESS)
6202 DWORD sd_len, err;
6203 SECURITY_INFORMATION si =
6204 OWNER_SECURITY_INFORMATION |
6205 GROUP_SECURITY_INFORMATION |
6206 DACL_SECURITY_INFORMATION ;
6207 int e = errno;
6209 filename = map_w32_filename (fname, NULL);
6210 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6211 fname = chase_symlinks (filename);
6212 else
6213 fname = filename;
6215 errno = 0;
6216 if (!get_file_security (fname, si, psd, 0, &sd_len)
6217 && errno != ENOTSUP)
6219 err = GetLastError ();
6220 if (err == ERROR_INSUFFICIENT_BUFFER)
6222 psd = xmalloc (sd_len);
6223 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
6225 xfree (psd);
6226 errno = EIO;
6227 psd = NULL;
6230 else if (err == ERROR_FILE_NOT_FOUND
6231 || err == ERROR_PATH_NOT_FOUND
6232 /* ERROR_INVALID_NAME is what we get if
6233 w32-unicode-filenames is nil and the file cannot
6234 be encoded in the current ANSI codepage. */
6235 || err == ERROR_INVALID_NAME)
6236 errno = ENOENT;
6237 else
6238 errno = EIO;
6240 else if (!errno)
6241 errno = e;
6243 else if (type != ACL_TYPE_DEFAULT)
6244 errno = EINVAL;
6246 return psd;
6250 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
6252 TOKEN_PRIVILEGES old1, old2;
6253 DWORD err;
6254 int st = 0, retval = -1;
6255 SECURITY_INFORMATION flags = 0;
6256 PSID psidOwner, psidGroup;
6257 PACL pacl;
6258 BOOL dflt;
6259 BOOL dacl_present;
6260 int e;
6261 const char *filename;
6263 if (acl_valid (acl) != 0
6264 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
6266 errno = EINVAL;
6267 return -1;
6270 if (type == ACL_TYPE_DEFAULT)
6272 errno = ENOSYS;
6273 return -1;
6276 filename = map_w32_filename (fname, NULL);
6277 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6278 fname = chase_symlinks (filename);
6279 else
6280 fname = filename;
6282 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
6283 &dflt)
6284 && psidOwner)
6285 flags |= OWNER_SECURITY_INFORMATION;
6286 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
6287 &dflt)
6288 && psidGroup)
6289 flags |= GROUP_SECURITY_INFORMATION;
6290 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
6291 &pacl, &dflt)
6292 && dacl_present)
6293 flags |= DACL_SECURITY_INFORMATION;
6294 if (!flags)
6295 return 0;
6297 /* According to KB-245153, setting the owner will succeed if either:
6298 (1) the caller is the user who will be the new owner, and has the
6299 SE_TAKE_OWNERSHIP privilege, or
6300 (2) the caller has the SE_RESTORE privilege, in which case she can
6301 set any valid user or group as the owner
6303 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
6304 privileges, and disregard any failures in obtaining them. If
6305 these privileges cannot be obtained, and do not already exist in
6306 the calling thread's security token, this function could fail
6307 with EPERM. */
6308 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
6309 st++;
6310 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
6311 st++;
6313 e = errno;
6314 errno = 0;
6315 /* SetFileSecurity is deprecated by MS, and sometimes fails when
6316 DACL inheritance is involved, but it seems to preserve ownership
6317 better than SetNamedSecurityInfo, which is important e.g., in
6318 copy-file. */
6319 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
6321 err = GetLastError ();
6323 if (errno != ENOTSUP)
6324 err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
6325 psidOwner, psidGroup, pacl, NULL);
6327 else
6328 err = ERROR_SUCCESS;
6329 if (err != ERROR_SUCCESS)
6331 if (errno == ENOTSUP)
6333 else if (err == ERROR_INVALID_OWNER
6334 || err == ERROR_NOT_ALL_ASSIGNED
6335 || err == ERROR_ACCESS_DENIED)
6337 /* Maybe the requested ACL and the one the file already has
6338 are identical, in which case we can silently ignore the
6339 failure. (And no, Windows doesn't.) */
6340 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
6342 errno = EPERM;
6343 if (current_acl)
6345 char *acl_from = acl_to_text (current_acl, NULL);
6346 char *acl_to = acl_to_text (acl, NULL);
6348 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
6350 retval = 0;
6351 errno = e;
6353 if (acl_from)
6354 acl_free (acl_from);
6355 if (acl_to)
6356 acl_free (acl_to);
6357 acl_free (current_acl);
6360 else if (err == ERROR_FILE_NOT_FOUND
6361 || err == ERROR_PATH_NOT_FOUND
6362 /* ERROR_INVALID_NAME is what we get if
6363 w32-unicode-filenames is nil and the file cannot be
6364 encoded in the current ANSI codepage. */
6365 || err == ERROR_INVALID_NAME)
6366 errno = ENOENT;
6367 else
6368 errno = EACCES;
6370 else
6372 retval = 0;
6373 errno = e;
6376 if (st)
6378 if (st >= 2)
6379 restore_privilege (&old2);
6380 restore_privilege (&old1);
6381 revert_to_self ();
6384 return retval;
6388 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
6389 have a fixed max size for file names, so we don't need the kind of
6390 alloc/malloc/realloc dance the gnulib version does. We also don't
6391 support FD-relative symlinks. */
6392 char *
6393 careadlinkat (int fd, char const *filename,
6394 char *buffer, size_t buffer_size,
6395 struct allocator const *alloc,
6396 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6398 char linkname[MAX_UTF8_PATH];
6399 ssize_t link_size;
6401 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6403 if (link_size > 0)
6405 char *retval = buffer;
6407 linkname[link_size++] = '\0';
6408 if (link_size > buffer_size)
6409 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6410 if (retval)
6411 memcpy (retval, linkname, link_size);
6413 return retval;
6415 return NULL;
6419 w32_copy_file (const char *from, const char *to,
6420 int keep_time, int preserve_ownership, int copy_acls)
6422 acl_t acl = NULL;
6423 BOOL copy_result;
6424 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6425 char from_a[MAX_PATH], to_a[MAX_PATH];
6427 /* We ignore preserve_ownership for now. */
6428 preserve_ownership = preserve_ownership;
6430 if (copy_acls)
6432 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6433 if (acl == NULL && acl_errno_valid (errno))
6434 return -2;
6436 if (w32_unicode_filenames)
6438 filename_to_utf16 (from, from_w);
6439 filename_to_utf16 (to, to_w);
6440 copy_result = CopyFileW (from_w, to_w, FALSE);
6442 else
6444 filename_to_ansi (from, from_a);
6445 filename_to_ansi (to, to_a);
6446 copy_result = CopyFileA (from_a, to_a, FALSE);
6448 if (!copy_result)
6450 /* CopyFile doesn't set errno when it fails. By far the most
6451 "popular" reason is that the target is read-only. */
6452 DWORD err = GetLastError ();
6454 switch (err)
6456 case ERROR_FILE_NOT_FOUND:
6457 errno = ENOENT;
6458 break;
6459 case ERROR_ACCESS_DENIED:
6460 errno = EACCES;
6461 break;
6462 case ERROR_ENCRYPTION_FAILED:
6463 errno = EIO;
6464 break;
6465 default:
6466 errno = EPERM;
6467 break;
6470 if (acl)
6471 acl_free (acl);
6472 return -1;
6474 /* CopyFile retains the timestamp by default. However, see
6475 "Community Additions" for CopyFile: it sounds like that is not
6476 entirely true. Testing on Windows XP confirms that modified time
6477 is copied, but creation and last-access times are not.
6478 FIXME? */
6479 else if (!keep_time)
6481 struct timespec now;
6482 DWORD attributes;
6484 if (w32_unicode_filenames)
6486 /* Ensure file is writable while its times are set. */
6487 attributes = GetFileAttributesW (to_w);
6488 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6489 now = current_timespec ();
6490 if (set_file_times (-1, to, now, now))
6492 /* Restore original attributes. */
6493 SetFileAttributesW (to_w, attributes);
6494 if (acl)
6495 acl_free (acl);
6496 return -3;
6498 /* Restore original attributes. */
6499 SetFileAttributesW (to_w, attributes);
6501 else
6503 attributes = GetFileAttributesA (to_a);
6504 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6505 now = current_timespec ();
6506 if (set_file_times (-1, to, now, now))
6508 SetFileAttributesA (to_a, attributes);
6509 if (acl)
6510 acl_free (acl);
6511 return -3;
6513 SetFileAttributesA (to_a, attributes);
6516 if (acl != NULL)
6518 bool fail =
6519 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6520 acl_free (acl);
6521 if (fail && acl_errno_valid (errno))
6522 return -4;
6525 return 0;
6529 /* Support for browsing other processes and their attributes. See
6530 process.c for the Lisp bindings. */
6532 /* Helper wrapper functions. */
6534 static HANDLE WINAPI
6535 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6537 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6539 if (g_b_init_create_toolhelp32_snapshot == 0)
6541 g_b_init_create_toolhelp32_snapshot = 1;
6542 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6543 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6544 "CreateToolhelp32Snapshot");
6546 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6548 return INVALID_HANDLE_VALUE;
6550 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6553 static BOOL WINAPI
6554 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6556 static Process32First_Proc s_pfn_Process32_First = NULL;
6558 if (g_b_init_process32_first == 0)
6560 g_b_init_process32_first = 1;
6561 s_pfn_Process32_First = (Process32First_Proc)
6562 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6563 "Process32First");
6565 if (s_pfn_Process32_First == NULL)
6567 return FALSE;
6569 return (s_pfn_Process32_First (hSnapshot, lppe));
6572 static BOOL WINAPI
6573 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6575 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6577 if (g_b_init_process32_next == 0)
6579 g_b_init_process32_next = 1;
6580 s_pfn_Process32_Next = (Process32Next_Proc)
6581 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6582 "Process32Next");
6584 if (s_pfn_Process32_Next == NULL)
6586 return FALSE;
6588 return (s_pfn_Process32_Next (hSnapshot, lppe));
6591 static BOOL WINAPI
6592 open_thread_token (HANDLE ThreadHandle,
6593 DWORD DesiredAccess,
6594 BOOL OpenAsSelf,
6595 PHANDLE TokenHandle)
6597 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6598 HMODULE hm_advapi32 = NULL;
6599 if (is_windows_9x () == TRUE)
6601 SetLastError (ERROR_NOT_SUPPORTED);
6602 return FALSE;
6604 if (g_b_init_open_thread_token == 0)
6606 g_b_init_open_thread_token = 1;
6607 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6608 s_pfn_Open_Thread_Token =
6609 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6611 if (s_pfn_Open_Thread_Token == NULL)
6613 SetLastError (ERROR_NOT_SUPPORTED);
6614 return FALSE;
6616 return (
6617 s_pfn_Open_Thread_Token (
6618 ThreadHandle,
6619 DesiredAccess,
6620 OpenAsSelf,
6621 TokenHandle)
6625 static BOOL WINAPI
6626 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6628 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6629 HMODULE hm_advapi32 = NULL;
6630 if (is_windows_9x () == TRUE)
6632 return FALSE;
6634 if (g_b_init_impersonate_self == 0)
6636 g_b_init_impersonate_self = 1;
6637 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6638 s_pfn_Impersonate_Self =
6639 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6641 if (s_pfn_Impersonate_Self == NULL)
6643 return FALSE;
6645 return s_pfn_Impersonate_Self (ImpersonationLevel);
6648 static BOOL WINAPI
6649 revert_to_self (void)
6651 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6652 HMODULE hm_advapi32 = NULL;
6653 if (is_windows_9x () == TRUE)
6655 return FALSE;
6657 if (g_b_init_revert_to_self == 0)
6659 g_b_init_revert_to_self = 1;
6660 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6661 s_pfn_Revert_To_Self =
6662 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6664 if (s_pfn_Revert_To_Self == NULL)
6666 return FALSE;
6668 return s_pfn_Revert_To_Self ();
6671 static BOOL WINAPI
6672 get_process_memory_info (HANDLE h_proc,
6673 PPROCESS_MEMORY_COUNTERS mem_counters,
6674 DWORD bufsize)
6676 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6677 HMODULE hm_psapi = NULL;
6678 if (is_windows_9x () == TRUE)
6680 return FALSE;
6682 if (g_b_init_get_process_memory_info == 0)
6684 g_b_init_get_process_memory_info = 1;
6685 hm_psapi = LoadLibrary ("Psapi.dll");
6686 if (hm_psapi)
6687 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6688 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6690 if (s_pfn_Get_Process_Memory_Info == NULL)
6692 return FALSE;
6694 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6697 static BOOL WINAPI
6698 get_process_working_set_size (HANDLE h_proc,
6699 PSIZE_T minrss,
6700 PSIZE_T maxrss)
6702 static GetProcessWorkingSetSize_Proc
6703 s_pfn_Get_Process_Working_Set_Size = NULL;
6705 if (is_windows_9x () == TRUE)
6707 return FALSE;
6709 if (g_b_init_get_process_working_set_size == 0)
6711 g_b_init_get_process_working_set_size = 1;
6712 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6713 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6714 "GetProcessWorkingSetSize");
6716 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6718 return FALSE;
6720 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6723 static BOOL WINAPI
6724 global_memory_status (MEMORYSTATUS *buf)
6726 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6728 if (is_windows_9x () == TRUE)
6730 return FALSE;
6732 if (g_b_init_global_memory_status == 0)
6734 g_b_init_global_memory_status = 1;
6735 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6736 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6737 "GlobalMemoryStatus");
6739 if (s_pfn_Global_Memory_Status == NULL)
6741 return FALSE;
6743 return s_pfn_Global_Memory_Status (buf);
6746 static BOOL WINAPI
6747 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6749 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6751 if (is_windows_9x () == TRUE)
6753 return FALSE;
6755 if (g_b_init_global_memory_status_ex == 0)
6757 g_b_init_global_memory_status_ex = 1;
6758 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6759 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6760 "GlobalMemoryStatusEx");
6762 if (s_pfn_Global_Memory_Status_Ex == NULL)
6764 return FALSE;
6766 return s_pfn_Global_Memory_Status_Ex (buf);
6769 Lisp_Object
6770 list_system_processes (void)
6772 Lisp_Object proclist = Qnil;
6773 HANDLE h_snapshot;
6775 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6777 if (h_snapshot != INVALID_HANDLE_VALUE)
6779 PROCESSENTRY32 proc_entry;
6780 DWORD proc_id;
6781 BOOL res;
6783 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6784 for (res = process32_first (h_snapshot, &proc_entry); res;
6785 res = process32_next (h_snapshot, &proc_entry))
6787 proc_id = proc_entry.th32ProcessID;
6788 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6791 CloseHandle (h_snapshot);
6792 proclist = Fnreverse (proclist);
6795 return proclist;
6798 static int
6799 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6801 TOKEN_PRIVILEGES priv;
6802 DWORD priv_size = sizeof (priv);
6803 DWORD opriv_size = sizeof (*old_priv);
6804 HANDLE h_token = NULL;
6805 HANDLE h_thread = GetCurrentThread ();
6806 int ret_val = 0;
6807 BOOL res;
6809 res = open_thread_token (h_thread,
6810 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6811 FALSE, &h_token);
6812 if (!res && GetLastError () == ERROR_NO_TOKEN)
6814 if (impersonate_self (SecurityImpersonation))
6815 res = open_thread_token (h_thread,
6816 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6817 FALSE, &h_token);
6819 if (res)
6821 priv.PrivilegeCount = 1;
6822 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6823 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6824 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6825 old_priv, &opriv_size)
6826 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6827 ret_val = 1;
6829 if (h_token)
6830 CloseHandle (h_token);
6832 return ret_val;
6835 static int
6836 restore_privilege (TOKEN_PRIVILEGES *priv)
6838 DWORD priv_size = sizeof (*priv);
6839 HANDLE h_token = NULL;
6840 int ret_val = 0;
6842 if (open_thread_token (GetCurrentThread (),
6843 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6844 FALSE, &h_token))
6846 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6847 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6848 ret_val = 1;
6850 if (h_token)
6851 CloseHandle (h_token);
6853 return ret_val;
6856 static Lisp_Object
6857 ltime (ULONGLONG time_100ns)
6859 ULONGLONG time_sec = time_100ns / 10000000;
6860 int subsec = time_100ns % 10000000;
6861 return list4i (time_sec >> 16, time_sec & 0xffff,
6862 subsec / 10, subsec % 10 * 100000);
6865 #define U64_TO_LISP_TIME(time) ltime (time)
6867 static int
6868 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6869 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6870 double *pcpu)
6872 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6873 ULONGLONG tem1, tem2, tem3, tem;
6875 if (!h_proc
6876 || !get_process_times_fn
6877 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6878 &ft_kernel, &ft_user))
6879 return 0;
6881 GetSystemTimeAsFileTime (&ft_current);
6883 FILETIME_TO_U64 (tem1, ft_kernel);
6884 *stime = U64_TO_LISP_TIME (tem1);
6886 FILETIME_TO_U64 (tem2, ft_user);
6887 *utime = U64_TO_LISP_TIME (tem2);
6889 tem3 = tem1 + tem2;
6890 *ttime = U64_TO_LISP_TIME (tem3);
6892 FILETIME_TO_U64 (tem, ft_creation);
6893 /* Process no 4 (System) returns zero creation time. */
6894 if (tem)
6895 tem -= utc_base;
6896 *ctime = U64_TO_LISP_TIME (tem);
6898 if (tem)
6900 FILETIME_TO_U64 (tem3, ft_current);
6901 tem = (tem3 - utc_base) - tem;
6903 *etime = U64_TO_LISP_TIME (tem);
6905 if (tem)
6907 *pcpu = 100.0 * (tem1 + tem2) / tem;
6908 if (*pcpu > 100)
6909 *pcpu = 100.0;
6911 else
6912 *pcpu = 0;
6914 return 1;
6917 Lisp_Object
6918 system_process_attributes (Lisp_Object pid)
6920 Lisp_Object attrs = Qnil;
6921 Lisp_Object cmd_str, decoded_cmd, tem;
6922 HANDLE h_snapshot, h_proc;
6923 DWORD proc_id;
6924 int found_proc = 0;
6925 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
6926 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
6927 DWORD glength = sizeof (gname);
6928 HANDLE token = NULL;
6929 SID_NAME_USE user_type;
6930 unsigned char *buf = NULL;
6931 DWORD blen = 0;
6932 TOKEN_USER user_token;
6933 TOKEN_PRIMARY_GROUP group_token;
6934 unsigned euid;
6935 unsigned egid;
6936 PROCESS_MEMORY_COUNTERS mem;
6937 PROCESS_MEMORY_COUNTERS_EX mem_ex;
6938 SIZE_T minrss, maxrss;
6939 MEMORYSTATUS memst;
6940 MEMORY_STATUS_EX memstex;
6941 double totphys = 0.0;
6942 Lisp_Object ctime, stime, utime, etime, ttime;
6943 double pcpu;
6944 BOOL result = FALSE;
6946 CHECK_NUMBER_OR_FLOAT (pid);
6947 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
6949 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6951 if (h_snapshot != INVALID_HANDLE_VALUE)
6953 PROCESSENTRY32 pe;
6954 BOOL res;
6956 pe.dwSize = sizeof (PROCESSENTRY32);
6957 for (res = process32_first (h_snapshot, &pe); res;
6958 res = process32_next (h_snapshot, &pe))
6960 if (proc_id == pe.th32ProcessID)
6962 if (proc_id == 0)
6963 decoded_cmd = build_string ("Idle");
6964 else
6966 /* Decode the command name from locale-specific
6967 encoding. */
6968 cmd_str = build_unibyte_string (pe.szExeFile);
6970 decoded_cmd =
6971 code_convert_string_norecord (cmd_str,
6972 Vlocale_coding_system, 0);
6974 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
6975 attrs = Fcons (Fcons (Qppid,
6976 make_fixnum_or_float (pe.th32ParentProcessID)),
6977 attrs);
6978 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
6979 attrs);
6980 attrs = Fcons (Fcons (Qthcount,
6981 make_fixnum_or_float (pe.cntThreads)),
6982 attrs);
6983 found_proc = 1;
6984 break;
6988 CloseHandle (h_snapshot);
6991 if (!found_proc)
6992 return Qnil;
6994 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6995 FALSE, proc_id);
6996 /* If we were denied a handle to the process, try again after
6997 enabling the SeDebugPrivilege in our process. */
6998 if (!h_proc)
7000 TOKEN_PRIVILEGES priv_current;
7002 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
7004 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
7005 FALSE, proc_id);
7006 restore_privilege (&priv_current);
7007 revert_to_self ();
7010 if (h_proc)
7012 result = open_process_token (h_proc, TOKEN_QUERY, &token);
7013 if (result)
7015 result = get_token_information (token, TokenUser, NULL, 0, &blen);
7016 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7018 buf = xmalloc (blen);
7019 result = get_token_information (token, TokenUser,
7020 (LPVOID)buf, blen, &needed);
7021 if (result)
7023 memcpy (&user_token, buf, sizeof (user_token));
7024 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
7026 euid = get_rid (user_token.User.Sid);
7027 result = lookup_account_sid (NULL, user_token.User.Sid,
7028 uname, &ulength,
7029 domain, &dlength,
7030 &user_type);
7031 if (result)
7032 w32_add_to_cache (user_token.User.Sid, euid, uname);
7033 else
7035 strcpy (uname, "unknown");
7036 result = TRUE;
7039 ulength = strlen (uname);
7043 if (result)
7045 /* Determine a reasonable euid and gid values. */
7046 if (xstrcasecmp ("administrator", uname) == 0)
7048 euid = 500; /* well-known Administrator uid */
7049 egid = 513; /* well-known None gid */
7051 else
7053 /* Get group id and name. */
7054 result = get_token_information (token, TokenPrimaryGroup,
7055 (LPVOID)buf, blen, &needed);
7056 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7058 buf = xrealloc (buf, blen = needed);
7059 result = get_token_information (token, TokenPrimaryGroup,
7060 (LPVOID)buf, blen, &needed);
7062 if (result)
7064 memcpy (&group_token, buf, sizeof (group_token));
7065 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
7067 egid = get_rid (group_token.PrimaryGroup);
7068 dlength = sizeof (domain);
7069 result =
7070 lookup_account_sid (NULL, group_token.PrimaryGroup,
7071 gname, &glength, NULL, &dlength,
7072 &user_type);
7073 if (result)
7074 w32_add_to_cache (group_token.PrimaryGroup,
7075 egid, gname);
7076 else
7078 strcpy (gname, "None");
7079 result = TRUE;
7082 glength = strlen (gname);
7086 xfree (buf);
7088 if (!result)
7090 if (!is_windows_9x ())
7092 /* We couldn't open the process token, presumably because of
7093 insufficient access rights. Assume this process is run
7094 by the system. */
7095 strcpy (uname, "SYSTEM");
7096 strcpy (gname, "None");
7097 euid = 18; /* SYSTEM */
7098 egid = 513; /* None */
7099 glength = strlen (gname);
7100 ulength = strlen (uname);
7102 /* If we are running under Windows 9X, where security calls are
7103 not supported, we assume all processes are run by the current
7104 user. */
7105 else if (GetUserName (uname, &ulength))
7107 if (xstrcasecmp ("administrator", uname) == 0)
7108 euid = 0;
7109 else
7110 euid = 123;
7111 egid = euid;
7112 strcpy (gname, "None");
7113 glength = strlen (gname);
7114 ulength = strlen (uname);
7116 else
7118 euid = 123;
7119 egid = 123;
7120 strcpy (uname, "administrator");
7121 ulength = strlen (uname);
7122 strcpy (gname, "None");
7123 glength = strlen (gname);
7125 if (token)
7126 CloseHandle (token);
7129 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
7130 tem = make_unibyte_string (uname, ulength);
7131 attrs = Fcons (Fcons (Quser,
7132 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7133 attrs);
7134 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
7135 tem = make_unibyte_string (gname, glength);
7136 attrs = Fcons (Fcons (Qgroup,
7137 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7138 attrs);
7140 if (global_memory_status_ex (&memstex))
7141 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
7142 totphys = memstex.ullTotalPhys / 1024.0;
7143 #else
7144 /* Visual Studio 6 cannot convert an unsigned __int64 type to
7145 double, so we need to do this for it... */
7147 DWORD tot_hi = memstex.ullTotalPhys >> 32;
7148 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
7149 DWORD tot_lo = memstex.ullTotalPhys % 1024;
7151 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
7153 #endif /* __GNUC__ || _MSC_VER >= 1300 */
7154 else if (global_memory_status (&memst))
7155 totphys = memst.dwTotalPhys / 1024.0;
7157 if (h_proc
7158 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
7159 sizeof (mem_ex)))
7161 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7163 attrs = Fcons (Fcons (Qmajflt,
7164 make_fixnum_or_float (mem_ex.PageFaultCount)),
7165 attrs);
7166 attrs = Fcons (Fcons (Qvsize,
7167 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
7168 attrs);
7169 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7170 if (totphys)
7171 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7173 else if (h_proc
7174 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
7176 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7178 attrs = Fcons (Fcons (Qmajflt,
7179 make_fixnum_or_float (mem.PageFaultCount)),
7180 attrs);
7181 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7182 if (totphys)
7183 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7185 else if (h_proc
7186 && get_process_working_set_size (h_proc, &minrss, &maxrss))
7188 DWORD rss = maxrss / 1024;
7190 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
7191 if (totphys)
7192 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7195 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
7197 attrs = Fcons (Fcons (Qutime, utime), attrs);
7198 attrs = Fcons (Fcons (Qstime, stime), attrs);
7199 attrs = Fcons (Fcons (Qtime, ttime), attrs);
7200 attrs = Fcons (Fcons (Qstart, ctime), attrs);
7201 attrs = Fcons (Fcons (Qetime, etime), attrs);
7202 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
7205 /* FIXME: Retrieve command line by walking the PEB of the process. */
7207 if (h_proc)
7208 CloseHandle (h_proc);
7209 return attrs;
7213 w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
7214 unsigned long long *totalswap, unsigned long long *freeswap)
7216 MEMORYSTATUS memst;
7217 MEMORY_STATUS_EX memstex;
7219 /* Use GlobalMemoryStatusEx if available, as it can report more than
7220 2GB of memory. */
7221 if (global_memory_status_ex (&memstex))
7223 *totalram = memstex.ullTotalPhys;
7224 *freeram = memstex.ullAvailPhys;
7225 *totalswap = memstex.ullTotalPageFile;
7226 *freeswap = memstex.ullAvailPageFile;
7227 return 0;
7229 else if (global_memory_status (&memst))
7231 *totalram = memst.dwTotalPhys;
7232 *freeram = memst.dwAvailPhys;
7233 *totalswap = memst.dwTotalPageFile;
7234 *freeswap = memst.dwAvailPageFile;
7235 return 0;
7237 else
7238 return -1;
7242 /* Wrappers for winsock functions to map between our file descriptors
7243 and winsock's handles; also set h_errno for convenience.
7245 To allow Emacs to run on systems which don't have winsock support
7246 installed, we dynamically link to winsock on startup if present, and
7247 otherwise provide the minimum necessary functionality
7248 (eg. gethostname). */
7250 /* function pointers for relevant socket functions */
7251 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
7252 void (PASCAL *pfn_WSASetLastError) (int iError);
7253 int (PASCAL *pfn_WSAGetLastError) (void);
7254 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
7255 int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject,
7256 WSANETWORKEVENTS *NetworkEvents);
7258 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
7259 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
7260 int (PASCAL *pfn_socket) (int af, int type, int protocol);
7261 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
7262 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
7263 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
7264 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
7265 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
7266 int (PASCAL *pfn_closesocket) (SOCKET s);
7267 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
7268 int (PASCAL *pfn_WSACleanup) (void);
7270 u_short (PASCAL *pfn_htons) (u_short hostshort);
7271 u_short (PASCAL *pfn_ntohs) (u_short netshort);
7272 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
7273 int (PASCAL *pfn_gethostname) (char * name, int namelen);
7274 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
7275 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
7276 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
7277 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
7278 const char * optval, int optlen);
7279 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
7280 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
7281 int * namelen);
7282 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
7283 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
7284 struct sockaddr * from, int * fromlen);
7285 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
7286 const struct sockaddr * to, int tolen);
7288 int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
7289 const struct addrinfo *, struct addrinfo **);
7290 void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
7292 /* SetHandleInformation is only needed to make sockets non-inheritable. */
7293 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7294 #ifndef HANDLE_FLAG_INHERIT
7295 #define HANDLE_FLAG_INHERIT 1
7296 #endif
7298 HANDLE winsock_lib;
7299 static int winsock_inuse;
7301 BOOL term_winsock (void);
7303 BOOL
7304 term_winsock (void)
7306 if (winsock_lib != NULL && winsock_inuse == 0)
7308 release_listen_threads ();
7309 /* Not sure what would cause WSAENETDOWN, or even if it can happen
7310 after WSAStartup returns successfully, but it seems reasonable
7311 to allow unloading winsock anyway in that case. */
7312 if (pfn_WSACleanup () == 0 ||
7313 pfn_WSAGetLastError () == WSAENETDOWN)
7315 if (FreeLibrary (winsock_lib))
7316 winsock_lib = NULL;
7317 return TRUE;
7320 return FALSE;
7323 BOOL
7324 init_winsock (int load_now)
7326 WSADATA winsockData;
7328 if (winsock_lib != NULL)
7329 return TRUE;
7331 pfn_SetHandleInformation
7332 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
7333 "SetHandleInformation");
7335 winsock_lib = LoadLibrary ("Ws2_32.dll");
7337 if (winsock_lib != NULL)
7339 /* dynamically link to socket functions */
7341 #define LOAD_PROC(fn) \
7342 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
7343 goto fail;
7345 LOAD_PROC (WSAStartup);
7346 LOAD_PROC (WSASetLastError);
7347 LOAD_PROC (WSAGetLastError);
7348 LOAD_PROC (WSAEventSelect);
7349 LOAD_PROC (WSAEnumNetworkEvents);
7350 LOAD_PROC (WSACreateEvent);
7351 LOAD_PROC (WSACloseEvent);
7352 LOAD_PROC (socket);
7353 LOAD_PROC (bind);
7354 LOAD_PROC (connect);
7355 LOAD_PROC (ioctlsocket);
7356 LOAD_PROC (recv);
7357 LOAD_PROC (send);
7358 LOAD_PROC (closesocket);
7359 LOAD_PROC (shutdown);
7360 LOAD_PROC (htons);
7361 LOAD_PROC (ntohs);
7362 LOAD_PROC (inet_addr);
7363 LOAD_PROC (gethostname);
7364 LOAD_PROC (gethostbyname);
7365 LOAD_PROC (getservbyname);
7366 LOAD_PROC (getpeername);
7367 LOAD_PROC (WSACleanup);
7368 LOAD_PROC (setsockopt);
7369 LOAD_PROC (listen);
7370 LOAD_PROC (getsockname);
7371 LOAD_PROC (accept);
7372 LOAD_PROC (recvfrom);
7373 LOAD_PROC (sendto);
7374 #undef LOAD_PROC
7376 /* Try loading functions not available before XP. */
7377 pfn_getaddrinfo = (void *) GetProcAddress (winsock_lib, "getaddrinfo");
7378 pfn_freeaddrinfo = (void *) GetProcAddress (winsock_lib, "freeaddrinfo");
7379 /* Paranoia: these two functions should go together, so if one
7380 is absent, we cannot use the other. */
7381 if (pfn_getaddrinfo == NULL)
7382 pfn_freeaddrinfo = NULL;
7383 else if (pfn_freeaddrinfo == NULL)
7384 pfn_getaddrinfo = NULL;
7386 /* specify version 1.1 of winsock */
7387 if (pfn_WSAStartup (0x101, &winsockData) == 0)
7389 if (winsockData.wVersion != 0x101)
7390 goto fail;
7392 if (!load_now)
7394 /* Report that winsock exists and is usable, but leave
7395 socket functions disabled. I am assuming that calling
7396 WSAStartup does not require any network interaction,
7397 and in particular does not cause or require a dial-up
7398 connection to be established. */
7400 pfn_WSACleanup ();
7401 FreeLibrary (winsock_lib);
7402 winsock_lib = NULL;
7404 winsock_inuse = 0;
7405 return TRUE;
7408 fail:
7409 FreeLibrary (winsock_lib);
7410 winsock_lib = NULL;
7413 return FALSE;
7417 int h_errno = 0;
7419 /* Function to map winsock error codes to errno codes for those errno
7420 code defined in errno.h (errno values not defined by errno.h are
7421 already in nt/inc/sys/socket.h). */
7422 static void
7423 set_errno (void)
7425 int wsa_err;
7427 h_errno = 0;
7428 if (winsock_lib == NULL)
7429 wsa_err = EINVAL;
7430 else
7431 wsa_err = pfn_WSAGetLastError ();
7433 switch (wsa_err)
7435 case WSAEACCES: errno = EACCES; break;
7436 case WSAEBADF: errno = EBADF; break;
7437 case WSAEFAULT: errno = EFAULT; break;
7438 case WSAEINTR: errno = EINTR; break;
7439 case WSAEINVAL: errno = EINVAL; break;
7440 case WSAEMFILE: errno = EMFILE; break;
7441 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7442 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7443 case WSAEWOULDBLOCK: errno = EWOULDBLOCK; break;
7444 case WSAENOTCONN: errno = ENOTCONN; break;
7445 default: errno = wsa_err; break;
7449 static void
7450 check_errno (void)
7452 h_errno = 0;
7453 if (winsock_lib != NULL)
7454 pfn_WSASetLastError (0);
7457 /* Extend strerror to handle the winsock-specific error codes. */
7458 struct {
7459 int errnum;
7460 const char * msg;
7461 } _wsa_errlist[] = {
7462 {WSAEINTR , "Interrupted function call"},
7463 {WSAEBADF , "Bad file descriptor"},
7464 {WSAEACCES , "Permission denied"},
7465 {WSAEFAULT , "Bad address"},
7466 {WSAEINVAL , "Invalid argument"},
7467 {WSAEMFILE , "Too many open files"},
7469 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7470 {WSAEINPROGRESS , "Operation now in progress"},
7471 {WSAEALREADY , "Operation already in progress"},
7472 {WSAENOTSOCK , "Socket operation on non-socket"},
7473 {WSAEDESTADDRREQ , "Destination address required"},
7474 {WSAEMSGSIZE , "Message too long"},
7475 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7476 {WSAENOPROTOOPT , "Bad protocol option"},
7477 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7478 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7479 {WSAEOPNOTSUPP , "Operation not supported"},
7480 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7481 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7482 {WSAEADDRINUSE , "Address already in use"},
7483 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7484 {WSAENETDOWN , "Network is down"},
7485 {WSAENETUNREACH , "Network is unreachable"},
7486 {WSAENETRESET , "Network dropped connection on reset"},
7487 {WSAECONNABORTED , "Software caused connection abort"},
7488 {WSAECONNRESET , "Connection reset by peer"},
7489 {WSAENOBUFS , "No buffer space available"},
7490 {WSAEISCONN , "Socket is already connected"},
7491 {WSAENOTCONN , "Socket is not connected"},
7492 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7493 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7494 {WSAETIMEDOUT , "Connection timed out"},
7495 {WSAECONNREFUSED , "Connection refused"},
7496 {WSAELOOP , "Network loop"}, /* not sure */
7497 {WSAENAMETOOLONG , "Name is too long"},
7498 {WSAEHOSTDOWN , "Host is down"},
7499 {WSAEHOSTUNREACH , "No route to host"},
7500 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7501 {WSAEPROCLIM , "Too many processes"},
7502 {WSAEUSERS , "Too many users"}, /* not sure */
7503 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7504 {WSAESTALE , "Data is stale"}, /* not sure */
7505 {WSAEREMOTE , "Remote error"}, /* not sure */
7507 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7508 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7509 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7510 {WSAEDISCON , "Graceful shutdown in progress"},
7511 #ifdef WSAENOMORE
7512 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7513 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7514 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7515 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7516 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7517 {WSASYSCALLFAILURE , "System call failure"},
7518 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7519 {WSATYPE_NOT_FOUND , "Class type not found"},
7520 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7521 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7522 {WSAEREFUSED , "Operation refused"}, /* not sure */
7523 #endif
7525 {WSAHOST_NOT_FOUND , "Host not found"},
7526 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7527 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7528 {WSANO_DATA , "Valid name, no data record of requested type"},
7530 {-1, NULL}
7533 char *
7534 sys_strerror (int error_no)
7536 int i;
7537 static char unknown_msg[40];
7539 if (error_no >= 0 && error_no < sys_nerr)
7540 return sys_errlist[error_no];
7542 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7543 if (_wsa_errlist[i].errnum == error_no)
7544 return (char *)_wsa_errlist[i].msg;
7546 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7547 return unknown_msg;
7550 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7551 but I believe the method of keeping the socket handle separate (and
7552 insuring it is not inheritable) is the correct one. */
7554 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7556 static int socket_to_fd (SOCKET s);
7559 sys_socket (int af, int type, int protocol)
7561 SOCKET s;
7563 if (winsock_lib == NULL)
7565 errno = ENETDOWN;
7566 return -1;
7569 check_errno ();
7571 /* call the real socket function */
7572 s = pfn_socket (af, type, protocol);
7574 if (s != INVALID_SOCKET)
7575 return socket_to_fd (s);
7577 set_errno ();
7578 return -1;
7581 /* Convert a SOCKET to a file descriptor. */
7582 static int
7583 socket_to_fd (SOCKET s)
7585 int fd;
7586 child_process * cp;
7588 /* Although under NT 3.5 _open_osfhandle will accept a socket
7589 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7590 that does not work under NT 3.1. However, we can get the same
7591 effect by using a backdoor function to replace an existing
7592 descriptor handle with the one we want. */
7594 /* allocate a file descriptor (with appropriate flags) */
7595 fd = _open ("NUL:", _O_RDWR);
7596 if (fd >= 0)
7598 /* Make a non-inheritable copy of the socket handle. Note
7599 that it is possible that sockets aren't actually kernel
7600 handles, which appears to be the case on Windows 9x when
7601 the MS Proxy winsock client is installed. */
7603 /* Apparently there is a bug in NT 3.51 with some service
7604 packs, which prevents using DuplicateHandle to make a
7605 socket handle non-inheritable (causes WSACleanup to
7606 hang). The work-around is to use SetHandleInformation
7607 instead if it is available and implemented. */
7608 if (pfn_SetHandleInformation)
7610 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7612 else
7614 HANDLE parent = GetCurrentProcess ();
7615 HANDLE new_s = INVALID_HANDLE_VALUE;
7617 if (DuplicateHandle (parent,
7618 (HANDLE) s,
7619 parent,
7620 &new_s,
7622 FALSE,
7623 DUPLICATE_SAME_ACCESS))
7625 /* It is possible that DuplicateHandle succeeds even
7626 though the socket wasn't really a kernel handle,
7627 because a real handle has the same value. So
7628 test whether the new handle really is a socket. */
7629 unsigned long nonblocking = 0;
7630 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7632 pfn_closesocket (s);
7633 s = (SOCKET) new_s;
7635 else
7637 CloseHandle (new_s);
7642 eassert (fd < MAXDESC);
7643 fd_info[fd].hnd = (HANDLE) s;
7645 /* set our own internal flags */
7646 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7648 cp = new_child ();
7649 if (cp)
7651 cp->fd = fd;
7652 cp->status = STATUS_READ_ACKNOWLEDGED;
7654 /* attach child_process to fd_info */
7655 if (fd_info[ fd ].cp != NULL)
7657 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7658 emacs_abort ();
7661 fd_info[ fd ].cp = cp;
7663 /* success! */
7664 winsock_inuse++; /* count open sockets */
7665 return fd;
7668 /* clean up */
7669 _close (fd);
7671 else
7672 pfn_closesocket (s);
7673 errno = EMFILE;
7674 return -1;
7678 sys_bind (int s, const struct sockaddr * addr, int namelen)
7680 if (winsock_lib == NULL)
7682 errno = ENOTSOCK;
7683 return SOCKET_ERROR;
7686 check_errno ();
7687 if (fd_info[s].flags & FILE_SOCKET)
7689 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7690 if (rc == SOCKET_ERROR)
7691 set_errno ();
7692 return rc;
7694 errno = ENOTSOCK;
7695 return SOCKET_ERROR;
7699 sys_connect (int s, const struct sockaddr * name, int namelen)
7701 if (winsock_lib == NULL)
7703 errno = ENOTSOCK;
7704 return SOCKET_ERROR;
7707 check_errno ();
7708 if (fd_info[s].flags & FILE_SOCKET)
7710 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7711 if (rc == SOCKET_ERROR)
7713 set_errno ();
7714 /* If this is a non-blocking 'connect', set the bit in flags
7715 that will tell reader_thread to wait for connection
7716 before trying to read. */
7717 if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0)
7719 errno = EINPROGRESS; /* that's what process.c expects */
7720 fd_info[s].flags |= FILE_CONNECT;
7723 return rc;
7725 errno = ENOTSOCK;
7726 return SOCKET_ERROR;
7729 u_short
7730 sys_htons (u_short hostshort)
7732 return (winsock_lib != NULL) ?
7733 pfn_htons (hostshort) : hostshort;
7736 u_short
7737 sys_ntohs (u_short netshort)
7739 return (winsock_lib != NULL) ?
7740 pfn_ntohs (netshort) : netshort;
7743 unsigned long
7744 sys_inet_addr (const char * cp)
7746 return (winsock_lib != NULL) ?
7747 pfn_inet_addr (cp) : INADDR_NONE;
7751 sys_gethostname (char * name, int namelen)
7753 if (winsock_lib != NULL)
7755 int retval;
7757 check_errno ();
7758 retval = pfn_gethostname (name, namelen);
7759 if (retval == SOCKET_ERROR)
7760 set_errno ();
7761 return retval;
7764 if (namelen > MAX_COMPUTERNAME_LENGTH)
7765 return !GetComputerName (name, (DWORD *)&namelen);
7767 errno = EFAULT;
7768 return SOCKET_ERROR;
7771 struct hostent *
7772 sys_gethostbyname (const char * name)
7774 struct hostent * host;
7775 int h_err = h_errno;
7777 if (winsock_lib == NULL)
7779 h_errno = NO_RECOVERY;
7780 errno = ENETDOWN;
7781 return NULL;
7784 check_errno ();
7785 host = pfn_gethostbyname (name);
7786 if (!host)
7788 set_errno ();
7789 h_errno = errno;
7791 else
7792 h_errno = h_err;
7793 return host;
7796 struct servent *
7797 sys_getservbyname (const char * name, const char * proto)
7799 struct servent * serv;
7801 if (winsock_lib == NULL)
7803 errno = ENETDOWN;
7804 return NULL;
7807 check_errno ();
7808 serv = pfn_getservbyname (name, proto);
7809 if (!serv)
7810 set_errno ();
7811 return serv;
7815 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7817 if (winsock_lib == NULL)
7819 errno = ENETDOWN;
7820 return SOCKET_ERROR;
7823 check_errno ();
7824 if (fd_info[s].flags & FILE_SOCKET)
7826 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7827 if (rc == SOCKET_ERROR)
7828 set_errno ();
7829 return rc;
7831 errno = ENOTSOCK;
7832 return SOCKET_ERROR;
7836 sys_getaddrinfo (const char *node, const char *service,
7837 const struct addrinfo *hints, struct addrinfo **res)
7839 int rc;
7841 if (winsock_lib == NULL)
7843 errno = ENETDOWN;
7844 return SOCKET_ERROR;
7847 check_errno ();
7848 if (pfn_getaddrinfo)
7849 rc = pfn_getaddrinfo (node, service, hints, res);
7850 else
7852 int port = 0;
7853 struct hostent *host_info;
7854 struct gai_storage {
7855 struct addrinfo addrinfo;
7856 struct sockaddr_in sockaddr_in;
7857 } *gai_storage;
7859 /* We don't (yet) support any flags, as Emacs doesn't need that. */
7860 if (hints && hints->ai_flags != 0)
7861 return WSAEINVAL;
7862 /* NODE cannot be NULL, since process.c has fallbacks for that. */
7863 if (!node)
7864 return WSAHOST_NOT_FOUND;
7866 if (service)
7868 const char *protocol =
7869 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
7870 struct servent *srv = sys_getservbyname (service, protocol);
7872 if (srv)
7873 port = srv->s_port;
7874 else if (*service >= '0' && *service <= '9')
7876 char *endp;
7878 port = strtoul (service, &endp, 10);
7879 if (*endp || port > 65536)
7880 return WSAHOST_NOT_FOUND;
7881 port = sys_htons ((unsigned short) port);
7883 else
7884 return WSAHOST_NOT_FOUND;
7887 gai_storage = xzalloc (sizeof *gai_storage);
7888 gai_storage->sockaddr_in.sin_port = port;
7889 host_info = sys_gethostbyname (node);
7890 if (host_info)
7892 memcpy (&gai_storage->sockaddr_in.sin_addr,
7893 host_info->h_addr, host_info->h_length);
7894 gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
7896 else
7898 /* Attempt to interpret host as numeric inet address. */
7899 unsigned long numeric_addr = sys_inet_addr (node);
7901 if (numeric_addr == -1)
7903 free (gai_storage);
7904 return WSAHOST_NOT_FOUND;
7907 memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
7908 sizeof (gai_storage->sockaddr_in.sin_addr));
7909 gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
7912 gai_storage->addrinfo.ai_addr =
7913 (struct sockaddr *)&gai_storage->sockaddr_in;
7914 gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
7915 gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
7916 gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
7917 gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
7918 gai_storage->addrinfo.ai_next = NULL;
7920 *res = &gai_storage->addrinfo;
7921 rc = 0;
7924 return rc;
7927 void
7928 sys_freeaddrinfo (struct addrinfo *ai)
7930 if (winsock_lib == NULL)
7932 errno = ENETDOWN;
7933 return;
7936 check_errno ();
7937 if (pfn_freeaddrinfo)
7938 pfn_freeaddrinfo (ai);
7939 else
7941 eassert (ai->ai_next == NULL);
7942 xfree (ai);
7947 sys_shutdown (int s, int how)
7949 if (winsock_lib == NULL)
7951 errno = ENETDOWN;
7952 return SOCKET_ERROR;
7955 check_errno ();
7956 if (fd_info[s].flags & FILE_SOCKET)
7958 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
7959 if (rc == SOCKET_ERROR)
7960 set_errno ();
7961 return rc;
7963 errno = ENOTSOCK;
7964 return SOCKET_ERROR;
7968 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
7970 if (winsock_lib == NULL)
7972 errno = ENETDOWN;
7973 return SOCKET_ERROR;
7976 check_errno ();
7977 if (fd_info[s].flags & FILE_SOCKET)
7979 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
7980 (const char *)optval, optlen);
7981 if (rc == SOCKET_ERROR)
7982 set_errno ();
7983 return rc;
7985 errno = ENOTSOCK;
7986 return SOCKET_ERROR;
7990 sys_listen (int s, int backlog)
7992 if (winsock_lib == NULL)
7994 errno = ENETDOWN;
7995 return SOCKET_ERROR;
7998 check_errno ();
7999 if (fd_info[s].flags & FILE_SOCKET)
8001 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
8002 if (rc == SOCKET_ERROR)
8003 set_errno ();
8004 else
8005 fd_info[s].flags |= FILE_LISTEN;
8006 return rc;
8008 errno = ENOTSOCK;
8009 return SOCKET_ERROR;
8013 sys_getsockname (int s, struct sockaddr * name, int * namelen)
8015 if (winsock_lib == NULL)
8017 errno = ENETDOWN;
8018 return SOCKET_ERROR;
8021 check_errno ();
8022 if (fd_info[s].flags & FILE_SOCKET)
8024 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
8025 if (rc == SOCKET_ERROR)
8026 set_errno ();
8027 return rc;
8029 errno = ENOTSOCK;
8030 return SOCKET_ERROR;
8034 sys_accept (int s, struct sockaddr * addr, int * addrlen)
8036 if (winsock_lib == NULL)
8038 errno = ENETDOWN;
8039 return -1;
8042 check_errno ();
8043 if (fd_info[s].flags & FILE_LISTEN)
8045 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
8046 int fd = -1;
8047 if (t == INVALID_SOCKET)
8048 set_errno ();
8049 else
8050 fd = socket_to_fd (t);
8052 if (fd >= 0)
8054 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
8055 ResetEvent (fd_info[s].cp->char_avail);
8057 return fd;
8059 errno = ENOTSOCK;
8060 return -1;
8064 sys_recvfrom (int s, char * buf, int len, int flags,
8065 struct sockaddr * from, int * fromlen)
8067 if (winsock_lib == NULL)
8069 errno = ENETDOWN;
8070 return SOCKET_ERROR;
8073 check_errno ();
8074 if (fd_info[s].flags & FILE_SOCKET)
8076 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
8077 if (rc == SOCKET_ERROR)
8078 set_errno ();
8079 return rc;
8081 errno = ENOTSOCK;
8082 return SOCKET_ERROR;
8086 sys_sendto (int s, const char * buf, int len, int flags,
8087 const struct sockaddr * to, int tolen)
8089 if (winsock_lib == NULL)
8091 errno = ENETDOWN;
8092 return SOCKET_ERROR;
8095 check_errno ();
8096 if (fd_info[s].flags & FILE_SOCKET)
8098 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
8099 if (rc == SOCKET_ERROR)
8100 set_errno ();
8101 return rc;
8103 errno = ENOTSOCK;
8104 return SOCKET_ERROR;
8107 /* Windows does not have an fcntl function. Provide an implementation
8108 good enough for Emacs. */
8110 fcntl (int s, int cmd, int options)
8112 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
8113 invoked in a context where fd1 is closed and all descriptors less
8114 than fd1 are open, so sys_dup is an adequate implementation. */
8115 if (cmd == F_DUPFD_CLOEXEC)
8116 return sys_dup (s);
8118 check_errno ();
8119 if (fd_info[s].flags & FILE_SOCKET)
8121 if (winsock_lib == NULL)
8123 errno = ENETDOWN;
8124 return -1;
8127 if (cmd == F_SETFL && options == O_NONBLOCK)
8129 unsigned long nblock = 1;
8130 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
8131 if (rc == SOCKET_ERROR)
8132 set_errno ();
8133 /* Keep track of the fact that we set this to non-blocking. */
8134 fd_info[s].flags |= FILE_NDELAY;
8135 return rc;
8137 else
8139 errno = EINVAL;
8140 return SOCKET_ERROR;
8143 else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE))
8144 == (FILE_PIPE | FILE_WRITE))
8146 /* Force our writes to pipes be non-blocking. */
8147 if (cmd == F_SETFL && options == O_NONBLOCK)
8149 HANDLE h = (HANDLE)_get_osfhandle (s);
8150 DWORD pipe_mode = PIPE_NOWAIT;
8152 if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL))
8154 DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ()));
8155 return SOCKET_ERROR;
8157 fd_info[s].flags |= FILE_NDELAY;
8158 return 0;
8160 else
8162 errno = EINVAL;
8163 return SOCKET_ERROR;
8166 errno = ENOTSOCK;
8167 return SOCKET_ERROR;
8171 /* Shadow main io functions: we need to handle pipes and sockets more
8172 intelligently. */
8175 sys_close (int fd)
8177 int rc;
8179 if (fd < 0)
8181 errno = EBADF;
8182 return -1;
8185 if (fd < MAXDESC && fd_info[fd].cp)
8187 child_process * cp = fd_info[fd].cp;
8189 fd_info[fd].cp = NULL;
8191 if (CHILD_ACTIVE (cp))
8193 /* if last descriptor to active child_process then cleanup */
8194 int i;
8195 for (i = 0; i < MAXDESC; i++)
8197 if (i == fd)
8198 continue;
8199 if (fd_info[i].cp == cp)
8200 break;
8202 if (i == MAXDESC)
8204 if (fd_info[fd].flags & FILE_SOCKET)
8206 if (winsock_lib == NULL) emacs_abort ();
8208 pfn_shutdown (SOCK_HANDLE (fd), 2);
8209 rc = pfn_closesocket (SOCK_HANDLE (fd));
8211 winsock_inuse--; /* count open sockets */
8213 /* If the process handle is NULL, it's either a socket
8214 or serial connection, or a subprocess that was
8215 already reaped by reap_subprocess, but whose
8216 resources were not yet freed, because its output was
8217 not fully read yet by the time it was reaped. (This
8218 usually happens with async subprocesses whose output
8219 is being read by Emacs.) Otherwise, this process was
8220 not reaped yet, so we set its FD to a negative value
8221 to make sure sys_select will eventually get to
8222 calling the SIGCHLD handler for it, which will then
8223 invoke waitpid and reap_subprocess. */
8224 if (cp->procinfo.hProcess == NULL)
8225 delete_child (cp);
8226 else
8227 cp->fd = -1;
8232 if (fd >= 0 && fd < MAXDESC)
8233 fd_info[fd].flags = 0;
8235 /* Note that sockets do not need special treatment here (at least on
8236 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
8237 closesocket is equivalent to CloseHandle, which is to be expected
8238 because socket handles are fully fledged kernel handles. */
8239 rc = _close (fd);
8241 return rc;
8245 sys_dup (int fd)
8247 int new_fd;
8249 new_fd = _dup (fd);
8250 if (new_fd >= 0 && new_fd < MAXDESC)
8252 /* duplicate our internal info as well */
8253 fd_info[new_fd] = fd_info[fd];
8255 return new_fd;
8259 sys_dup2 (int src, int dst)
8261 int rc;
8263 if (dst < 0 || dst >= MAXDESC)
8265 errno = EBADF;
8266 return -1;
8269 /* MS _dup2 seems to have weird side effect when invoked with 2
8270 identical arguments: an attempt to fclose the corresponding stdio
8271 stream after that hangs (we do close standard streams in
8272 init_ntproc). Attempt to avoid that by not calling _dup2 that
8273 way: if SRC is valid, we know that dup2 should be a no-op, so do
8274 nothing and return DST. */
8275 if (src == dst)
8277 if ((HANDLE)_get_osfhandle (src) == INVALID_HANDLE_VALUE)
8279 errno = EBADF;
8280 return -1;
8282 return dst;
8285 /* Make sure we close the destination first if it's a pipe or socket. */
8286 if (fd_info[dst].flags != 0)
8287 sys_close (dst);
8289 rc = _dup2 (src, dst);
8290 if (rc == 0)
8292 /* Duplicate our internal info as well. */
8293 fd_info[dst] = fd_info[src];
8295 return rc == 0 ? dst : rc;
8299 pipe2 (int * phandles, int pipe2_flags)
8301 int rc;
8302 unsigned flags;
8303 unsigned pipe_size = 0;
8305 eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
8307 /* Allow Lisp to override the default buffer size of the pipe. */
8308 if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
8309 pipe_size = w32_pipe_buffer_size;
8311 /* make pipe handles non-inheritable; when we spawn a child, we
8312 replace the relevant handle with an inheritable one. Also put
8313 pipes into binary mode; we will do text mode translation ourselves
8314 if required. */
8315 rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
8317 if (rc == 0)
8319 /* Protect against overflow, since Windows can open more handles than
8320 our fd_info array has room for. */
8321 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
8323 _close (phandles[0]);
8324 _close (phandles[1]);
8325 errno = EMFILE;
8326 rc = -1;
8328 else
8330 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
8331 fd_info[phandles[0]].flags = flags;
8333 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
8334 fd_info[phandles[1]].flags = flags;
8338 return rc;
8341 /* Function to do blocking read of one byte, needed to implement
8342 select. It is only allowed on communication ports, sockets, or
8343 pipes. */
8345 _sys_read_ahead (int fd)
8347 child_process * cp;
8348 int rc;
8350 if (fd < 0 || fd >= MAXDESC)
8351 return STATUS_READ_ERROR;
8353 cp = fd_info[fd].cp;
8355 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8356 return STATUS_READ_ERROR;
8358 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
8359 || (fd_info[fd].flags & FILE_READ) == 0)
8361 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
8362 emacs_abort ();
8365 if ((fd_info[fd].flags & FILE_CONNECT) != 0)
8366 DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd));
8367 cp->status = STATUS_READ_IN_PROGRESS;
8369 if (fd_info[fd].flags & FILE_PIPE)
8371 rc = _read (fd, &cp->chr, sizeof (char));
8373 /* Give subprocess time to buffer some more output for us before
8374 reporting that input is available; we need this because Windows 95
8375 connects DOS programs to pipes by making the pipe appear to be
8376 the normal console stdout - as a result most DOS programs will
8377 write to stdout without buffering, ie. one character at a
8378 time. Even some W32 programs do this - "dir" in a command
8379 shell on NT is very slow if we don't do this. */
8380 if (rc > 0)
8382 int wait = w32_pipe_read_delay;
8384 if (wait > 0)
8385 Sleep (wait);
8386 else if (wait < 0)
8387 while (++wait <= 0)
8388 /* Yield remainder of our time slice, effectively giving a
8389 temporary priority boost to the child process. */
8390 Sleep (0);
8393 else if (fd_info[fd].flags & FILE_SERIAL)
8395 HANDLE hnd = fd_info[fd].hnd;
8396 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8397 COMMTIMEOUTS ct;
8399 /* Configure timeouts for blocking read. */
8400 if (!GetCommTimeouts (hnd, &ct))
8402 cp->status = STATUS_READ_ERROR;
8403 return STATUS_READ_ERROR;
8405 ct.ReadIntervalTimeout = 0;
8406 ct.ReadTotalTimeoutMultiplier = 0;
8407 ct.ReadTotalTimeoutConstant = 0;
8408 if (!SetCommTimeouts (hnd, &ct))
8410 cp->status = STATUS_READ_ERROR;
8411 return STATUS_READ_ERROR;
8414 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
8416 if (GetLastError () != ERROR_IO_PENDING)
8418 cp->status = STATUS_READ_ERROR;
8419 return STATUS_READ_ERROR;
8421 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8423 cp->status = STATUS_READ_ERROR;
8424 return STATUS_READ_ERROR;
8428 else if (fd_info[fd].flags & FILE_SOCKET)
8430 unsigned long nblock = 0;
8431 /* We always want this to block, so temporarily disable NDELAY. */
8432 if (fd_info[fd].flags & FILE_NDELAY)
8433 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8435 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
8437 if (fd_info[fd].flags & FILE_NDELAY)
8439 nblock = 1;
8440 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8444 if (rc == sizeof (char))
8445 cp->status = STATUS_READ_SUCCEEDED;
8446 else
8447 cp->status = STATUS_READ_FAILED;
8449 return cp->status;
8453 _sys_wait_accept (int fd)
8455 HANDLE hEv;
8456 child_process * cp;
8457 int rc;
8459 if (fd < 0 || fd >= MAXDESC)
8460 return STATUS_READ_ERROR;
8462 cp = fd_info[fd].cp;
8464 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8465 return STATUS_READ_ERROR;
8467 cp->status = STATUS_READ_FAILED;
8469 hEv = pfn_WSACreateEvent ();
8470 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
8471 if (rc != SOCKET_ERROR)
8473 do {
8474 rc = WaitForSingleObject (hEv, 500);
8475 Sleep (5);
8476 } while (rc == WAIT_TIMEOUT
8477 && cp->status != STATUS_READ_ERROR
8478 && cp->char_avail);
8479 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8480 if (rc == WAIT_OBJECT_0)
8481 cp->status = STATUS_READ_SUCCEEDED;
8483 pfn_WSACloseEvent (hEv);
8485 return cp->status;
8489 _sys_wait_connect (int fd)
8491 HANDLE hEv;
8492 child_process * cp;
8493 int rc;
8495 if (fd < 0 || fd >= MAXDESC)
8496 return STATUS_READ_ERROR;
8498 cp = fd_info[fd].cp;
8499 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8500 return STATUS_READ_ERROR;
8502 cp->status = STATUS_READ_FAILED;
8504 hEv = pfn_WSACreateEvent ();
8505 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT);
8506 if (rc != SOCKET_ERROR)
8508 do {
8509 rc = WaitForSingleObject (hEv, 500);
8510 Sleep (5);
8511 } while (rc == WAIT_TIMEOUT
8512 && cp->status != STATUS_READ_ERROR
8513 && cp->char_avail);
8514 if (rc == WAIT_OBJECT_0)
8516 /* We've got an event, but it could be a successful
8517 connection, or it could be a failure. Find out
8518 which one is it. */
8519 WSANETWORKEVENTS events;
8521 pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events);
8522 if ((events.lNetworkEvents & FD_CONNECT) != 0
8523 && events.iErrorCode[FD_CONNECT_BIT])
8525 cp->status = STATUS_CONNECT_FAILED;
8526 cp->errcode = events.iErrorCode[FD_CONNECT_BIT];
8528 else
8530 cp->status = STATUS_READ_SUCCEEDED;
8531 cp->errcode = 0;
8534 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8536 else
8537 pfn_WSACloseEvent (hEv);
8539 return cp->status;
8543 sys_read (int fd, char * buffer, unsigned int count)
8545 int nchars;
8546 int to_read;
8547 DWORD waiting;
8548 char * orig_buffer = buffer;
8550 if (fd < 0)
8552 errno = EBADF;
8553 return -1;
8556 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8558 child_process *cp = fd_info[fd].cp;
8560 if ((fd_info[fd].flags & FILE_READ) == 0)
8562 errno = EBADF;
8563 return -1;
8566 nchars = 0;
8568 /* re-read CR carried over from last read */
8569 if (fd_info[fd].flags & FILE_LAST_CR)
8571 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
8572 *buffer++ = 0x0d;
8573 count--;
8574 nchars++;
8575 fd_info[fd].flags &= ~FILE_LAST_CR;
8578 /* presence of a child_process structure means we are operating in
8579 non-blocking mode - otherwise we just call _read directly.
8580 Note that the child_process structure might be missing because
8581 reap_subprocess has been called; in this case the pipe is
8582 already broken, so calling _read on it is okay. */
8583 if (cp)
8585 int current_status = cp->status;
8587 switch (current_status)
8589 case STATUS_READ_FAILED:
8590 case STATUS_READ_ERROR:
8591 /* report normal EOF if nothing in buffer */
8592 if (nchars <= 0)
8593 fd_info[fd].flags |= FILE_AT_EOF;
8594 return nchars;
8596 case STATUS_READ_READY:
8597 case STATUS_READ_IN_PROGRESS:
8598 #if 0
8599 /* This happens all the time during GnuTLS handshake
8600 with the remote, evidently because GnuTLS waits for
8601 the read to complete by retrying the read operation
8602 upon EAGAIN. So I'm disabling the DebPrint to avoid
8603 wasting cycles on something that is not a real
8604 problem. Enable if you need to debug something that
8605 bumps into this. */
8606 DebPrint (("sys_read called when read is in progress %d\n",
8607 current_status));
8608 #endif
8609 errno = EWOULDBLOCK;
8610 return -1;
8612 case STATUS_READ_SUCCEEDED:
8613 /* consume read-ahead char */
8614 *buffer++ = cp->chr;
8615 count--;
8616 nchars++;
8617 cp->status = STATUS_READ_ACKNOWLEDGED;
8618 ResetEvent (cp->char_avail);
8620 case STATUS_READ_ACKNOWLEDGED:
8621 case STATUS_CONNECT_FAILED:
8622 break;
8624 default:
8625 DebPrint (("sys_read: bad status %d\n", current_status));
8626 errno = EBADF;
8627 return -1;
8630 if (fd_info[fd].flags & FILE_PIPE)
8632 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
8633 to_read = min (waiting, (DWORD) count);
8635 if (to_read > 0)
8636 nchars += _read (fd, buffer, to_read);
8638 else if (fd_info[fd].flags & FILE_SERIAL)
8640 HANDLE hnd = fd_info[fd].hnd;
8641 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8642 int rc = 0;
8643 COMMTIMEOUTS ct;
8645 if (count > 0)
8647 /* Configure timeouts for non-blocking read. */
8648 if (!GetCommTimeouts (hnd, &ct))
8650 errno = EIO;
8651 return -1;
8653 ct.ReadIntervalTimeout = MAXDWORD;
8654 ct.ReadTotalTimeoutMultiplier = 0;
8655 ct.ReadTotalTimeoutConstant = 0;
8656 if (!SetCommTimeouts (hnd, &ct))
8658 errno = EIO;
8659 return -1;
8662 if (!ResetEvent (ovl->hEvent))
8664 errno = EIO;
8665 return -1;
8667 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8669 if (GetLastError () != ERROR_IO_PENDING)
8671 errno = EIO;
8672 return -1;
8674 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8676 errno = EIO;
8677 return -1;
8680 nchars += rc;
8683 else /* FILE_SOCKET */
8685 if (winsock_lib == NULL) emacs_abort ();
8687 /* When a non-blocking 'connect' call fails,
8688 wait_reading_process_output detects this by calling
8689 'getpeername', and then attempts to obtain the connection
8690 error code by trying to read 1 byte from the socket. If
8691 we try to serve that read by calling 'recv' below, the
8692 error we get is a generic WSAENOTCONN, not the actual
8693 connection error. So instead, we use the actual error
8694 code stashed by '_sys_wait_connect' in cp->errcode.
8695 Alternatively, we could have used 'getsockopt', like on
8696 GNU/Linux, but: (a) I have no idea whether the winsock
8697 version could hang, as it does "on some systems" (see the
8698 comment in process.c); and (b) 'getsockopt' on Windows is
8699 documented to clear the socket error for the entire
8700 process, which I'm not sure is TRT; FIXME. */
8701 if (current_status == STATUS_CONNECT_FAILED
8702 && (fd_info[fd].flags & FILE_CONNECT) != 0
8703 && cp->errcode != 0)
8705 pfn_WSASetLastError (cp->errcode);
8706 set_errno ();
8707 return -1;
8709 /* Do the equivalent of a non-blocking read. */
8710 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8711 if (waiting == 0 && nchars == 0)
8713 errno = EWOULDBLOCK;
8714 return -1;
8717 if (waiting)
8719 /* always use binary mode for sockets */
8720 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8721 if (res == SOCKET_ERROR)
8723 set_errno ();
8724 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8725 errno, SOCK_HANDLE (fd)));
8726 return -1;
8728 nchars += res;
8732 else
8734 int nread = _read (fd, buffer, count);
8735 if (nread >= 0)
8736 nchars += nread;
8737 else if (nchars == 0)
8738 nchars = nread;
8741 if (nchars <= 0)
8742 fd_info[fd].flags |= FILE_AT_EOF;
8743 /* Perform text mode translation if required. */
8744 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8746 nchars = crlf_to_lf (nchars, orig_buffer);
8747 /* If buffer contains only CR, return that. To be absolutely
8748 sure we should attempt to read the next char, but in
8749 practice a CR to be followed by LF would not appear by
8750 itself in the buffer. */
8751 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8753 fd_info[fd].flags |= FILE_LAST_CR;
8754 nchars--;
8758 else
8759 nchars = _read (fd, buffer, count);
8761 return nchars;
8764 /* From w32xfns.c */
8765 extern HANDLE interrupt_handle;
8768 sys_write (int fd, const void * buffer, unsigned int count)
8770 int nchars;
8771 USE_SAFE_ALLOCA;
8773 if (fd < 0)
8775 errno = EBADF;
8776 return -1;
8779 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8781 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8783 errno = EBADF;
8784 return -1;
8787 /* Perform text mode translation if required. */
8788 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8790 char * tmpbuf;
8791 const unsigned char * src = buffer;
8792 unsigned char * dst;
8793 int nbytes = count;
8795 SAFE_NALLOCA (tmpbuf, 2, count);
8796 dst = (unsigned char *)tmpbuf;
8798 while (1)
8800 unsigned char *next;
8801 /* Copy next line or remaining bytes. */
8802 next = _memccpy (dst, src, '\n', nbytes);
8803 if (next)
8805 /* Copied one line ending with '\n'. */
8806 int copied = next - dst;
8807 nbytes -= copied;
8808 src += copied;
8809 /* Insert '\r' before '\n'. */
8810 next[-1] = '\r';
8811 next[0] = '\n';
8812 dst = next + 1;
8813 count++;
8815 else
8816 /* Copied remaining partial line -> now finished. */
8817 break;
8819 buffer = tmpbuf;
8823 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8825 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8826 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8827 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8828 DWORD active = 0;
8830 /* This is async (a.k.a. "overlapped") I/O, so the return value
8831 of FALSE from WriteFile means either an error or the output
8832 will be completed asynchronously (ERROR_IO_PENDING). */
8833 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8835 if (GetLastError () != ERROR_IO_PENDING)
8837 errno = EIO;
8838 nchars = -1;
8840 else
8842 /* Wait for the write to complete, and watch C-g while
8843 at that. */
8844 if (detect_input_pending ())
8845 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
8846 INFINITE, QS_ALLINPUT);
8847 else
8848 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8849 switch (active)
8851 case WAIT_OBJECT_0:
8852 /* User pressed C-g, cancel write, then leave.
8853 Don't bother cleaning up as we may only get stuck
8854 in buggy drivers. */
8855 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8856 CancelIo (hnd);
8857 errno = EIO; /* Why not EINTR? */
8858 nchars = -1;
8859 break;
8860 case WAIT_OBJECT_0 + 1:
8861 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8863 errno = EIO;
8864 nchars = -1;
8866 break;
8871 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8873 unsigned long nblock = 0;
8874 if (winsock_lib == NULL) emacs_abort ();
8876 child_process *cp = fd_info[fd].cp;
8878 /* If this is a non-blocking socket whose connection is in
8879 progress or terminated with an error already, return the
8880 proper error code to the caller. */
8881 if (cp != NULL && (fd_info[fd].flags & FILE_CONNECT) != 0)
8883 /* In case connection is in progress, ENOTCONN that would
8884 result from calling pfn_send is not what callers expect. */
8885 if (cp->status != STATUS_CONNECT_FAILED)
8887 errno = EWOULDBLOCK;
8888 return -1;
8890 /* In case connection failed, use the actual error code
8891 stashed by '_sys_wait_connect' in cp->errcode. */
8892 else if (cp->errcode != 0)
8894 pfn_WSASetLastError (cp->errcode);
8895 set_errno ();
8896 return -1;
8900 /* TODO: implement select() properly so non-blocking I/O works. */
8901 /* For now, make sure the write blocks. */
8902 if (fd_info[fd].flags & FILE_NDELAY)
8903 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8905 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
8907 if (nchars == SOCKET_ERROR)
8909 set_errno ();
8910 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
8911 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8914 /* Set the socket back to non-blocking if it was before,
8915 for other operations that support it. */
8916 if (fd_info[fd].flags & FILE_NDELAY)
8918 nblock = 1;
8919 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8922 else
8924 /* Some networked filesystems don't like too large writes, so
8925 break them into smaller chunks. See the Comments section of
8926 the MSDN documentation of WriteFile for details behind the
8927 choice of the value of CHUNK below. See also the thread
8928 http://thread.gmane.org/gmane.comp.version-control.git/145294
8929 in the git mailing list. */
8930 const unsigned char *p = buffer;
8931 const bool is_pipe = (fd < MAXDESC
8932 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
8933 == (FILE_PIPE | FILE_NDELAY)));
8934 /* Some programs, notably Node.js's node.exe, seem to never
8935 completely empty the pipe, so writing more than the size of
8936 the pipe's buffer always returns ENOSPC, and we loop forever
8937 between send_process and here. As a workaround, write no
8938 more than the pipe's buffer can hold. */
8939 DWORD pipe_buffer_size;
8940 if (is_pipe)
8942 if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
8943 NULL, &pipe_buffer_size, NULL, NULL))
8945 DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
8946 pipe_buffer_size = 4096;
8949 const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
8951 nchars = 0;
8952 errno = 0;
8953 while (count > 0)
8955 unsigned this_chunk = count < chunk ? count : chunk;
8956 int n = _write (fd, p, this_chunk);
8958 if (n > 0)
8959 nchars += n;
8960 if (n < 0)
8962 /* When there's no buffer space in a pipe that is in the
8963 non-blocking mode, _write returns ENOSPC. We return
8964 EAGAIN instead, which should trigger the logic in
8965 send_process that enters waiting loop and calls
8966 wait_reading_process_output to allow process input to
8967 be accepted during the wait. Those calls to
8968 wait_reading_process_output allow sys_select to
8969 notice when process input becomes available, thus
8970 avoiding deadlock whereby each side of the pipe is
8971 blocked on write, waiting for the other party to read
8972 its end of the pipe. */
8973 if (errno == ENOSPC && is_pipe)
8974 errno = EAGAIN;
8975 if (nchars == 0)
8976 nchars = -1;
8977 break;
8979 else if (n < this_chunk)
8980 break;
8981 count -= n;
8982 p += n;
8986 SAFE_FREE ();
8987 return nchars;
8991 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
8993 /* Return information about network interface IFNAME, or about all
8994 interfaces (if IFNAME is nil). */
8995 static Lisp_Object
8996 network_interface_get_info (Lisp_Object ifname)
8998 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
8999 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
9000 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
9001 Lisp_Object res = Qnil;
9003 if (retval == ERROR_BUFFER_OVERFLOW)
9005 ainfo = xrealloc (ainfo, ainfo_len);
9006 retval = get_adapters_info (ainfo, &ainfo_len);
9009 if (retval == ERROR_SUCCESS)
9011 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
9012 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
9013 int if_num;
9014 struct sockaddr_in sa;
9016 /* For the below, we need some winsock functions, so make sure
9017 the winsock DLL is loaded. If we cannot successfully load
9018 it, they will have no use of the information we provide,
9019 anyway, so punt. */
9020 if (!winsock_lib && !init_winsock (1))
9021 goto done;
9023 for (adapter = ainfo; adapter; adapter = adapter->Next)
9025 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
9026 u_long ip_addr;
9027 /* Present Unix-compatible interface names, instead of the
9028 Windows names, which are really GUIDs not readable by
9029 humans. */
9030 static const char *ifmt[] = {
9031 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
9032 "lo", "ifx%d"
9034 enum {
9035 NONE = -1,
9036 ETHERNET = 0,
9037 TOKENRING = 1,
9038 FDDI = 2,
9039 PPP = 3,
9040 SLIP = 4,
9041 WLAN = 5,
9042 LOOPBACK = 6,
9043 OTHER_IF = 7
9044 } ifmt_idx;
9046 switch (adapter->Type)
9048 case MIB_IF_TYPE_ETHERNET:
9049 /* Windows before Vista reports wireless adapters as
9050 Ethernet. Work around by looking at the Description
9051 string. */
9052 if (strstr (adapter->Description, "Wireless "))
9054 ifmt_idx = WLAN;
9055 if_num = wlan_count++;
9057 else
9059 ifmt_idx = ETHERNET;
9060 if_num = eth_count++;
9062 break;
9063 case MIB_IF_TYPE_TOKENRING:
9064 ifmt_idx = TOKENRING;
9065 if_num = tr_count++;
9066 break;
9067 case MIB_IF_TYPE_FDDI:
9068 ifmt_idx = FDDI;
9069 if_num = fddi_count++;
9070 break;
9071 case MIB_IF_TYPE_PPP:
9072 ifmt_idx = PPP;
9073 if_num = ppp_count++;
9074 break;
9075 case MIB_IF_TYPE_SLIP:
9076 ifmt_idx = SLIP;
9077 if_num = sl_count++;
9078 break;
9079 case IF_TYPE_IEEE80211:
9080 ifmt_idx = WLAN;
9081 if_num = wlan_count++;
9082 break;
9083 case MIB_IF_TYPE_LOOPBACK:
9084 if (lo_count < 0)
9086 ifmt_idx = LOOPBACK;
9087 if_num = lo_count++;
9089 else
9090 ifmt_idx = NONE;
9091 break;
9092 default:
9093 ifmt_idx = OTHER_IF;
9094 if_num = ifx_count++;
9095 break;
9097 if (ifmt_idx == NONE)
9098 continue;
9099 sprintf (namebuf, ifmt[ifmt_idx], if_num);
9101 sa.sin_family = AF_INET;
9102 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
9103 if (ip_addr == INADDR_NONE)
9105 /* Bogus address, skip this interface. */
9106 continue;
9108 sa.sin_addr.s_addr = ip_addr;
9109 sa.sin_port = 0;
9110 if (NILP (ifname))
9111 res = Fcons (Fcons (build_string (namebuf),
9112 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9113 sizeof (struct sockaddr))),
9114 res);
9115 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
9117 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
9118 register struct Lisp_Vector *p = XVECTOR (hwaddr);
9119 Lisp_Object flags = Qnil;
9120 int n;
9121 u_long net_mask;
9123 /* Flags. We guess most of them by type, since the
9124 Windows flags are different and hard to get by. */
9125 flags = Fcons (intern ("up"), flags);
9126 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
9128 flags = Fcons (intern ("broadcast"), flags);
9129 flags = Fcons (intern ("multicast"), flags);
9131 flags = Fcons (intern ("running"), flags);
9132 if (ifmt_idx == PPP)
9134 flags = Fcons (intern ("pointopoint"), flags);
9135 flags = Fcons (intern ("noarp"), flags);
9137 if (adapter->HaveWins)
9138 flags = Fcons (intern ("WINS"), flags);
9139 if (adapter->DhcpEnabled)
9140 flags = Fcons (intern ("dynamic"), flags);
9142 res = Fcons (flags, res);
9144 /* Hardware address and its family. */
9145 for (n = 0; n < adapter->AddressLength; n++)
9146 p->contents[n] = make_number ((int) adapter->Address[n]);
9147 /* Windows does not support AF_LINK or AF_PACKET family
9148 of addresses. Use an arbitrary family number that is
9149 identical to what GNU/Linux returns. */
9150 res = Fcons (Fcons (make_number (1), hwaddr), res);
9152 /* Network mask. */
9153 sa.sin_family = AF_INET;
9154 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
9155 if (net_mask != INADDR_NONE)
9157 sa.sin_addr.s_addr = net_mask;
9158 sa.sin_port = 0;
9159 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9160 sizeof (struct sockaddr)),
9161 res);
9163 else
9164 res = Fcons (Qnil, res);
9166 sa.sin_family = AF_INET;
9167 if (ip_addr != INADDR_NONE)
9169 /* Broadcast address is only reported by
9170 GetAdaptersAddresses, which is of limited
9171 availability. Generate it on our own. */
9172 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
9174 sa.sin_addr.s_addr = bcast_addr;
9175 sa.sin_port = 0;
9176 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9177 sizeof (struct sockaddr)),
9178 res);
9180 /* IP address. */
9181 sa.sin_addr.s_addr = ip_addr;
9182 sa.sin_port = 0;
9183 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9184 sizeof (struct sockaddr)),
9185 res);
9187 else
9188 res = Fcons (Qnil, Fcons (Qnil, res));
9191 /* GetAdaptersInfo is documented to not report loopback
9192 interfaces, so we generate one out of thin air. */
9193 if (!lo_count)
9195 sa.sin_family = AF_INET;
9196 sa.sin_port = 0;
9197 if (NILP (ifname))
9199 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9200 res = Fcons (Fcons (build_string ("lo"),
9201 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9202 sizeof (struct sockaddr))),
9203 res);
9205 else if (strcmp (SSDATA (ifname), "lo") == 0)
9207 res = Fcons (Fcons (intern ("running"),
9208 Fcons (intern ("loopback"),
9209 Fcons (intern ("up"), Qnil))), Qnil);
9210 /* 772 is what 3 different GNU/Linux systems report for
9211 the loopback interface. */
9212 res = Fcons (Fcons (make_number (772),
9213 Fmake_vector (make_number (6),
9214 make_number (0))),
9215 res);
9216 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
9217 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9218 sizeof (struct sockaddr)),
9219 res);
9220 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
9221 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9222 sizeof (struct sockaddr)),
9223 res);
9224 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9225 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9226 sizeof (struct sockaddr)),
9227 res);
9233 done:
9234 xfree (ainfo);
9235 return res;
9238 Lisp_Object
9239 network_interface_list (void)
9241 return network_interface_get_info (Qnil);
9244 Lisp_Object
9245 network_interface_info (Lisp_Object ifname)
9247 CHECK_STRING (ifname);
9248 return network_interface_get_info (ifname);
9252 /* The Windows CRT functions are "optimized for speed", so they don't
9253 check for timezone and DST changes if they were last called less
9254 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
9255 all Emacs features that repeatedly call time functions (e.g.,
9256 display-time) are in real danger of missing timezone and DST
9257 changes. Calling tzset before each localtime call fixes that. */
9258 struct tm *
9259 sys_localtime (const time_t *t)
9261 tzset ();
9262 return localtime (t);
9267 /* Try loading LIBRARY_ID from the file(s) specified in
9268 Vdynamic_library_alist. If the library is loaded successfully,
9269 return the handle of the DLL, and record the filename in the
9270 property :loaded-from of LIBRARY_ID. If the library could not be
9271 found, or when it was already loaded (because the handle is not
9272 recorded anywhere, and so is lost after use), return NULL.
9274 We could also save the handle in :loaded-from, but currently
9275 there's no use case for it. */
9276 HMODULE
9277 w32_delayed_load (Lisp_Object library_id)
9279 HMODULE dll_handle = NULL;
9281 CHECK_SYMBOL (library_id);
9283 if (CONSP (Vdynamic_library_alist)
9284 && NILP (Fassq (library_id, Vlibrary_cache)))
9286 Lisp_Object found = Qnil;
9287 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
9289 if (CONSP (dlls))
9290 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
9292 Lisp_Object dll = XCAR (dlls);
9293 char name[MAX_UTF8_PATH];
9294 DWORD res = -1;
9296 CHECK_STRING (dll);
9297 dll = ENCODE_FILE (dll);
9298 if (w32_unicode_filenames)
9300 wchar_t name_w[MAX_PATH];
9302 filename_to_utf16 (SSDATA (dll), name_w);
9303 dll_handle = LoadLibraryW (name_w);
9304 if (dll_handle)
9306 res = GetModuleFileNameW (dll_handle, name_w,
9307 sizeof (name_w));
9308 if (res > 0)
9309 filename_from_utf16 (name_w, name);
9312 else
9314 char name_a[MAX_PATH];
9316 filename_to_ansi (SSDATA (dll), name_a);
9317 dll_handle = LoadLibraryA (name_a);
9318 if (dll_handle)
9320 res = GetModuleFileNameA (dll_handle, name_a,
9321 sizeof (name_a));
9322 if (res > 0)
9323 filename_from_ansi (name_a, name);
9326 if (dll_handle)
9328 ptrdiff_t len = strlen (name);
9329 found = Fcons (dll,
9330 (res > 0)
9331 /* Possibly truncated */
9332 ? make_specified_string (name, -1, len, 1)
9333 : Qnil);
9334 /* This prevents thread start and end notifications
9335 from being sent to the DLL, for every thread we
9336 start. We don't need those notifications because
9337 threads we create never use any of these DLLs, only
9338 the main thread uses them. This is supposed to
9339 speed up thread creation. */
9340 DisableThreadLibraryCalls (dll_handle);
9341 break;
9345 Fput (library_id, QCloaded_from, found);
9348 return dll_handle;
9352 void
9353 check_windows_init_file (void)
9355 /* A common indication that Emacs is not installed properly is when
9356 it cannot find the Windows installation file. If this file does
9357 not exist in the expected place, tell the user. */
9359 if (!noninteractive && !inhibit_window_system
9360 /* Vload_path is not yet initialized when we are loading
9361 loadup.el. */
9362 && NILP (Vpurify_flag))
9364 Lisp_Object init_file;
9365 int fd;
9367 /* Implementation note: this function runs early during Emacs
9368 startup, before startup.el is run. So Vload_path is still in
9369 its initial unibyte form, but it holds UTF-8 encoded file
9370 names, since init_callproc was already called. So we do not
9371 need to ENCODE_FILE here, but we do need to convert the file
9372 names from UTF-8 to ANSI. */
9373 init_file = build_string ("term/w32-win");
9374 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
9375 if (fd < 0)
9377 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
9378 char *init_file_name = SSDATA (init_file);
9379 char *load_path = SSDATA (load_path_print);
9380 char *buffer = alloca (1024
9381 + strlen (init_file_name)
9382 + strlen (load_path));
9383 char *msg = buffer;
9384 int needed;
9386 sprintf (buffer,
9387 "The Emacs Windows initialization file \"%s.el\" "
9388 "could not be found in your Emacs installation. "
9389 "Emacs checked the following directories for this file:\n"
9390 "\n%s\n\n"
9391 "When Emacs cannot find this file, it usually means that it "
9392 "was not installed properly, or its distribution file was "
9393 "not unpacked properly.\nSee the README.W32 file in the "
9394 "top-level Emacs directory for more information.",
9395 init_file_name, load_path);
9396 needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
9397 buffer, -1, NULL, 0);
9398 if (needed > 0)
9400 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
9402 pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
9403 -1, msg_w, needed);
9404 needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
9405 NULL, 0, NULL, NULL);
9406 if (needed > 0)
9408 char *msg_a = alloca (needed + 1);
9410 pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
9411 NULL, NULL);
9412 msg = msg_a;
9415 MessageBox (NULL,
9416 msg,
9417 "Emacs Abort Dialog",
9418 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
9419 /* Use the low-level system abort. */
9420 abort ();
9422 else
9424 _close (fd);
9429 void
9430 term_ntproc (int ignored)
9432 (void)ignored;
9434 term_timers ();
9436 /* shutdown the socket interface if necessary */
9437 term_winsock ();
9439 term_w32select ();
9442 void
9443 init_ntproc (int dumping)
9445 sigset_t initial_mask = 0;
9447 /* Initialize the socket interface now if available and requested by
9448 the user by defining PRELOAD_WINSOCK; otherwise loading will be
9449 delayed until open-network-stream is called (w32-has-winsock can
9450 also be used to dynamically load or reload winsock).
9452 Conveniently, init_environment is called before us, so
9453 PRELOAD_WINSOCK can be set in the registry. */
9455 /* Always initialize this correctly. */
9456 winsock_lib = NULL;
9458 if (getenv ("PRELOAD_WINSOCK") != NULL)
9459 init_winsock (TRUE);
9461 /* Initial preparation for subprocess support: replace our standard
9462 handles with non-inheritable versions. */
9464 HANDLE parent;
9465 HANDLE stdin_save = INVALID_HANDLE_VALUE;
9466 HANDLE stdout_save = INVALID_HANDLE_VALUE;
9467 HANDLE stderr_save = INVALID_HANDLE_VALUE;
9469 parent = GetCurrentProcess ();
9471 /* ignore errors when duplicating and closing; typically the
9472 handles will be invalid when running as a gui program. */
9473 DuplicateHandle (parent,
9474 GetStdHandle (STD_INPUT_HANDLE),
9475 parent,
9476 &stdin_save,
9478 FALSE,
9479 DUPLICATE_SAME_ACCESS);
9481 DuplicateHandle (parent,
9482 GetStdHandle (STD_OUTPUT_HANDLE),
9483 parent,
9484 &stdout_save,
9486 FALSE,
9487 DUPLICATE_SAME_ACCESS);
9489 DuplicateHandle (parent,
9490 GetStdHandle (STD_ERROR_HANDLE),
9491 parent,
9492 &stderr_save,
9494 FALSE,
9495 DUPLICATE_SAME_ACCESS);
9497 fclose (stdin);
9498 fclose (stdout);
9499 fclose (stderr);
9501 if (stdin_save != INVALID_HANDLE_VALUE)
9502 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
9503 else
9504 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
9505 _fdopen (0, "r");
9507 if (stdout_save != INVALID_HANDLE_VALUE)
9508 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
9509 else
9510 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9511 _fdopen (1, "w");
9513 if (stderr_save != INVALID_HANDLE_VALUE)
9514 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
9515 else
9516 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9517 _fdopen (2, "w");
9520 /* unfortunately, atexit depends on implementation of malloc */
9521 /* atexit (term_ntproc); */
9522 if (!dumping)
9524 /* Make sure we start with all signals unblocked. */
9525 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
9526 signal (SIGABRT, term_ntproc);
9528 init_timers ();
9530 /* determine which drives are fixed, for GetCachedVolumeInformation */
9532 /* GetDriveType must have trailing backslash. */
9533 char drive[] = "A:\\";
9535 /* Loop over all possible drive letters */
9536 while (*drive <= 'Z')
9538 /* Record if this drive letter refers to a fixed drive. */
9539 fixed_drives[DRIVE_INDEX (*drive)] =
9540 (GetDriveType (drive) == DRIVE_FIXED);
9542 (*drive)++;
9545 /* Reset the volume info cache. */
9546 volume_cache = NULL;
9551 shutdown_handler ensures that buffers' autosave files are
9552 up to date when the user logs off, or the system shuts down.
9554 static BOOL WINAPI
9555 shutdown_handler (DWORD type)
9557 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
9558 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
9559 || type == CTRL_LOGOFF_EVENT /* User logs off. */
9560 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
9562 /* Shut down cleanly, making sure autosave files are up to date. */
9563 shut_down_emacs (0, Qnil);
9566 /* Allow other handlers to handle this signal. */
9567 return FALSE;
9570 /* On Windows 9X, load UNICOWS.DLL and return its handle, or die. On
9571 NT, return a handle to GDI32.DLL. */
9572 HANDLE
9573 maybe_load_unicows_dll (void)
9575 if (os_subtype == OS_9X)
9577 HANDLE ret = LoadLibrary ("Unicows.dll");
9578 if (ret)
9580 /* These two functions are present on Windows 9X as stubs
9581 that always fail. We need the real implementations from
9582 UNICOWS.DLL, so we must call these functions through
9583 pointers, and assign the correct addresses to these
9584 pointers at program startup (see emacs.c, which calls
9585 this function early on). */
9586 pMultiByteToWideChar =
9587 (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
9588 pWideCharToMultiByte =
9589 (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
9590 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9591 return ret;
9593 else
9595 int button;
9597 button = MessageBox (NULL,
9598 "Emacs cannot load the UNICOWS.DLL library.\n"
9599 "This library is essential for using Emacs\n"
9600 "on this system. You need to install it.\n\n"
9601 "Emacs will exit when you click OK.",
9602 "Emacs cannot load UNICOWS.DLL",
9603 MB_ICONERROR | MB_TASKMODAL
9604 | MB_SETFOREGROUND | MB_OK);
9605 switch (button)
9607 case IDOK:
9608 default:
9609 exit (1);
9613 else
9615 /* On NT family of Windows, these two functions are always
9616 linked in, so we just assign their addresses to the 2
9617 pointers; no need for the LoadLibrary dance. */
9618 pMultiByteToWideChar = MultiByteToWideChar;
9619 pWideCharToMultiByte = WideCharToMultiByte;
9620 /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported. */
9621 if (w32_major_version < 5)
9622 multiByteToWideCharFlags = 0;
9623 else
9624 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9625 return LoadLibrary ("Gdi32.dll");
9630 globals_of_w32 is used to initialize those global variables that
9631 must always be initialized on startup even when the global variable
9632 initialized is non zero (see the function main in emacs.c).
9634 void
9635 globals_of_w32 (void)
9637 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
9639 get_process_times_fn = (GetProcessTimes_Proc)
9640 GetProcAddress (kernel32, "GetProcessTimes");
9642 DEFSYM (QCloaded_from, ":loaded-from");
9644 g_b_init_is_windows_9x = 0;
9645 g_b_init_open_process_token = 0;
9646 g_b_init_get_token_information = 0;
9647 g_b_init_lookup_account_sid = 0;
9648 g_b_init_get_sid_sub_authority = 0;
9649 g_b_init_get_sid_sub_authority_count = 0;
9650 g_b_init_get_security_info = 0;
9651 g_b_init_get_file_security_w = 0;
9652 g_b_init_get_file_security_a = 0;
9653 g_b_init_get_security_descriptor_owner = 0;
9654 g_b_init_get_security_descriptor_group = 0;
9655 g_b_init_is_valid_sid = 0;
9656 g_b_init_create_toolhelp32_snapshot = 0;
9657 g_b_init_process32_first = 0;
9658 g_b_init_process32_next = 0;
9659 g_b_init_open_thread_token = 0;
9660 g_b_init_impersonate_self = 0;
9661 g_b_init_revert_to_self = 0;
9662 g_b_init_get_process_memory_info = 0;
9663 g_b_init_get_process_working_set_size = 0;
9664 g_b_init_global_memory_status = 0;
9665 g_b_init_global_memory_status_ex = 0;
9666 g_b_init_equal_sid = 0;
9667 g_b_init_copy_sid = 0;
9668 g_b_init_get_length_sid = 0;
9669 g_b_init_get_native_system_info = 0;
9670 g_b_init_get_system_times = 0;
9671 g_b_init_create_symbolic_link_w = 0;
9672 g_b_init_create_symbolic_link_a = 0;
9673 g_b_init_get_security_descriptor_dacl = 0;
9674 g_b_init_convert_sd_to_sddl = 0;
9675 g_b_init_convert_sddl_to_sd = 0;
9676 g_b_init_is_valid_security_descriptor = 0;
9677 g_b_init_set_file_security_w = 0;
9678 g_b_init_set_file_security_a = 0;
9679 g_b_init_set_named_security_info_w = 0;
9680 g_b_init_set_named_security_info_a = 0;
9681 g_b_init_get_adapters_info = 0;
9682 g_b_init_compare_string_w = 0;
9683 g_b_init_debug_break_process = 0;
9684 num_of_processors = 0;
9685 /* The following sets a handler for shutdown notifications for
9686 console apps. This actually applies to Emacs in both console and
9687 GUI modes, since we had to fool windows into thinking emacs is a
9688 console application to get console mode to work. */
9689 SetConsoleCtrlHandler (shutdown_handler, TRUE);
9691 /* "None" is the default group name on standalone workstations. */
9692 strcpy (dflt_group_name, "None");
9694 /* Reset, in case it has some value inherited from dump time. */
9695 w32_stat_get_owner_group = 0;
9697 /* If w32_unicode_filenames is non-zero, we will be using Unicode
9698 (a.k.a. "wide") APIs to invoke functions that accept file
9699 names. */
9700 if (is_windows_9x ())
9701 w32_unicode_filenames = 0;
9702 else
9703 w32_unicode_filenames = 1;
9705 #ifdef HAVE_MODULES
9706 dynlib_reset_last_error ();
9707 #endif
9709 w32_crypto_hprov = (HCRYPTPROV)0;
9712 /* For make-serial-process */
9714 serial_open (Lisp_Object port_obj)
9716 char *port = SSDATA (port_obj);
9717 HANDLE hnd;
9718 child_process *cp;
9719 int fd = -1;
9721 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
9722 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
9723 if (hnd == INVALID_HANDLE_VALUE)
9724 error ("Could not open %s", port);
9725 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
9726 if (fd == -1)
9727 error ("Could not open %s", port);
9729 cp = new_child ();
9730 if (!cp)
9731 error ("Could not create child process");
9732 cp->fd = fd;
9733 cp->status = STATUS_READ_ACKNOWLEDGED;
9734 fd_info[ fd ].hnd = hnd;
9735 fd_info[ fd ].flags |=
9736 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
9737 if (fd_info[ fd ].cp != NULL)
9739 error ("fd_info[fd = %d] is already in use", fd);
9741 fd_info[ fd ].cp = cp;
9742 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9743 if (cp->ovl_read.hEvent == NULL)
9744 error ("Could not create read event");
9745 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9746 if (cp->ovl_write.hEvent == NULL)
9747 error ("Could not create write event");
9749 return fd;
9752 /* For serial-process-configure */
9753 void
9754 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
9756 Lisp_Object childp2 = Qnil;
9757 Lisp_Object tem = Qnil;
9758 HANDLE hnd;
9759 DCB dcb;
9760 COMMTIMEOUTS ct;
9761 char summary[4] = "???"; /* This usually becomes "8N1". */
9763 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
9764 error ("Not a serial process");
9765 hnd = fd_info[ p->outfd ].hnd;
9767 childp2 = Fcopy_sequence (p->childp);
9769 /* Initialize timeouts for blocking read and blocking write. */
9770 if (!GetCommTimeouts (hnd, &ct))
9771 error ("GetCommTimeouts() failed");
9772 ct.ReadIntervalTimeout = 0;
9773 ct.ReadTotalTimeoutMultiplier = 0;
9774 ct.ReadTotalTimeoutConstant = 0;
9775 ct.WriteTotalTimeoutMultiplier = 0;
9776 ct.WriteTotalTimeoutConstant = 0;
9777 if (!SetCommTimeouts (hnd, &ct))
9778 error ("SetCommTimeouts() failed");
9779 /* Read port attributes and prepare default configuration. */
9780 memset (&dcb, 0, sizeof (dcb));
9781 dcb.DCBlength = sizeof (DCB);
9782 if (!GetCommState (hnd, &dcb))
9783 error ("GetCommState() failed");
9784 dcb.fBinary = TRUE;
9785 dcb.fNull = FALSE;
9786 dcb.fAbortOnError = FALSE;
9787 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
9788 dcb.ErrorChar = 0;
9789 dcb.EofChar = 0;
9790 dcb.EvtChar = 0;
9792 /* Configure speed. */
9793 if (!NILP (Fplist_member (contact, QCspeed)))
9794 tem = Fplist_get (contact, QCspeed);
9795 else
9796 tem = Fplist_get (p->childp, QCspeed);
9797 CHECK_NUMBER (tem);
9798 dcb.BaudRate = XINT (tem);
9799 childp2 = Fplist_put (childp2, QCspeed, tem);
9801 /* Configure bytesize. */
9802 if (!NILP (Fplist_member (contact, QCbytesize)))
9803 tem = Fplist_get (contact, QCbytesize);
9804 else
9805 tem = Fplist_get (p->childp, QCbytesize);
9806 if (NILP (tem))
9807 tem = make_number (8);
9808 CHECK_NUMBER (tem);
9809 if (XINT (tem) != 7 && XINT (tem) != 8)
9810 error (":bytesize must be nil (8), 7, or 8");
9811 dcb.ByteSize = XINT (tem);
9812 summary[0] = XINT (tem) + '0';
9813 childp2 = Fplist_put (childp2, QCbytesize, tem);
9815 /* Configure parity. */
9816 if (!NILP (Fplist_member (contact, QCparity)))
9817 tem = Fplist_get (contact, QCparity);
9818 else
9819 tem = Fplist_get (p->childp, QCparity);
9820 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
9821 error (":parity must be nil (no parity), `even', or `odd'");
9822 dcb.fParity = FALSE;
9823 dcb.Parity = NOPARITY;
9824 dcb.fErrorChar = FALSE;
9825 if (NILP (tem))
9827 summary[1] = 'N';
9829 else if (EQ (tem, Qeven))
9831 summary[1] = 'E';
9832 dcb.fParity = TRUE;
9833 dcb.Parity = EVENPARITY;
9834 dcb.fErrorChar = TRUE;
9836 else if (EQ (tem, Qodd))
9838 summary[1] = 'O';
9839 dcb.fParity = TRUE;
9840 dcb.Parity = ODDPARITY;
9841 dcb.fErrorChar = TRUE;
9843 childp2 = Fplist_put (childp2, QCparity, tem);
9845 /* Configure stopbits. */
9846 if (!NILP (Fplist_member (contact, QCstopbits)))
9847 tem = Fplist_get (contact, QCstopbits);
9848 else
9849 tem = Fplist_get (p->childp, QCstopbits);
9850 if (NILP (tem))
9851 tem = make_number (1);
9852 CHECK_NUMBER (tem);
9853 if (XINT (tem) != 1 && XINT (tem) != 2)
9854 error (":stopbits must be nil (1 stopbit), 1, or 2");
9855 summary[2] = XINT (tem) + '0';
9856 if (XINT (tem) == 1)
9857 dcb.StopBits = ONESTOPBIT;
9858 else if (XINT (tem) == 2)
9859 dcb.StopBits = TWOSTOPBITS;
9860 childp2 = Fplist_put (childp2, QCstopbits, tem);
9862 /* Configure flowcontrol. */
9863 if (!NILP (Fplist_member (contact, QCflowcontrol)))
9864 tem = Fplist_get (contact, QCflowcontrol);
9865 else
9866 tem = Fplist_get (p->childp, QCflowcontrol);
9867 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
9868 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
9869 dcb.fOutxCtsFlow = FALSE;
9870 dcb.fOutxDsrFlow = FALSE;
9871 dcb.fDtrControl = DTR_CONTROL_DISABLE;
9872 dcb.fDsrSensitivity = FALSE;
9873 dcb.fTXContinueOnXoff = FALSE;
9874 dcb.fOutX = FALSE;
9875 dcb.fInX = FALSE;
9876 dcb.fRtsControl = RTS_CONTROL_DISABLE;
9877 dcb.XonChar = 17; /* Control-Q */
9878 dcb.XoffChar = 19; /* Control-S */
9879 if (NILP (tem))
9881 /* Already configured. */
9883 else if (EQ (tem, Qhw))
9885 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
9886 dcb.fOutxCtsFlow = TRUE;
9888 else if (EQ (tem, Qsw))
9890 dcb.fOutX = TRUE;
9891 dcb.fInX = TRUE;
9893 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
9895 /* Activate configuration. */
9896 if (!SetCommState (hnd, &dcb))
9897 error ("SetCommState() failed");
9899 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
9900 pset_childp (p, childp2);
9903 /* For make-pipe-process */
9904 void
9905 register_aux_fd (int infd)
9907 child_process *cp;
9909 cp = new_child ();
9910 if (!cp)
9911 error ("Could not create child process");
9912 cp->fd = infd;
9913 cp->status = STATUS_READ_ACKNOWLEDGED;
9915 if (fd_info[ infd ].cp != NULL)
9917 error ("fd_info[fd = %d] is already in use", infd);
9919 fd_info[ infd ].cp = cp;
9920 fd_info[ infd ].hnd = (HANDLE) _get_osfhandle (infd);
9923 #ifdef HAVE_GNUTLS
9925 ssize_t
9926 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
9928 int n, err;
9929 struct Lisp_Process *process = (struct Lisp_Process *)p;
9930 int fd = process->infd;
9932 n = sys_read (fd, (char*)buf, sz);
9934 if (n >= 0)
9935 return n;
9937 err = errno;
9939 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9940 if (err == EWOULDBLOCK)
9941 err = EAGAIN;
9943 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
9945 return -1;
9948 ssize_t
9949 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
9951 struct Lisp_Process *process = (struct Lisp_Process *)p;
9952 int fd = process->outfd;
9953 ssize_t n = sys_write (fd, buf, sz);
9955 /* 0 or more bytes written means everything went fine. */
9956 if (n >= 0)
9957 return n;
9959 /* Negative bytes written means we got an error in errno.
9960 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9961 emacs_gnutls_transport_set_errno (process->gnutls_state,
9962 errno == EWOULDBLOCK ? EAGAIN : errno);
9964 return -1;
9966 #endif /* HAVE_GNUTLS */
9968 /* end of w32.c */