Document reserved keys
[emacs.git] / src / w32.c
blob5ac66181403aca4c2458332c566bf4958ef4775c
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
3 Copyright (C) 1994-1995, 2000-2018 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 <https://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_open (const char *, int, int);
78 int sys_rename (char const *, char const *);
79 int sys_rmdir (const char *);
80 int sys_close (int);
81 int sys_dup2 (int, int);
82 int sys_read (int, char *, unsigned int);
83 int sys_write (int, const void *, unsigned int);
84 struct tm *sys_localtime (const time_t *);
85 /* MinGW64 system headers include string.h too early, causing the
86 compiler to emit a warning about sys_strerror having no
87 prototype. */
88 char *sys_strerror (int);
90 #ifdef HAVE_MODULES
91 extern void dynlib_reset_last_error (void);
92 #endif
94 #include "lisp.h"
95 #include "epaths.h" /* for PATH_EXEC */
97 #include <pwd.h>
98 #include <grp.h>
100 #include <windows.h>
101 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
102 use a different name to avoid compilation problems. */
103 typedef struct _MEMORY_STATUS_EX {
104 DWORD dwLength;
105 DWORD dwMemoryLoad;
106 DWORDLONG ullTotalPhys;
107 DWORDLONG ullAvailPhys;
108 DWORDLONG ullTotalPageFile;
109 DWORDLONG ullAvailPageFile;
110 DWORDLONG ullTotalVirtual;
111 DWORDLONG ullAvailVirtual;
112 DWORDLONG ullAvailExtendedVirtual;
113 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
115 /* These are here so that GDB would know about these data types. This
116 allows attaching GDB to Emacs when a fatal exception is triggered
117 and Windows pops up the "application needs to be closed" dialog.
118 At that point, _gnu_exception_handler, the top-level exception
119 handler installed by the MinGW startup code, is somewhere on the
120 call-stack of the main thread, so going to that call frame and
121 looking at the argument to _gnu_exception_handler, which is a
122 PEXCEPTION_POINTERS pointer, can reveal the exception code
123 (excptr->ExceptionRecord->ExceptionCode) and the address where the
124 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
125 well as some additional information specific to the exception. */
126 PEXCEPTION_POINTERS excptr;
127 PEXCEPTION_RECORD excprec;
128 PCONTEXT ctxrec;
130 #include <lmcons.h>
131 #include <shlobj.h>
133 #include <tlhelp32.h>
134 #include <psapi.h>
135 #ifndef _MSC_VER
136 #include <w32api.h>
137 #endif
138 #if _WIN32_WINNT < 0x0500
139 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
140 /* This either is not in psapi.h or guarded by higher value of
141 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
142 defines it in psapi.h */
143 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
144 DWORD cb;
145 DWORD PageFaultCount;
146 SIZE_T PeakWorkingSetSize;
147 SIZE_T WorkingSetSize;
148 SIZE_T QuotaPeakPagedPoolUsage;
149 SIZE_T QuotaPagedPoolUsage;
150 SIZE_T QuotaPeakNonPagedPoolUsage;
151 SIZE_T QuotaNonPagedPoolUsage;
152 SIZE_T PagefileUsage;
153 SIZE_T PeakPagefileUsage;
154 SIZE_T PrivateUsage;
155 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
156 #endif
157 #endif
159 #include <winioctl.h>
160 #include <aclapi.h>
161 #include <sddl.h>
163 #include <sys/acl.h>
164 #include <acl.h>
166 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
167 define them by hand if not already defined. */
168 #ifndef SDDL_REVISION_1
169 #define SDDL_REVISION_1 1
170 #endif /* SDDL_REVISION_1 */
172 #if defined(_MSC_VER) || defined(MINGW_W64)
173 /* MSVC and MinGW64 don't provide the definition of
174 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
175 which cannot be included because it triggers conflicts with other
176 Windows API headers. So we define it here by hand. */
178 typedef struct _REPARSE_DATA_BUFFER {
179 ULONG ReparseTag;
180 USHORT ReparseDataLength;
181 USHORT Reserved;
182 union {
183 struct {
184 USHORT SubstituteNameOffset;
185 USHORT SubstituteNameLength;
186 USHORT PrintNameOffset;
187 USHORT PrintNameLength;
188 ULONG Flags;
189 WCHAR PathBuffer[1];
190 } SymbolicLinkReparseBuffer;
191 struct {
192 USHORT SubstituteNameOffset;
193 USHORT SubstituteNameLength;
194 USHORT PrintNameOffset;
195 USHORT PrintNameLength;
196 WCHAR PathBuffer[1];
197 } MountPointReparseBuffer;
198 struct {
199 UCHAR DataBuffer[1];
200 } GenericReparseBuffer;
201 } DUMMYUNIONNAME;
202 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
204 #ifndef FILE_DEVICE_FILE_SYSTEM
205 #define FILE_DEVICE_FILE_SYSTEM 9
206 #endif
207 #ifndef METHOD_BUFFERED
208 #define METHOD_BUFFERED 0
209 #endif
210 #ifndef FILE_ANY_ACCESS
211 #define FILE_ANY_ACCESS 0x00000000
212 #endif
213 #ifndef CTL_CODE
214 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
215 #endif
216 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
217 #ifndef FSCTL_GET_REPARSE_POINT
218 #define FSCTL_GET_REPARSE_POINT \
219 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
220 #endif
221 #endif
223 /* TCP connection support. */
224 #include <sys/socket.h>
225 #undef socket
226 #undef bind
227 #undef connect
228 #undef htons
229 #undef ntohs
230 #undef inet_addr
231 #undef gethostname
232 #undef gethostbyname
233 #undef getservbyname
234 #undef getpeername
235 #undef shutdown
236 #undef setsockopt
237 #undef listen
238 #undef getsockname
239 #undef accept
240 #undef recvfrom
241 #undef sendto
243 #include <iphlpapi.h> /* should be after winsock2.h */
245 #include <wincrypt.h>
247 #include <c-strcase.h>
248 #include <utimens.h> /* for fdutimens */
250 #include "w32.h"
251 #include <dirent.h>
252 #include "w32common.h"
253 #include "w32select.h"
254 #include "systime.h" /* for current_timespec, struct timespec */
255 #include "dispextern.h" /* for xstrcasecmp */
256 #include "coding.h" /* for Vlocale_coding_system */
258 #include "careadlinkat.h"
259 #include "allocator.h"
261 /* For Lisp_Process, serial_configure and serial_open. */
262 #include "process.h"
263 #include "systty.h"
265 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
266 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
268 static DWORD get_rid (PSID);
269 static int is_symlink (const char *);
270 static char * chase_symlinks (const char *);
271 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
272 static int restore_privilege (TOKEN_PRIVILEGES *);
273 static BOOL WINAPI revert_to_self (void);
275 static int sys_access (const char *, int);
276 extern void *e_malloc (size_t);
277 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
278 const struct timespec *, const sigset_t *);
279 extern int sys_dup (int);
282 /* Initialization states.
284 WARNING: If you add any more such variables for additional APIs,
285 you MUST add initialization for them to globals_of_w32
286 below. This is because these variables might get set
287 to non-NULL values during dumping, but the dumped Emacs
288 cannot reuse those values, because it could be run on a
289 different version of the OS, where API addresses are
290 different. */
291 static BOOL g_b_init_is_windows_9x;
292 static BOOL g_b_init_open_process_token;
293 static BOOL g_b_init_get_token_information;
294 static BOOL g_b_init_lookup_account_sid;
295 static BOOL g_b_init_get_sid_sub_authority;
296 static BOOL g_b_init_get_sid_sub_authority_count;
297 static BOOL g_b_init_get_security_info;
298 static BOOL g_b_init_get_file_security_w;
299 static BOOL g_b_init_get_file_security_a;
300 static BOOL g_b_init_get_security_descriptor_owner;
301 static BOOL g_b_init_get_security_descriptor_group;
302 static BOOL g_b_init_is_valid_sid;
303 static BOOL g_b_init_create_toolhelp32_snapshot;
304 static BOOL g_b_init_process32_first;
305 static BOOL g_b_init_process32_next;
306 static BOOL g_b_init_open_thread_token;
307 static BOOL g_b_init_impersonate_self;
308 static BOOL g_b_init_revert_to_self;
309 static BOOL g_b_init_get_process_memory_info;
310 static BOOL g_b_init_get_process_working_set_size;
311 static BOOL g_b_init_global_memory_status;
312 static BOOL g_b_init_global_memory_status_ex;
313 static BOOL g_b_init_get_length_sid;
314 static BOOL g_b_init_equal_sid;
315 static BOOL g_b_init_copy_sid;
316 static BOOL g_b_init_get_native_system_info;
317 static BOOL g_b_init_get_system_times;
318 static BOOL g_b_init_create_symbolic_link_w;
319 static BOOL g_b_init_create_symbolic_link_a;
320 static BOOL g_b_init_get_security_descriptor_dacl;
321 static BOOL g_b_init_convert_sd_to_sddl;
322 static BOOL g_b_init_convert_sddl_to_sd;
323 static BOOL g_b_init_is_valid_security_descriptor;
324 static BOOL g_b_init_set_file_security_w;
325 static BOOL g_b_init_set_file_security_a;
326 static BOOL g_b_init_set_named_security_info_w;
327 static BOOL g_b_init_set_named_security_info_a;
328 static BOOL g_b_init_get_adapters_info;
330 BOOL g_b_init_compare_string_w;
331 BOOL g_b_init_debug_break_process;
334 BEGIN: Wrapper functions around OpenProcessToken
335 and other functions in advapi32.dll that are only
336 supported in Windows NT / 2k / XP
338 /* ** Function pointer typedefs ** */
339 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
340 HANDLE ProcessHandle,
341 DWORD DesiredAccess,
342 PHANDLE TokenHandle);
343 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
344 HANDLE TokenHandle,
345 TOKEN_INFORMATION_CLASS TokenInformationClass,
346 LPVOID TokenInformation,
347 DWORD TokenInformationLength,
348 PDWORD ReturnLength);
349 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
350 HANDLE process_handle,
351 LPFILETIME creation_time,
352 LPFILETIME exit_time,
353 LPFILETIME kernel_time,
354 LPFILETIME user_time);
356 GetProcessTimes_Proc get_process_times_fn = NULL;
358 #ifdef _UNICODE
359 const char * const LookupAccountSid_Name = "LookupAccountSidW";
360 #else
361 const char * const LookupAccountSid_Name = "LookupAccountSidA";
362 #endif
363 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
364 LPCTSTR lpSystemName,
365 PSID Sid,
366 LPTSTR Name,
367 LPDWORD cbName,
368 LPTSTR DomainName,
369 LPDWORD cbDomainName,
370 PSID_NAME_USE peUse);
371 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
372 PSID pSid,
373 DWORD n);
374 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
375 PSID pSid);
376 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
377 HANDLE handle,
378 SE_OBJECT_TYPE ObjectType,
379 SECURITY_INFORMATION SecurityInfo,
380 PSID *ppsidOwner,
381 PSID *ppsidGroup,
382 PACL *ppDacl,
383 PACL *ppSacl,
384 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
385 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
386 LPCWSTR lpFileName,
387 SECURITY_INFORMATION RequestedInformation,
388 PSECURITY_DESCRIPTOR pSecurityDescriptor,
389 DWORD nLength,
390 LPDWORD lpnLengthNeeded);
391 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
392 LPCSTR lpFileName,
393 SECURITY_INFORMATION RequestedInformation,
394 PSECURITY_DESCRIPTOR pSecurityDescriptor,
395 DWORD nLength,
396 LPDWORD lpnLengthNeeded);
397 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
398 LPCWSTR lpFileName,
399 SECURITY_INFORMATION SecurityInformation,
400 PSECURITY_DESCRIPTOR pSecurityDescriptor);
401 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
402 LPCSTR lpFileName,
403 SECURITY_INFORMATION SecurityInformation,
404 PSECURITY_DESCRIPTOR pSecurityDescriptor);
405 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
406 LPCWSTR lpObjectName,
407 SE_OBJECT_TYPE ObjectType,
408 SECURITY_INFORMATION SecurityInformation,
409 PSID psidOwner,
410 PSID psidGroup,
411 PACL pDacl,
412 PACL pSacl);
413 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
414 LPCSTR lpObjectName,
415 SE_OBJECT_TYPE ObjectType,
416 SECURITY_INFORMATION SecurityInformation,
417 PSID psidOwner,
418 PSID psidGroup,
419 PACL pDacl,
420 PACL pSacl);
421 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
422 PSECURITY_DESCRIPTOR pSecurityDescriptor,
423 PSID *pOwner,
424 LPBOOL lpbOwnerDefaulted);
425 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
426 PSECURITY_DESCRIPTOR pSecurityDescriptor,
427 PSID *pGroup,
428 LPBOOL lpbGroupDefaulted);
429 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
430 PSECURITY_DESCRIPTOR pSecurityDescriptor,
431 LPBOOL lpbDaclPresent,
432 PACL *pDacl,
433 LPBOOL lpbDaclDefaulted);
434 typedef BOOL (WINAPI * IsValidSid_Proc) (
435 PSID sid);
436 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
437 DWORD dwFlags,
438 DWORD th32ProcessID);
439 typedef BOOL (WINAPI * Process32First_Proc) (
440 HANDLE hSnapshot,
441 LPPROCESSENTRY32 lppe);
442 typedef BOOL (WINAPI * Process32Next_Proc) (
443 HANDLE hSnapshot,
444 LPPROCESSENTRY32 lppe);
445 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
446 HANDLE ThreadHandle,
447 DWORD DesiredAccess,
448 BOOL OpenAsSelf,
449 PHANDLE TokenHandle);
450 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
451 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
452 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
453 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
454 HANDLE Process,
455 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
456 DWORD cb);
457 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
458 HANDLE hProcess,
459 PSIZE_T lpMinimumWorkingSetSize,
460 PSIZE_T lpMaximumWorkingSetSize);
461 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
462 LPMEMORYSTATUS lpBuffer);
463 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
464 LPMEMORY_STATUS_EX lpBuffer);
465 typedef BOOL (WINAPI * CopySid_Proc) (
466 DWORD nDestinationSidLength,
467 PSID pDestinationSid,
468 PSID pSourceSid);
469 typedef BOOL (WINAPI * EqualSid_Proc) (
470 PSID pSid1,
471 PSID pSid2);
472 typedef DWORD (WINAPI * GetLengthSid_Proc) (
473 PSID pSid);
474 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
475 LPSYSTEM_INFO lpSystemInfo);
476 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
477 LPFILETIME lpIdleTime,
478 LPFILETIME lpKernelTime,
479 LPFILETIME lpUserTime);
480 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
481 LPCWSTR lpSymlinkFileName,
482 LPCWSTR lpTargetFileName,
483 DWORD dwFlags);
484 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
485 LPCSTR lpSymlinkFileName,
486 LPCSTR lpTargetFileName,
487 DWORD dwFlags);
488 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
489 LPCTSTR StringSecurityDescriptor,
490 DWORD StringSDRevision,
491 PSECURITY_DESCRIPTOR *SecurityDescriptor,
492 PULONG SecurityDescriptorSize);
493 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
494 PSECURITY_DESCRIPTOR SecurityDescriptor,
495 DWORD RequestedStringSDRevision,
496 SECURITY_INFORMATION SecurityInformation,
497 LPTSTR *StringSecurityDescriptor,
498 PULONG StringSecurityDescriptorLen);
499 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
500 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
501 PIP_ADAPTER_INFO pAdapterInfo,
502 PULONG pOutBufLen);
504 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
505 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
506 DWORD multiByteToWideCharFlags;
508 /* ** A utility function ** */
509 static BOOL
510 is_windows_9x (void)
512 static BOOL s_b_ret = 0;
513 OSVERSIONINFO os_ver;
514 if (g_b_init_is_windows_9x == 0)
516 g_b_init_is_windows_9x = 1;
517 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
518 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
519 if (GetVersionEx (&os_ver))
521 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
524 return s_b_ret;
527 static Lisp_Object ltime (ULONGLONG);
529 /* Get total user and system times for get-internal-run-time.
530 Returns a list of integers if the times are provided by the OS
531 (NT derivatives), otherwise it returns the result of current-time. */
532 Lisp_Object w32_get_internal_run_time (void);
534 Lisp_Object
535 w32_get_internal_run_time (void)
537 if (get_process_times_fn)
539 FILETIME create, exit, kernel, user;
540 HANDLE proc = GetCurrentProcess ();
541 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
543 LARGE_INTEGER user_int, kernel_int, total;
544 user_int.LowPart = user.dwLowDateTime;
545 user_int.HighPart = user.dwHighDateTime;
546 kernel_int.LowPart = kernel.dwLowDateTime;
547 kernel_int.HighPart = kernel.dwHighDateTime;
548 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
549 return ltime (total.QuadPart);
553 return Fcurrent_time ();
556 /* ** The wrapper functions ** */
558 static BOOL WINAPI
559 open_process_token (HANDLE ProcessHandle,
560 DWORD DesiredAccess,
561 PHANDLE TokenHandle)
563 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
564 HMODULE hm_advapi32 = NULL;
565 if (is_windows_9x () == TRUE)
567 return FALSE;
569 if (g_b_init_open_process_token == 0)
571 g_b_init_open_process_token = 1;
572 hm_advapi32 = LoadLibrary ("Advapi32.dll");
573 s_pfn_Open_Process_Token =
574 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
576 if (s_pfn_Open_Process_Token == NULL)
578 return FALSE;
580 return (
581 s_pfn_Open_Process_Token (
582 ProcessHandle,
583 DesiredAccess,
584 TokenHandle)
588 static BOOL WINAPI
589 get_token_information (HANDLE TokenHandle,
590 TOKEN_INFORMATION_CLASS TokenInformationClass,
591 LPVOID TokenInformation,
592 DWORD TokenInformationLength,
593 PDWORD ReturnLength)
595 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
596 HMODULE hm_advapi32 = NULL;
597 if (is_windows_9x () == TRUE)
599 return FALSE;
601 if (g_b_init_get_token_information == 0)
603 g_b_init_get_token_information = 1;
604 hm_advapi32 = LoadLibrary ("Advapi32.dll");
605 s_pfn_Get_Token_Information =
606 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
608 if (s_pfn_Get_Token_Information == NULL)
610 return FALSE;
612 return (
613 s_pfn_Get_Token_Information (
614 TokenHandle,
615 TokenInformationClass,
616 TokenInformation,
617 TokenInformationLength,
618 ReturnLength)
622 static BOOL WINAPI
623 lookup_account_sid (LPCTSTR lpSystemName,
624 PSID Sid,
625 LPTSTR Name,
626 LPDWORD cbName,
627 LPTSTR DomainName,
628 LPDWORD cbDomainName,
629 PSID_NAME_USE peUse)
631 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
632 HMODULE hm_advapi32 = NULL;
633 if (is_windows_9x () == TRUE)
635 return FALSE;
637 if (g_b_init_lookup_account_sid == 0)
639 g_b_init_lookup_account_sid = 1;
640 hm_advapi32 = LoadLibrary ("Advapi32.dll");
641 s_pfn_Lookup_Account_Sid =
642 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
644 if (s_pfn_Lookup_Account_Sid == NULL)
646 return FALSE;
648 return (
649 s_pfn_Lookup_Account_Sid (
650 lpSystemName,
651 Sid,
652 Name,
653 cbName,
654 DomainName,
655 cbDomainName,
656 peUse)
660 static PDWORD WINAPI
661 get_sid_sub_authority (PSID pSid, DWORD n)
663 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
664 static DWORD zero = 0U;
665 HMODULE hm_advapi32 = NULL;
666 if (is_windows_9x () == TRUE)
668 return &zero;
670 if (g_b_init_get_sid_sub_authority == 0)
672 g_b_init_get_sid_sub_authority = 1;
673 hm_advapi32 = LoadLibrary ("Advapi32.dll");
674 s_pfn_Get_Sid_Sub_Authority =
675 (GetSidSubAuthority_Proc) GetProcAddress (
676 hm_advapi32, "GetSidSubAuthority");
678 if (s_pfn_Get_Sid_Sub_Authority == NULL)
680 return &zero;
682 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
685 static PUCHAR WINAPI
686 get_sid_sub_authority_count (PSID pSid)
688 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
689 static UCHAR zero = 0U;
690 HMODULE hm_advapi32 = NULL;
691 if (is_windows_9x () == TRUE)
693 return &zero;
695 if (g_b_init_get_sid_sub_authority_count == 0)
697 g_b_init_get_sid_sub_authority_count = 1;
698 hm_advapi32 = LoadLibrary ("Advapi32.dll");
699 s_pfn_Get_Sid_Sub_Authority_Count =
700 (GetSidSubAuthorityCount_Proc) GetProcAddress (
701 hm_advapi32, "GetSidSubAuthorityCount");
703 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
705 return &zero;
707 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
710 static DWORD WINAPI
711 get_security_info (HANDLE handle,
712 SE_OBJECT_TYPE ObjectType,
713 SECURITY_INFORMATION SecurityInfo,
714 PSID *ppsidOwner,
715 PSID *ppsidGroup,
716 PACL *ppDacl,
717 PACL *ppSacl,
718 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
720 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
721 HMODULE hm_advapi32 = NULL;
722 if (is_windows_9x () == TRUE)
724 return FALSE;
726 if (g_b_init_get_security_info == 0)
728 g_b_init_get_security_info = 1;
729 hm_advapi32 = LoadLibrary ("Advapi32.dll");
730 s_pfn_Get_Security_Info =
731 (GetSecurityInfo_Proc) GetProcAddress (
732 hm_advapi32, "GetSecurityInfo");
734 if (s_pfn_Get_Security_Info == NULL)
736 return FALSE;
738 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
739 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
740 ppSecurityDescriptor));
743 static BOOL WINAPI
744 get_file_security (const char *lpFileName,
745 SECURITY_INFORMATION RequestedInformation,
746 PSECURITY_DESCRIPTOR pSecurityDescriptor,
747 DWORD nLength,
748 LPDWORD lpnLengthNeeded)
750 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
751 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
752 HMODULE hm_advapi32 = NULL;
753 if (is_windows_9x () == TRUE)
755 errno = ENOTSUP;
756 return FALSE;
758 if (w32_unicode_filenames)
760 wchar_t filename_w[MAX_PATH];
762 if (g_b_init_get_file_security_w == 0)
764 g_b_init_get_file_security_w = 1;
765 hm_advapi32 = LoadLibrary ("Advapi32.dll");
766 s_pfn_Get_File_SecurityW =
767 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
768 "GetFileSecurityW");
770 if (s_pfn_Get_File_SecurityW == NULL)
772 errno = ENOTSUP;
773 return FALSE;
775 filename_to_utf16 (lpFileName, filename_w);
776 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
777 pSecurityDescriptor, nLength,
778 lpnLengthNeeded));
780 else
782 char filename_a[MAX_PATH];
784 if (g_b_init_get_file_security_a == 0)
786 g_b_init_get_file_security_a = 1;
787 hm_advapi32 = LoadLibrary ("Advapi32.dll");
788 s_pfn_Get_File_SecurityA =
789 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
790 "GetFileSecurityA");
792 if (s_pfn_Get_File_SecurityA == NULL)
794 errno = ENOTSUP;
795 return FALSE;
797 filename_to_ansi (lpFileName, filename_a);
798 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
799 pSecurityDescriptor, nLength,
800 lpnLengthNeeded));
804 static BOOL WINAPI
805 set_file_security (const char *lpFileName,
806 SECURITY_INFORMATION SecurityInformation,
807 PSECURITY_DESCRIPTOR pSecurityDescriptor)
809 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
810 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
811 HMODULE hm_advapi32 = NULL;
812 if (is_windows_9x () == TRUE)
814 errno = ENOTSUP;
815 return FALSE;
817 if (w32_unicode_filenames)
819 wchar_t filename_w[MAX_PATH];
821 if (g_b_init_set_file_security_w == 0)
823 g_b_init_set_file_security_w = 1;
824 hm_advapi32 = LoadLibrary ("Advapi32.dll");
825 s_pfn_Set_File_SecurityW =
826 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
827 "SetFileSecurityW");
829 if (s_pfn_Set_File_SecurityW == NULL)
831 errno = ENOTSUP;
832 return FALSE;
834 filename_to_utf16 (lpFileName, filename_w);
835 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
836 pSecurityDescriptor));
838 else
840 char filename_a[MAX_PATH];
842 if (g_b_init_set_file_security_a == 0)
844 g_b_init_set_file_security_a = 1;
845 hm_advapi32 = LoadLibrary ("Advapi32.dll");
846 s_pfn_Set_File_SecurityA =
847 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
848 "SetFileSecurityA");
850 if (s_pfn_Set_File_SecurityA == NULL)
852 errno = ENOTSUP;
853 return FALSE;
855 filename_to_ansi (lpFileName, filename_a);
856 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
857 pSecurityDescriptor));
861 static DWORD WINAPI
862 set_named_security_info (LPCTSTR lpObjectName,
863 SE_OBJECT_TYPE ObjectType,
864 SECURITY_INFORMATION SecurityInformation,
865 PSID psidOwner,
866 PSID psidGroup,
867 PACL pDacl,
868 PACL pSacl)
870 static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
871 static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
872 HMODULE hm_advapi32 = NULL;
873 if (is_windows_9x () == TRUE)
875 errno = ENOTSUP;
876 return ENOTSUP;
878 if (w32_unicode_filenames)
880 wchar_t filename_w[MAX_PATH];
882 if (g_b_init_set_named_security_info_w == 0)
884 g_b_init_set_named_security_info_w = 1;
885 hm_advapi32 = LoadLibrary ("Advapi32.dll");
886 s_pfn_Set_Named_Security_InfoW =
887 (SetNamedSecurityInfoW_Proc) GetProcAddress (hm_advapi32,
888 "SetNamedSecurityInfoW");
890 if (s_pfn_Set_Named_Security_InfoW == NULL)
892 errno = ENOTSUP;
893 return ENOTSUP;
895 filename_to_utf16 (lpObjectName, filename_w);
896 return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
897 SecurityInformation, psidOwner,
898 psidGroup, pDacl, pSacl));
900 else
902 char filename_a[MAX_PATH];
904 if (g_b_init_set_named_security_info_a == 0)
906 g_b_init_set_named_security_info_a = 1;
907 hm_advapi32 = LoadLibrary ("Advapi32.dll");
908 s_pfn_Set_Named_Security_InfoA =
909 (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
910 "SetNamedSecurityInfoA");
912 if (s_pfn_Set_Named_Security_InfoA == NULL)
914 errno = ENOTSUP;
915 return ENOTSUP;
917 filename_to_ansi (lpObjectName, filename_a);
918 return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
919 SecurityInformation, psidOwner,
920 psidGroup, pDacl, pSacl));
924 static BOOL WINAPI
925 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
926 PSID *pOwner,
927 LPBOOL lpbOwnerDefaulted)
929 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
930 HMODULE hm_advapi32 = NULL;
931 if (is_windows_9x () == TRUE)
933 errno = ENOTSUP;
934 return FALSE;
936 if (g_b_init_get_security_descriptor_owner == 0)
938 g_b_init_get_security_descriptor_owner = 1;
939 hm_advapi32 = LoadLibrary ("Advapi32.dll");
940 s_pfn_Get_Security_Descriptor_Owner =
941 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
942 hm_advapi32, "GetSecurityDescriptorOwner");
944 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
946 errno = ENOTSUP;
947 return FALSE;
949 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
950 lpbOwnerDefaulted));
953 static BOOL WINAPI
954 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
955 PSID *pGroup,
956 LPBOOL lpbGroupDefaulted)
958 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
959 HMODULE hm_advapi32 = NULL;
960 if (is_windows_9x () == TRUE)
962 errno = ENOTSUP;
963 return FALSE;
965 if (g_b_init_get_security_descriptor_group == 0)
967 g_b_init_get_security_descriptor_group = 1;
968 hm_advapi32 = LoadLibrary ("Advapi32.dll");
969 s_pfn_Get_Security_Descriptor_Group =
970 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
971 hm_advapi32, "GetSecurityDescriptorGroup");
973 if (s_pfn_Get_Security_Descriptor_Group == NULL)
975 errno = ENOTSUP;
976 return FALSE;
978 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
979 lpbGroupDefaulted));
982 static BOOL WINAPI
983 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
984 LPBOOL lpbDaclPresent,
985 PACL *pDacl,
986 LPBOOL lpbDaclDefaulted)
988 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
989 HMODULE hm_advapi32 = NULL;
990 if (is_windows_9x () == TRUE)
992 errno = ENOTSUP;
993 return FALSE;
995 if (g_b_init_get_security_descriptor_dacl == 0)
997 g_b_init_get_security_descriptor_dacl = 1;
998 hm_advapi32 = LoadLibrary ("Advapi32.dll");
999 s_pfn_Get_Security_Descriptor_Dacl =
1000 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
1001 hm_advapi32, "GetSecurityDescriptorDacl");
1003 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
1005 errno = ENOTSUP;
1006 return FALSE;
1008 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
1009 lpbDaclPresent, pDacl,
1010 lpbDaclDefaulted));
1013 static BOOL WINAPI
1014 is_valid_sid (PSID sid)
1016 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
1017 HMODULE hm_advapi32 = NULL;
1018 if (is_windows_9x () == TRUE)
1020 return FALSE;
1022 if (g_b_init_is_valid_sid == 0)
1024 g_b_init_is_valid_sid = 1;
1025 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1026 s_pfn_Is_Valid_Sid =
1027 (IsValidSid_Proc) GetProcAddress (
1028 hm_advapi32, "IsValidSid");
1030 if (s_pfn_Is_Valid_Sid == NULL)
1032 return FALSE;
1034 return (s_pfn_Is_Valid_Sid (sid));
1037 static BOOL WINAPI
1038 equal_sid (PSID sid1, PSID sid2)
1040 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
1041 HMODULE hm_advapi32 = NULL;
1042 if (is_windows_9x () == TRUE)
1044 return FALSE;
1046 if (g_b_init_equal_sid == 0)
1048 g_b_init_equal_sid = 1;
1049 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1050 s_pfn_Equal_Sid =
1051 (EqualSid_Proc) GetProcAddress (
1052 hm_advapi32, "EqualSid");
1054 if (s_pfn_Equal_Sid == NULL)
1056 return FALSE;
1058 return (s_pfn_Equal_Sid (sid1, sid2));
1061 static DWORD WINAPI
1062 get_length_sid (PSID sid)
1064 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
1065 HMODULE hm_advapi32 = NULL;
1066 if (is_windows_9x () == TRUE)
1068 return 0;
1070 if (g_b_init_get_length_sid == 0)
1072 g_b_init_get_length_sid = 1;
1073 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1074 s_pfn_Get_Length_Sid =
1075 (GetLengthSid_Proc) GetProcAddress (
1076 hm_advapi32, "GetLengthSid");
1078 if (s_pfn_Get_Length_Sid == NULL)
1080 return 0;
1082 return (s_pfn_Get_Length_Sid (sid));
1085 static BOOL WINAPI
1086 copy_sid (DWORD destlen, PSID dest, PSID src)
1088 static CopySid_Proc s_pfn_Copy_Sid = NULL;
1089 HMODULE hm_advapi32 = NULL;
1090 if (is_windows_9x () == TRUE)
1092 return FALSE;
1094 if (g_b_init_copy_sid == 0)
1096 g_b_init_copy_sid = 1;
1097 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1098 s_pfn_Copy_Sid =
1099 (CopySid_Proc) GetProcAddress (
1100 hm_advapi32, "CopySid");
1102 if (s_pfn_Copy_Sid == NULL)
1104 return FALSE;
1106 return (s_pfn_Copy_Sid (destlen, dest, src));
1110 END: Wrapper functions around OpenProcessToken
1111 and other functions in advapi32.dll that are only
1112 supported in Windows NT / 2k / XP
1115 static void WINAPI
1116 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1118 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1119 if (is_windows_9x () != TRUE)
1121 if (g_b_init_get_native_system_info == 0)
1123 g_b_init_get_native_system_info = 1;
1124 s_pfn_Get_Native_System_Info =
1125 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1126 "GetNativeSystemInfo");
1128 if (s_pfn_Get_Native_System_Info != NULL)
1129 s_pfn_Get_Native_System_Info (lpSystemInfo);
1131 else
1132 lpSystemInfo->dwNumberOfProcessors = -1;
1135 static BOOL WINAPI
1136 get_system_times (LPFILETIME lpIdleTime,
1137 LPFILETIME lpKernelTime,
1138 LPFILETIME lpUserTime)
1140 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1141 if (is_windows_9x () == TRUE)
1143 return FALSE;
1145 if (g_b_init_get_system_times == 0)
1147 g_b_init_get_system_times = 1;
1148 s_pfn_Get_System_times =
1149 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1150 "GetSystemTimes");
1152 if (s_pfn_Get_System_times == NULL)
1153 return FALSE;
1154 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1157 static BOOLEAN WINAPI
1158 create_symbolic_link (LPCSTR lpSymlinkFilename,
1159 LPCSTR lpTargetFileName,
1160 DWORD dwFlags)
1162 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1163 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1164 BOOLEAN retval;
1166 if (is_windows_9x () == TRUE)
1168 errno = ENOSYS;
1169 return 0;
1171 if (w32_unicode_filenames)
1173 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1175 if (g_b_init_create_symbolic_link_w == 0)
1177 g_b_init_create_symbolic_link_w = 1;
1178 s_pfn_Create_Symbolic_LinkW =
1179 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1180 "CreateSymbolicLinkW");
1182 if (s_pfn_Create_Symbolic_LinkW == NULL)
1184 errno = ENOSYS;
1185 return 0;
1188 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1189 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1190 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1191 /* If we were denied creation of the symlink, try again after
1192 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1193 if (!retval)
1195 TOKEN_PRIVILEGES priv_current;
1197 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1198 &priv_current))
1200 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1201 restore_privilege (&priv_current);
1202 revert_to_self ();
1206 else
1208 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1210 if (g_b_init_create_symbolic_link_a == 0)
1212 g_b_init_create_symbolic_link_a = 1;
1213 s_pfn_Create_Symbolic_LinkA =
1214 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1215 "CreateSymbolicLinkA");
1217 if (s_pfn_Create_Symbolic_LinkA == NULL)
1219 errno = ENOSYS;
1220 return 0;
1223 filename_to_ansi (lpSymlinkFilename, symfn_a);
1224 filename_to_ansi (lpTargetFileName, tgtfn_a);
1225 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1226 /* If we were denied creation of the symlink, try again after
1227 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1228 if (!retval)
1230 TOKEN_PRIVILEGES priv_current;
1232 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1233 &priv_current))
1235 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1236 restore_privilege (&priv_current);
1237 revert_to_self ();
1241 return retval;
1244 static BOOL WINAPI
1245 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1247 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1249 if (is_windows_9x () == TRUE)
1251 errno = ENOTSUP;
1252 return FALSE;
1255 if (g_b_init_is_valid_security_descriptor == 0)
1257 g_b_init_is_valid_security_descriptor = 1;
1258 s_pfn_Is_Valid_Security_Descriptor_Proc =
1259 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1260 "IsValidSecurityDescriptor");
1262 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1264 errno = ENOTSUP;
1265 return FALSE;
1268 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1271 static BOOL WINAPI
1272 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1273 DWORD RequestedStringSDRevision,
1274 SECURITY_INFORMATION SecurityInformation,
1275 LPTSTR *StringSecurityDescriptor,
1276 PULONG StringSecurityDescriptorLen)
1278 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1279 BOOL retval;
1281 if (is_windows_9x () == TRUE)
1283 errno = ENOTSUP;
1284 return FALSE;
1287 if (g_b_init_convert_sd_to_sddl == 0)
1289 g_b_init_convert_sd_to_sddl = 1;
1290 #ifdef _UNICODE
1291 s_pfn_Convert_SD_To_SDDL =
1292 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1293 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1294 #else
1295 s_pfn_Convert_SD_To_SDDL =
1296 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1297 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1298 #endif
1300 if (s_pfn_Convert_SD_To_SDDL == NULL)
1302 errno = ENOTSUP;
1303 return FALSE;
1306 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1307 RequestedStringSDRevision,
1308 SecurityInformation,
1309 StringSecurityDescriptor,
1310 StringSecurityDescriptorLen);
1312 return retval;
1315 static BOOL WINAPI
1316 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1317 DWORD StringSDRevision,
1318 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1319 PULONG SecurityDescriptorSize)
1321 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1322 BOOL retval;
1324 if (is_windows_9x () == TRUE)
1326 errno = ENOTSUP;
1327 return FALSE;
1330 if (g_b_init_convert_sddl_to_sd == 0)
1332 g_b_init_convert_sddl_to_sd = 1;
1333 #ifdef _UNICODE
1334 s_pfn_Convert_SDDL_To_SD =
1335 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1336 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1337 #else
1338 s_pfn_Convert_SDDL_To_SD =
1339 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1340 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1341 #endif
1343 if (s_pfn_Convert_SDDL_To_SD == NULL)
1345 errno = ENOTSUP;
1346 return FALSE;
1349 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1350 StringSDRevision,
1351 SecurityDescriptor,
1352 SecurityDescriptorSize);
1354 return retval;
1357 static DWORD WINAPI
1358 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1360 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1361 HMODULE hm_iphlpapi = NULL;
1363 if (is_windows_9x () == TRUE)
1364 return ERROR_NOT_SUPPORTED;
1366 if (g_b_init_get_adapters_info == 0)
1368 g_b_init_get_adapters_info = 1;
1369 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1370 if (hm_iphlpapi)
1371 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1372 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1374 if (s_pfn_Get_Adapters_Info == NULL)
1375 return ERROR_NOT_SUPPORTED;
1376 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1381 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1382 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1384 This is called from alloc.c:valid_pointer_p. */
1386 w32_valid_pointer_p (void *p, int size)
1388 SIZE_T done;
1389 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1391 if (h)
1393 unsigned char *buf = alloca (size);
1394 int retval = ReadProcessMemory (h, p, buf, size, &done);
1396 CloseHandle (h);
1397 return retval;
1399 else
1400 return -1;
1405 /* Here's an overview of how the Windows build supports file names
1406 that cannot be encoded by the current system codepage.
1408 From the POV of Lisp and layers of C code above the functions here,
1409 Emacs on Windows pretends that its file names are encoded in UTF-8;
1410 see encode_file and decode_file on coding.c. Any file name that is
1411 passed as a unibyte string to C functions defined here is assumed
1412 to be in UTF-8 encoding. Any file name returned by functions
1413 defined here must be in UTF-8 encoding, with only a few exceptions
1414 reserved for a couple of special cases. (Be sure to use
1415 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1416 as they can be much longer than MAX_PATH!)
1418 The UTF-8 encoded file names cannot be passed to system APIs, as
1419 Windows does not support that. Therefore, they are converted
1420 either to UTF-16 or to the ANSI codepage, depending on the value of
1421 w32-unicode-filenames, before calling any system APIs or CRT library
1422 functions. The default value of that variable is determined by the
1423 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1424 user can change that default (although I don't see why would she
1425 want to).
1427 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1428 filename_from_utf16, and filename_from_ansi, are the workhorses of
1429 these conversions. They rely on Windows native APIs
1430 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1431 functions from coding.c here, because they allocate memory, which
1432 is a bad idea on the level of libc, which is what the functions
1433 here emulate. (If you worry about performance due to constant
1434 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1435 it was measured to take only a few microseconds on a not-so-fast
1436 machine, and second, that's exactly what the ANSI APIs we used
1437 before did anyway, because they are just thin wrappers around the
1438 Unicode APIs.)
1440 The variables file-name-coding-system and default-file-name-coding-system
1441 still exist, but are actually used only when a file name needs to
1442 be converted to the ANSI codepage. This happens all the time when
1443 w32-unicode-filenames is nil, but can also happen from time to time
1444 when it is t. Otherwise, these variables have no effect on file-name
1445 encoding when w32-unicode-filenames is t; this is similar to
1446 selection-coding-system.
1448 This arrangement works very well, but it has a few gotchas and
1449 limitations:
1451 . Lisp code that encodes or decodes file names manually should
1452 normally use 'utf-8' as the coding-system on Windows,
1453 disregarding file-name-coding-system. This is a somewhat
1454 unpleasant consequence, but it cannot be avoided. Fortunately,
1455 very few Lisp packages need to do that.
1457 More generally, passing to library functions (e.g., fopen or
1458 opendir) file names already encoded in the ANSI codepage is
1459 explicitly *verboten*, as all those functions, as shadowed and
1460 emulated here, assume they will receive UTF-8 encoded file names.
1462 For the same reasons, no CRT function or Win32 API can be called
1463 directly in Emacs sources, without either converting the file
1464 names from UTF-8 to UTF-16 or ANSI codepage, or going through
1465 some shadowing function defined here.
1467 . Environment variables stored in Vprocess_environment are encoded
1468 in the ANSI codepage, so if getenv/egetenv is used for a variable
1469 whose value is a file name or a list of directories, it needs to
1470 be converted to UTF-8, before it is used as argument to functions
1471 or decoded into a Lisp string.
1473 . File names passed to external libraries, like the image libraries
1474 and GnuTLS, need special handling. These libraries generally
1475 don't support UTF-16 or UTF-8 file names, so they must get file
1476 names encoded in the ANSI codepage. To facilitate using these
1477 libraries with file names that are not encodable in the ANSI
1478 codepage, use the function ansi_encode_filename, which will try
1479 to use the short 8+3 alias of a file name if that file name is
1480 not encodable in the ANSI codepage. See image.c and gnutls.c for
1481 examples of how this should be done.
1483 . Running subprocesses in non-ASCII directories and with non-ASCII
1484 file arguments is limited to the current codepage (even though
1485 Emacs is perfectly capable of finding an executable program file
1486 in a directory whose name cannot be encoded in the current
1487 codepage). This is because the command-line arguments are
1488 encoded _before_ they get to the w32-specific level, and the
1489 encoding is not known in advance (it doesn't have to be the
1490 current ANSI codepage), so w32proc.c functions cannot re-encode
1491 them in UTF-16. This should be fixed, but will also require
1492 changes in cmdproxy. The current limitation is not terribly bad
1493 anyway, since very few, if any, Windows console programs that are
1494 likely to be invoked by Emacs support UTF-16 encoded command
1495 lines.
1497 . For similar reasons, server.el and emacsclient are also limited
1498 to the current ANSI codepage for now.
1500 . Emacs itself can only handle command-line arguments encoded in
1501 the current codepage.
1503 . Turning on w32-unicode-filename on Windows 9X (if it at all
1504 works) requires UNICOWS.DLL, which is thus a requirement even in
1505 non-GUI sessions, something that we previously avoided. */
1509 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1510 codepage defined by file-name-coding-system. */
1512 /* Current codepage for encoding file names. */
1513 static int file_name_codepage;
1515 /* Initialize the codepage used for decoding file names. This is
1516 needed to undo the value recorded during dumping, which might not
1517 be correct when we run the dumped Emacs. */
1518 void
1519 w32_init_file_name_codepage (void)
1521 file_name_codepage = CP_ACP;
1522 w32_ansi_code_page = CP_ACP;
1525 /* Produce a Windows ANSI codepage suitable for encoding file names.
1526 Return the information about that codepage in CP_INFO. */
1528 codepage_for_filenames (CPINFO *cp_info)
1530 /* A simple cache to avoid calling GetCPInfo every time we need to
1531 encode/decode a file name. The file-name encoding is not
1532 supposed to be changed too frequently, if ever. */
1533 static Lisp_Object last_file_name_encoding;
1534 static CPINFO cp;
1535 Lisp_Object current_encoding;
1537 current_encoding = Vfile_name_coding_system;
1538 if (NILP (current_encoding))
1539 current_encoding = Vdefault_file_name_coding_system;
1541 if (!EQ (last_file_name_encoding, current_encoding)
1542 || NILP (last_file_name_encoding))
1544 /* Default to the current ANSI codepage. */
1545 file_name_codepage = w32_ansi_code_page;
1547 if (!NILP (current_encoding))
1549 char *cpname = SSDATA (SYMBOL_NAME (current_encoding));
1550 char *cp = NULL, *end;
1551 int cpnum;
1553 if (strncmp (cpname, "cp", 2) == 0)
1554 cp = cpname + 2;
1555 else if (strncmp (cpname, "windows-", 8) == 0)
1556 cp = cpname + 8;
1558 if (cp)
1560 end = cp;
1561 cpnum = strtol (cp, &end, 10);
1562 if (cpnum && *end == '\0' && end - cp >= 2)
1563 file_name_codepage = cpnum;
1567 if (!file_name_codepage)
1568 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1570 if (!GetCPInfo (file_name_codepage, &cp))
1572 file_name_codepage = CP_ACP;
1573 if (!GetCPInfo (file_name_codepage, &cp))
1574 emacs_abort ();
1577 /* Cache the new value. */
1578 last_file_name_encoding = current_encoding;
1580 if (cp_info)
1581 *cp_info = cp;
1583 return file_name_codepage;
1587 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1589 int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
1590 -1, fn_out, MAX_PATH);
1592 if (!result)
1594 DWORD err = GetLastError ();
1596 switch (err)
1598 case ERROR_INVALID_FLAGS:
1599 case ERROR_INVALID_PARAMETER:
1600 errno = EINVAL;
1601 break;
1602 case ERROR_INSUFFICIENT_BUFFER:
1603 case ERROR_NO_UNICODE_TRANSLATION:
1604 default:
1605 errno = ENOENT;
1606 break;
1608 return -1;
1610 return 0;
1614 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1616 int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1617 fn_out, MAX_UTF8_PATH, NULL, NULL);
1619 if (!result)
1621 DWORD err = GetLastError ();
1623 switch (err)
1625 case ERROR_INVALID_FLAGS:
1626 case ERROR_INVALID_PARAMETER:
1627 errno = EINVAL;
1628 break;
1629 case ERROR_INSUFFICIENT_BUFFER:
1630 case ERROR_NO_UNICODE_TRANSLATION:
1631 default:
1632 errno = ENOENT;
1633 break;
1635 return -1;
1637 return 0;
1641 filename_to_ansi (const char *fn_in, char *fn_out)
1643 wchar_t fn_utf16[MAX_PATH];
1645 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1647 int result;
1648 int codepage = codepage_for_filenames (NULL);
1650 result = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
1651 fn_out, MAX_PATH, NULL, NULL);
1652 if (!result)
1654 DWORD err = GetLastError ();
1656 switch (err)
1658 case ERROR_INVALID_FLAGS:
1659 case ERROR_INVALID_PARAMETER:
1660 errno = EINVAL;
1661 break;
1662 case ERROR_INSUFFICIENT_BUFFER:
1663 case ERROR_NO_UNICODE_TRANSLATION:
1664 default:
1665 errno = ENOENT;
1666 break;
1668 return -1;
1670 return 0;
1672 return -1;
1676 filename_from_ansi (const char *fn_in, char *fn_out)
1678 wchar_t fn_utf16[MAX_PATH];
1679 int codepage = codepage_for_filenames (NULL);
1680 int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
1681 -1, fn_utf16, MAX_PATH);
1683 if (!result)
1685 DWORD err = GetLastError ();
1687 switch (err)
1689 case ERROR_INVALID_FLAGS:
1690 case ERROR_INVALID_PARAMETER:
1691 errno = EINVAL;
1692 break;
1693 case ERROR_INSUFFICIENT_BUFFER:
1694 case ERROR_NO_UNICODE_TRANSLATION:
1695 default:
1696 errno = ENOENT;
1697 break;
1699 return -1;
1701 return filename_from_utf16 (fn_utf16, fn_out);
1706 /* The directory where we started, in UTF-8. */
1707 static char startup_dir[MAX_UTF8_PATH];
1709 /* Get the current working directory. */
1710 char *
1711 getcwd (char *dir, int dirsize)
1713 if (!dirsize)
1715 errno = EINVAL;
1716 return NULL;
1718 if (dirsize <= strlen (startup_dir))
1720 errno = ERANGE;
1721 return NULL;
1723 #if 0
1724 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1725 return dir;
1726 return NULL;
1727 #else
1728 /* Emacs doesn't actually change directory itself, it stays in the
1729 same directory where it was started. */
1730 strcpy (dir, startup_dir);
1731 return dir;
1732 #endif
1735 /* Emulate getloadavg. */
1737 struct load_sample {
1738 time_t sample_time;
1739 ULONGLONG idle;
1740 ULONGLONG kernel;
1741 ULONGLONG user;
1744 /* Number of processors on this machine. */
1745 static unsigned num_of_processors;
1747 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1748 static struct load_sample samples[16*60];
1749 static int first_idx = -1, last_idx = -1;
1750 static int max_idx = ARRAYELTS (samples);
1752 static int
1753 buf_next (int from)
1755 int next_idx = from + 1;
1757 if (next_idx >= max_idx)
1758 next_idx = 0;
1760 return next_idx;
1763 static int
1764 buf_prev (int from)
1766 int prev_idx = from - 1;
1768 if (prev_idx < 0)
1769 prev_idx = max_idx - 1;
1771 return prev_idx;
1774 static void
1775 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1777 SYSTEM_INFO sysinfo;
1778 FILETIME ft_idle, ft_user, ft_kernel;
1780 /* Initialize the number of processors on this machine. */
1781 if (num_of_processors <= 0)
1783 get_native_system_info (&sysinfo);
1784 num_of_processors = sysinfo.dwNumberOfProcessors;
1785 if (num_of_processors <= 0)
1787 GetSystemInfo (&sysinfo);
1788 num_of_processors = sysinfo.dwNumberOfProcessors;
1790 if (num_of_processors <= 0)
1791 num_of_processors = 1;
1794 /* TODO: Take into account threads that are ready to run, by
1795 sampling the "\System\Processor Queue Length" performance
1796 counter. The code below accounts only for threads that are
1797 actually running. */
1799 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1801 ULARGE_INTEGER uidle, ukernel, uuser;
1803 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1804 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1805 memcpy (&uuser, &ft_user, sizeof (ft_user));
1806 *idle = uidle.QuadPart;
1807 *kernel = ukernel.QuadPart;
1808 *user = uuser.QuadPart;
1810 else
1812 *idle = 0;
1813 *kernel = 0;
1814 *user = 0;
1818 /* Produce the load average for a given time interval, using the
1819 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1820 1-minute, 5-minute, or 15-minute average, respectively. */
1821 static double
1822 getavg (int which)
1824 double retval = -1.0;
1825 double tdiff;
1826 int idx;
1827 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1828 time_t now = samples[last_idx].sample_time;
1830 if (first_idx != last_idx)
1832 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1834 tdiff = difftime (now, samples[idx].sample_time);
1835 if (tdiff >= span - 2*DBL_EPSILON*now)
1837 long double sys =
1838 samples[last_idx].kernel + samples[last_idx].user
1839 - (samples[idx].kernel + samples[idx].user);
1840 long double idl = samples[last_idx].idle - samples[idx].idle;
1842 retval = (1.0 - idl / sys) * num_of_processors;
1843 break;
1845 if (idx == first_idx)
1846 break;
1850 return retval;
1854 getloadavg (double loadavg[], int nelem)
1856 int elem;
1857 ULONGLONG idle, kernel, user;
1858 time_t now = time (NULL);
1860 /* If system time jumped back for some reason, delete all samples
1861 whose time is later than the current wall-clock time. This
1862 prevents load average figures from becoming frozen for prolonged
1863 periods of time, when system time is reset backwards. */
1864 if (last_idx >= 0)
1866 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1868 if (last_idx == first_idx)
1870 first_idx = last_idx = -1;
1871 break;
1873 last_idx = buf_prev (last_idx);
1877 /* Store another sample. We ignore samples that are less than 1 sec
1878 apart. */
1879 if (last_idx < 0
1880 || (difftime (now, samples[last_idx].sample_time)
1881 >= 1.0 - 2*DBL_EPSILON*now))
1883 sample_system_load (&idle, &kernel, &user);
1884 last_idx = buf_next (last_idx);
1885 samples[last_idx].sample_time = now;
1886 samples[last_idx].idle = idle;
1887 samples[last_idx].kernel = kernel;
1888 samples[last_idx].user = user;
1889 /* If the buffer has more that 15 min worth of samples, discard
1890 the old ones. */
1891 if (first_idx == -1)
1892 first_idx = last_idx;
1893 while (first_idx != last_idx
1894 && (difftime (now, samples[first_idx].sample_time)
1895 >= 15.0*60 + 2*DBL_EPSILON*now))
1896 first_idx = buf_next (first_idx);
1899 for (elem = 0; elem < nelem; elem++)
1901 double avg = getavg (elem);
1903 if (avg < 0)
1904 break;
1905 loadavg[elem] = avg;
1908 return elem;
1911 /* Emulate getpwuid, getpwnam and others. */
1913 #define PASSWD_FIELD_SIZE 256
1915 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1916 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1917 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1918 static char dflt_passwd_dir[MAX_UTF8_PATH];
1919 static char dflt_passwd_shell[MAX_UTF8_PATH];
1921 static struct passwd dflt_passwd =
1923 dflt_passwd_name,
1924 dflt_passwd_passwd,
1928 dflt_passwd_gecos,
1929 dflt_passwd_dir,
1930 dflt_passwd_shell,
1933 static char dflt_group_name[GNLEN+1];
1935 static struct group dflt_group =
1937 /* When group information is not available, we return this as the
1938 group for all files. */
1939 dflt_group_name,
1943 unsigned
1944 getuid (void)
1946 return dflt_passwd.pw_uid;
1949 unsigned
1950 geteuid (void)
1952 /* I could imagine arguing for checking to see whether the user is
1953 in the Administrators group and returning a UID of 0 for that
1954 case, but I don't know how wise that would be in the long run. */
1955 return getuid ();
1958 unsigned
1959 getgid (void)
1961 return dflt_passwd.pw_gid;
1964 unsigned
1965 getegid (void)
1967 return getgid ();
1970 struct passwd *
1971 getpwuid (unsigned uid)
1973 if (uid == dflt_passwd.pw_uid)
1974 return &dflt_passwd;
1975 return NULL;
1978 struct group *
1979 getgrgid (gid_t gid)
1981 return &dflt_group;
1984 struct passwd *
1985 getpwnam (char *name)
1987 struct passwd *pw;
1989 pw = getpwuid (getuid ());
1990 if (!pw)
1991 return pw;
1993 if (xstrcasecmp (name, pw->pw_name))
1994 return NULL;
1996 return pw;
1999 static void
2000 init_user_info (void)
2002 /* Find the user's real name by opening the process token and
2003 looking up the name associated with the user-sid in that token.
2005 Use the relative portion of the identifier authority value from
2006 the user-sid as the user id value (same for group id using the
2007 primary group sid from the process token). */
2009 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
2010 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
2011 DWORD glength = sizeof (gname);
2012 HANDLE token = NULL;
2013 SID_NAME_USE user_type;
2014 unsigned char *buf = NULL;
2015 DWORD blen = 0;
2016 TOKEN_USER user_token;
2017 TOKEN_PRIMARY_GROUP group_token;
2018 BOOL result;
2020 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
2021 if (result)
2023 result = get_token_information (token, TokenUser, NULL, 0, &blen);
2024 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2026 buf = xmalloc (blen);
2027 result = get_token_information (token, TokenUser,
2028 (LPVOID)buf, blen, &needed);
2029 if (result)
2031 memcpy (&user_token, buf, sizeof (user_token));
2032 result = lookup_account_sid (NULL, user_token.User.Sid,
2033 uname, &ulength,
2034 domain, &dlength, &user_type);
2037 else
2038 result = FALSE;
2040 if (result)
2042 strcpy (dflt_passwd.pw_name, uname);
2043 /* Determine a reasonable uid value. */
2044 if (xstrcasecmp ("administrator", uname) == 0)
2046 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
2047 dflt_passwd.pw_gid = 513; /* well-known None gid */
2049 else
2051 /* Use the last sub-authority value of the RID, the relative
2052 portion of the SID, as user/group ID. */
2053 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
2055 /* Get group id and name. */
2056 result = get_token_information (token, TokenPrimaryGroup,
2057 (LPVOID)buf, blen, &needed);
2058 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2060 buf = xrealloc (buf, blen = needed);
2061 result = get_token_information (token, TokenPrimaryGroup,
2062 (LPVOID)buf, blen, &needed);
2064 if (result)
2066 memcpy (&group_token, buf, sizeof (group_token));
2067 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
2068 dlength = sizeof (domain);
2069 /* If we can get at the real Primary Group name, use that.
2070 Otherwise, the default group name was already set to
2071 "None" in globals_of_w32. */
2072 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
2073 gname, &glength, NULL, &dlength,
2074 &user_type))
2075 strcpy (dflt_group_name, gname);
2077 else
2078 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2081 /* If security calls are not supported (presumably because we
2082 are running under Windows 9X), fallback to this: */
2083 else if (GetUserName (uname, &ulength))
2085 strcpy (dflt_passwd.pw_name, uname);
2086 if (xstrcasecmp ("administrator", uname) == 0)
2087 dflt_passwd.pw_uid = 0;
2088 else
2089 dflt_passwd.pw_uid = 123;
2090 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2092 else
2094 strcpy (dflt_passwd.pw_name, "unknown");
2095 dflt_passwd.pw_uid = 123;
2096 dflt_passwd.pw_gid = 123;
2098 dflt_group.gr_gid = dflt_passwd.pw_gid;
2100 /* Set dir and shell from environment variables. */
2101 if (w32_unicode_filenames)
2103 wchar_t *home = _wgetenv (L"HOME");
2104 wchar_t *shell = _wgetenv (L"SHELL");
2106 /* Ensure HOME and SHELL are defined. */
2107 if (home == NULL)
2108 emacs_abort ();
2109 if (shell == NULL)
2110 emacs_abort ();
2111 filename_from_utf16 (home, dflt_passwd.pw_dir);
2112 filename_from_utf16 (shell, dflt_passwd.pw_shell);
2114 else
2116 char *home = getenv ("HOME");
2117 char *shell = getenv ("SHELL");
2119 if (home == NULL)
2120 emacs_abort ();
2121 if (shell == NULL)
2122 emacs_abort ();
2123 filename_from_ansi (home, dflt_passwd.pw_dir);
2124 filename_from_ansi (shell, dflt_passwd.pw_shell);
2127 xfree (buf);
2128 if (token)
2129 CloseHandle (token);
2132 static HCRYPTPROV w32_crypto_hprov;
2133 static int
2134 w32_init_crypt_random (void)
2136 if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL,
2137 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2139 DebPrint (("CryptAcquireContext failed with error %x\n",
2140 GetLastError ()));
2141 w32_crypto_hprov = 0;
2142 return -1;
2144 return 0;
2148 w32_init_random (void *buf, ptrdiff_t buflen)
2150 if (!w32_crypto_hprov)
2151 w32_init_crypt_random ();
2152 if (w32_crypto_hprov)
2154 if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf))
2155 return 0;
2157 return -1;
2160 /* MS-Windows 'rand' produces separate identical series for each
2161 thread, so we replace it with our version. */
2163 /* Algorithm AS183: An Efficient and Portable Pseudo-random Number
2164 Generator, by B.A. Wichmann, I.D. Hill. AS, v31, No. 2 (1982). */
2165 static int ix = 3172, iy = 9814, iz = 20125;
2166 #define RAND_MAX_X 30269
2167 #define RAND_MAX_Y 30307
2168 #define RAND_MAX_Z 30323
2170 static int
2171 rand_as183 (void)
2173 ix = (171 * ix) % RAND_MAX_X;
2174 iy = (172 * iy) % RAND_MAX_Y;
2175 iz = (170 * iz) % RAND_MAX_Z;
2177 return (ix + iy + iz) & 0x7fff;
2181 random (void)
2183 /* rand_as183 () gives us 15 random bits...hack together 30 bits. */
2184 return ((rand_as183 () << 15) | rand_as183 ());
2187 void
2188 srandom (int seed)
2190 srand (seed);
2191 ix = rand () % RAND_MAX_X;
2192 iy = rand () % RAND_MAX_Y;
2193 iz = rand () % RAND_MAX_Z;
2196 /* Return the maximum length in bytes of a multibyte character
2197 sequence encoded in the current ANSI codepage. This is required to
2198 correctly walk the encoded file names one character at a time. */
2199 static int
2200 max_filename_mbslen (void)
2202 CPINFO cp_info;
2204 codepage_for_filenames (&cp_info);
2205 return cp_info.MaxCharSize;
2208 /* Normalize filename by converting in-place all of its path
2209 separators to the separator specified by PATH_SEP. */
2211 static void
2212 normalize_filename (register char *fp, char path_sep)
2214 char *p2;
2216 /* Always lower-case drive letters a-z, even if the filesystem
2217 preserves case in filenames.
2218 This is so filenames can be compared by string comparison
2219 functions that are case-sensitive. Even case-preserving filesystems
2220 do not distinguish case in drive letters. */
2221 p2 = fp + 1;
2223 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2225 *fp += 'a' - 'A';
2226 fp += 2;
2229 while (*fp)
2231 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2232 *fp = path_sep;
2233 fp++;
2237 /* Destructively turn backslashes into slashes. */
2238 void
2239 dostounix_filename (register char *p)
2241 normalize_filename (p, '/');
2244 /* Destructively turn slashes into backslashes. */
2245 void
2246 unixtodos_filename (register char *p)
2248 normalize_filename (p, '\\');
2251 /* Remove all CR's that are followed by a LF.
2252 (From msdos.c...probably should figure out a way to share it,
2253 although this code isn't going to ever change.) */
2254 static int
2255 crlf_to_lf (register int n, register char *buf)
2257 unsigned char *np = (unsigned char *)buf;
2258 unsigned char *startp = np;
2259 char *endp = buf + n;
2261 if (n == 0)
2262 return n;
2263 while (buf < endp - 1)
2265 if (*buf == 0x0d)
2267 if (*(++buf) != 0x0a)
2268 *np++ = 0x0d;
2270 else
2271 *np++ = *buf++;
2273 if (buf < endp)
2274 *np++ = *buf++;
2275 return np - startp;
2278 /* Parse the root part of file name, if present. Return length and
2279 optionally store pointer to char after root. */
2280 static int
2281 parse_root (const char * name, const char ** pPath)
2283 const char * start = name;
2285 if (name == NULL)
2286 return 0;
2288 /* find the root name of the volume if given */
2289 if (isalpha (name[0]) && name[1] == ':')
2291 /* skip past drive specifier */
2292 name += 2;
2293 if (IS_DIRECTORY_SEP (name[0]))
2294 name++;
2296 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2298 int slashes = 2;
2300 name += 2;
2303 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2304 break;
2305 name++;
2307 while ( *name );
2308 if (IS_DIRECTORY_SEP (name[0]))
2309 name++;
2312 if (pPath)
2313 *pPath = name;
2315 return name - start;
2318 /* Get long base name for name; name is assumed to be absolute. */
2319 static int
2320 get_long_basename (char * name, char * buf, int size)
2322 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2323 char fname_utf8[MAX_UTF8_PATH];
2324 int len = 0;
2325 int cstatus = -1;
2327 /* Must be valid filename, no wild cards or other invalid characters. */
2328 if (strpbrk (name, "*?|<>\""))
2329 return 0;
2331 if (w32_unicode_filenames)
2333 wchar_t fname_utf16[MAX_PATH];
2334 WIN32_FIND_DATAW find_data_wide;
2336 filename_to_utf16 (name, fname_utf16);
2337 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2338 if (dir_handle != INVALID_HANDLE_VALUE)
2339 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2341 else
2343 char fname_ansi[MAX_PATH];
2344 WIN32_FIND_DATAA find_data_ansi;
2346 filename_to_ansi (name, fname_ansi);
2347 /* If the ANSI name includes ? characters, it is not encodable
2348 in the ANSI codepage. In that case, we deliver the question
2349 marks to the caller; calling FindFirstFileA in this case
2350 could return some unrelated file name in the same
2351 directory. */
2352 if (_mbspbrk (fname_ansi, "?"))
2354 /* Find the basename of fname_ansi. */
2355 char *p = strrchr (fname_ansi, '\\');
2357 if (!p)
2358 p = fname_ansi;
2359 else
2360 p++;
2361 cstatus = filename_from_ansi (p, fname_utf8);
2363 else
2365 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2366 if (dir_handle != INVALID_HANDLE_VALUE)
2367 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2371 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2372 memcpy (buf, fname_utf8, len + 1);
2373 else
2374 len = 0;
2376 if (dir_handle != INVALID_HANDLE_VALUE)
2377 FindClose (dir_handle);
2379 return len;
2382 /* Get long name for file, if possible (assumed to be absolute). */
2383 BOOL
2384 w32_get_long_filename (const char * name, char * buf, int size)
2386 char * o = buf;
2387 char * p;
2388 const char * q;
2389 char full[ MAX_UTF8_PATH ];
2390 int len;
2392 len = strlen (name);
2393 if (len >= MAX_UTF8_PATH)
2394 return FALSE;
2396 /* Use local copy for destructive modification. */
2397 memcpy (full, name, len+1);
2398 unixtodos_filename (full);
2400 /* Copy root part verbatim. */
2401 len = parse_root (full, (const char **)&p);
2402 memcpy (o, full, len);
2403 o += len;
2404 *o = '\0';
2405 size -= len;
2407 while (p != NULL && *p)
2409 q = p;
2410 p = strchr (q, '\\');
2411 if (p) *p = '\0';
2412 len = get_long_basename (full, o, size);
2413 if (len > 0)
2415 o += len;
2416 size -= len;
2417 if (p != NULL)
2419 *p++ = '\\';
2420 if (size < 2)
2421 return FALSE;
2422 *o++ = '\\';
2423 size--;
2424 *o = '\0';
2427 else
2428 return FALSE;
2431 return TRUE;
2434 unsigned int
2435 w32_get_short_filename (const char * name, char * buf, int size)
2437 if (w32_unicode_filenames)
2439 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2440 unsigned int retval;
2442 filename_to_utf16 (name, name_utf16);
2443 retval = GetShortPathNameW (name_utf16, short_name, size);
2444 if (retval && retval < size)
2445 filename_from_utf16 (short_name, buf);
2446 return retval;
2448 else
2450 char name_ansi[MAX_PATH];
2452 filename_to_ansi (name, name_ansi);
2453 return GetShortPathNameA (name_ansi, buf, size);
2457 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2458 MS-Windows ANSI codepage. If FILENAME includes characters not
2459 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2460 if it exists. This is needed because the w32 build wants to
2461 support file names outside of the system locale, but image
2462 libraries typically don't support wide (a.k.a. "Unicode") APIs
2463 required for that. */
2465 Lisp_Object
2466 ansi_encode_filename (Lisp_Object filename)
2468 Lisp_Object encoded_filename;
2469 char fname[MAX_PATH];
2471 filename_to_ansi (SSDATA (filename), fname);
2472 if (_mbspbrk (fname, "?"))
2474 char shortname[MAX_PATH];
2476 if (w32_get_short_filename (SSDATA (filename), shortname, MAX_PATH))
2478 dostounix_filename (shortname);
2479 encoded_filename = build_string (shortname);
2481 else
2482 encoded_filename = build_unibyte_string (fname);
2484 else
2485 encoded_filename = build_unibyte_string (fname);
2486 return encoded_filename;
2489 static int
2490 is_unc_volume (const char *filename)
2492 const char *ptr = filename;
2494 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2495 return 0;
2497 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2498 return 0;
2500 return 1;
2503 /* Emulate the Posix unsetenv. */
2505 unsetenv (const char *name)
2507 char *var;
2508 size_t name_len;
2510 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2512 errno = EINVAL;
2513 return -1;
2515 name_len = strlen (name);
2516 /* MS docs says an environment variable cannot be longer than 32K. */
2517 if (name_len > 32767)
2519 errno = ENOMEM;
2520 return 0;
2522 /* It is safe to use 'alloca' with 32K size, since the stack is at
2523 least 2MB, and we set it to 8MB in the link command line. */
2524 var = alloca (name_len + 2);
2525 strncpy (var, name, name_len);
2526 var[name_len++] = '=';
2527 var[name_len] = '\0';
2528 return _putenv (var);
2531 /* MS _putenv doesn't support removing a variable when the argument
2532 does not include the '=' character, so we fix that here. */
2534 sys_putenv (char *str)
2536 const char *const name_end = strchr (str, '=');
2538 if (name_end == NULL)
2540 /* Remove the variable from the environment. */
2541 return unsetenv (str);
2544 if (strncmp (str, "TZ=<", 4) == 0)
2546 /* MS-Windows does not support POSIX.1-2001 angle-bracket TZ
2547 abbreviation syntax. Convert to POSIX.1-1988 syntax if possible,
2548 and to the undocumented placeholder "ZZZ" otherwise. */
2549 bool supported_abbr = true;
2550 for (char *p = str + 4; *p; p++)
2552 if (('0' <= *p && *p <= '9') || *p == '-' || *p == '+')
2553 supported_abbr = false;
2554 else if (*p == '>')
2556 ptrdiff_t abbrlen;
2557 if (supported_abbr)
2559 abbrlen = p - (str + 4);
2560 memmove (str + 3, str + 4, abbrlen);
2562 else
2564 abbrlen = 3;
2565 memset (str + 3, 'Z', abbrlen);
2567 memmove (str + 3 + abbrlen, p + 1, strlen (p));
2568 break;
2573 return _putenv (str);
2576 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2578 LPBYTE
2579 w32_get_resource (const char *key, LPDWORD lpdwtype)
2581 LPBYTE lpvalue;
2582 HKEY hrootkey = NULL;
2583 DWORD cbData;
2585 /* Check both the current user and the local machine to see if
2586 we have any resources. */
2588 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2590 lpvalue = NULL;
2592 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2593 && (lpvalue = xmalloc (cbData)) != NULL
2594 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2596 RegCloseKey (hrootkey);
2597 return (lpvalue);
2600 xfree (lpvalue);
2602 RegCloseKey (hrootkey);
2605 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2607 lpvalue = NULL;
2609 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2610 && (lpvalue = xmalloc (cbData)) != NULL
2611 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2613 RegCloseKey (hrootkey);
2614 return (lpvalue);
2617 xfree (lpvalue);
2619 RegCloseKey (hrootkey);
2622 return (NULL);
2625 /* The argv[] array holds ANSI-encoded strings, and so this function
2626 works with ANS_encoded strings. */
2627 void
2628 init_environment (char ** argv)
2630 static const char * const tempdirs[] = {
2631 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2634 int i;
2636 const int imax = ARRAYELTS (tempdirs);
2638 /* Implementation note: This function explicitly works with ANSI
2639 file names, not with UTF-8 encoded file names. This is because
2640 this function pushes variables into the Emacs's environment, and
2641 the environment variables are always assumed to be in the
2642 locale-specific encoding. Do NOT call any functions that accept
2643 UTF-8 file names from this function! */
2645 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2646 temporary files and assume "/tmp" if $TMPDIR is unset, which
2647 will break on DOS/Windows. Refuse to work if we cannot find
2648 a directory, not even "c:/", usable for that purpose. */
2649 for (i = 0; i < imax ; i++)
2651 const char *tmp = tempdirs[i];
2653 if (*tmp == '$')
2654 tmp = getenv (tmp + 1);
2655 /* Note that `access' can lie to us if the directory resides on a
2656 read-only filesystem, like CD-ROM or a write-protected floppy.
2657 The only way to be really sure is to actually create a file and
2658 see if it succeeds. But I think that's too much to ask. */
2660 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2661 if (tmp && sys_access (tmp, D_OK) == 0)
2663 char * var = alloca (strlen (tmp) + 8);
2664 sprintf (var, "TMPDIR=%s", tmp);
2665 _putenv (strdup (var));
2666 break;
2669 if (i >= imax)
2670 cmd_error_internal
2671 (Fcons (Qerror,
2672 Fcons (build_string ("no usable temporary directories found!!"),
2673 Qnil)),
2674 "While setting TMPDIR: ");
2676 /* Check for environment variables and use registry settings if they
2677 don't exist. Fallback on default values where applicable. */
2679 int i;
2680 LPBYTE lpval;
2681 DWORD dwType;
2682 char locale_name[32];
2683 char default_home[MAX_PATH];
2684 int appdata = 0;
2686 static const struct env_entry
2688 const char * name;
2689 const char * def_value;
2690 } dflt_envvars[] =
2692 /* If the default value is NULL, we will use the value from the
2693 outside environment or the Registry, but will not push the
2694 variable into the Emacs environment if it is defined neither
2695 in the Registry nor in the outside environment. */
2696 {"HOME", "C:/"},
2697 {"PRELOAD_WINSOCK", NULL},
2698 {"emacs_dir", "C:/emacs"},
2699 {"EMACSLOADPATH", NULL},
2700 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2701 {"EMACSDATA", NULL},
2702 {"EMACSPATH", NULL},
2703 {"INFOPATH", NULL},
2704 {"EMACSDOC", NULL},
2705 {"TERM", "cmd"},
2706 {"LANG", NULL},
2709 #define N_ENV_VARS ARRAYELTS (dflt_envvars)
2711 /* We need to copy dflt_envvars[] and work on the copy because we
2712 don't want the dumped Emacs to inherit the values of
2713 environment variables we saw during dumping (which could be on
2714 a different system). The defaults above must be left intact. */
2715 struct env_entry env_vars[N_ENV_VARS];
2717 for (i = 0; i < N_ENV_VARS; i++)
2718 env_vars[i] = dflt_envvars[i];
2720 /* For backwards compatibility, check if a .emacs file exists in C:/
2721 If not, then we can try to default to the appdata directory under the
2722 user's profile, which is more likely to be writable. */
2723 if (sys_access ("C:/.emacs", F_OK) != 0)
2725 HRESULT profile_result;
2726 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2727 of Windows 95 and NT4 that have not been updated to include
2728 MSIE 5. */
2729 ShGetFolderPath_fn get_folder_path;
2730 get_folder_path = (ShGetFolderPath_fn)
2731 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2733 if (get_folder_path != NULL)
2735 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2736 0, default_home);
2738 /* If we can't get the appdata dir, revert to old behavior. */
2739 if (profile_result == S_OK)
2741 env_vars[0].def_value = default_home;
2742 appdata = 1;
2747 /* Get default locale info and use it for LANG. */
2748 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2749 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2750 locale_name, sizeof (locale_name)))
2752 for (i = 0; i < N_ENV_VARS; i++)
2754 if (strcmp (env_vars[i].name, "LANG") == 0)
2756 env_vars[i].def_value = locale_name;
2757 break;
2762 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2764 /* Treat emacs_dir specially: set it unconditionally based on our
2765 location. */
2767 char *p;
2768 char modname[MAX_PATH];
2770 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2771 emacs_abort ();
2772 if ((p = _mbsrchr (modname, '\\')) == NULL)
2773 emacs_abort ();
2774 *p = 0;
2776 if ((p = _mbsrchr (modname, '\\'))
2777 /* From bin means installed Emacs, from src means uninstalled. */
2778 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2780 char buf[SET_ENV_BUF_SIZE];
2781 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2783 *p = 0;
2784 for (p = modname; *p; p = CharNext (p))
2785 if (*p == '\\') *p = '/';
2787 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2788 _putenv (strdup (buf));
2789 /* If we are running from the Posix-like build tree, define
2790 SHELL to point to our own cmdproxy. The loop below will
2791 then disregard PATH_EXEC and the default value. */
2792 if (within_build_tree)
2794 _snprintf (buf, sizeof (buf) - 1,
2795 "SHELL=%s/nt/cmdproxy.exe", modname);
2796 _putenv (strdup (buf));
2801 for (i = 0; i < N_ENV_VARS; i++)
2803 if (!getenv (env_vars[i].name))
2805 int dont_free = 0;
2806 char bufc[SET_ENV_BUF_SIZE];
2808 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2809 /* Also ignore empty environment variables. */
2810 || *lpval == 0)
2812 xfree (lpval);
2813 dont_free = 1;
2814 if (strcmp (env_vars[i].name, "SHELL") == 0)
2816 /* Look for cmdproxy.exe in every directory in
2817 PATH_EXEC. FIXME: This does not find cmdproxy
2818 in nt/ when we run uninstalled. */
2819 char fname[MAX_PATH];
2820 const char *pstart = PATH_EXEC, *pend;
2822 do {
2823 pend = _mbschr (pstart, ';');
2824 if (!pend)
2825 pend = pstart + strlen (pstart);
2826 /* Be defensive against series of ;;; characters. */
2827 if (pend > pstart)
2829 strncpy (fname, pstart, pend - pstart);
2830 fname[pend - pstart] = '/';
2831 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2832 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2833 sizeof (bufc));
2834 if (sys_access (bufc, F_OK) == 0)
2836 lpval = bufc;
2837 dwType = REG_SZ;
2838 break;
2841 if (*pend)
2842 pstart = pend + 1;
2843 else
2844 pstart = pend;
2845 if (!*pstart)
2847 /* If not found in any directory, use the
2848 default as the last resort. */
2849 lpval = (char *)env_vars[i].def_value;
2850 dwType = REG_EXPAND_SZ;
2852 } while (*pstart);
2854 else
2856 lpval = (char *)env_vars[i].def_value;
2857 dwType = REG_EXPAND_SZ;
2859 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2860 Vdelayed_warnings_list
2861 = Fcons
2862 (listn (CONSTYPE_HEAP, 2,
2863 intern ("initialization"), build_string
2864 ("Use of `C:\\.emacs' without defining `HOME'\n"
2865 "in the environment is deprecated, "
2866 "see `Windows HOME' in the Emacs manual.")),
2867 Vdelayed_warnings_list);
2870 if (lpval)
2872 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2874 if (dwType == REG_EXPAND_SZ)
2875 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2876 else if (dwType == REG_SZ)
2877 strcpy (buf1, (char *)lpval);
2878 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2880 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2881 buf1);
2882 _putenv (strdup (buf2));
2885 if (!dont_free)
2886 xfree (lpval);
2892 /* Rebuild system configuration to reflect invoking system. */
2893 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2895 /* Another special case: on NT, the PATH variable is actually named
2896 "Path" although cmd.exe (perhaps NT itself) arranges for
2897 environment variable lookup and setting to be case insensitive.
2898 However, Emacs assumes a fully case sensitive environment, so we
2899 need to change "Path" to "PATH" to match the expectations of
2900 various elisp packages. We do this by the sneaky method of
2901 modifying the string in the C runtime environ entry.
2903 The same applies to COMSPEC. */
2905 char ** envp;
2906 const char *path = "PATH=";
2907 int path_len = strlen (path);
2908 const char *comspec = "COMSPEC=";
2909 int comspec_len = strlen (comspec);
2911 for (envp = environ; *envp; envp++)
2912 if (_strnicmp (*envp, path, path_len) == 0)
2913 memcpy (*envp, path, path_len);
2914 else if (_strnicmp (*envp, comspec, comspec_len) == 0)
2915 memcpy (*envp, comspec, comspec_len);
2917 /* Make the same modification to `process-environment' which has
2918 already been initialized in set_initial_environment. */
2919 for (Lisp_Object env = Vprocess_environment; CONSP (env); env = XCDR (env))
2921 Lisp_Object entry = XCAR (env);
2922 if (_strnicmp (SDATA (entry), path, path_len) == 0)
2923 for (int i = 0; i < path_len; i++)
2924 SSET (entry, i, path[i]);
2925 else if (_strnicmp (SDATA (entry), comspec, comspec_len) == 0)
2926 for (int i = 0; i < comspec_len; i++)
2927 SSET (entry, i, comspec[i]);
2931 /* Remember the initial working directory for getcwd. */
2932 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2933 Does it matter anywhere in Emacs? */
2934 if (w32_unicode_filenames)
2936 wchar_t wstartup_dir[MAX_PATH];
2938 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2939 emacs_abort ();
2940 filename_from_utf16 (wstartup_dir, startup_dir);
2942 else
2944 char astartup_dir[MAX_PATH];
2946 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2947 emacs_abort ();
2948 filename_from_ansi (astartup_dir, startup_dir);
2952 static char modname[MAX_PATH];
2954 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2955 emacs_abort ();
2956 argv[0] = modname;
2959 /* Determine if there is a middle mouse button, to allow parse_button
2960 to decide whether right mouse events should be mouse-2 or
2961 mouse-3. */
2962 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2964 init_user_info ();
2967 /* Called from expand-file-name when default-directory is not a string. */
2969 char *
2970 emacs_root_dir (void)
2972 static char root_dir[MAX_UTF8_PATH];
2973 const char *p;
2975 p = getenv ("emacs_dir");
2976 if (p == NULL)
2977 emacs_abort ();
2978 filename_from_ansi (p, root_dir);
2979 root_dir[parse_root (root_dir, NULL)] = '\0';
2980 dostounix_filename (root_dir);
2981 return root_dir;
2984 /* Emulate fdutimens. */
2986 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2987 TIMESPEC[0] and TIMESPEC[1], respectively.
2988 FD must be either negative -- in which case it is ignored --
2989 or a file descriptor that is open on FILE.
2990 If FD is nonnegative, then FILE can be NULL, which means
2991 use just futimes instead of utimes.
2992 If TIMESPEC is null, FAIL.
2993 Return 0 on success, -1 (setting errno) on failure. */
2996 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2998 if (!timespec)
3000 errno = ENOSYS;
3001 return -1;
3003 if (fd < 0 && !file)
3005 errno = EBADF;
3006 return -1;
3008 /* _futime's prototype defines 2nd arg as having the type 'struct
3009 _utimbuf', while utime needs to accept 'struct utimbuf' for
3010 compatibility with Posix. So we need to use 2 different (but
3011 equivalent) types to avoid compiler warnings, sigh. */
3012 if (fd >= 0)
3014 struct _utimbuf _ut;
3016 _ut.actime = timespec[0].tv_sec;
3017 _ut.modtime = timespec[1].tv_sec;
3018 return _futime (fd, &_ut);
3020 else
3022 struct utimbuf ut;
3024 ut.actime = timespec[0].tv_sec;
3025 ut.modtime = timespec[1].tv_sec;
3026 /* Call 'utime', which is implemented below, not the MS library
3027 function, which fails on directories. */
3028 return utime (file, &ut);
3033 /* ------------------------------------------------------------------------- */
3034 /* IO support and wrapper functions for the Windows API. */
3035 /* ------------------------------------------------------------------------- */
3037 /* Place a wrapper around the MSVC version of ctime. It returns NULL
3038 on network directories, so we handle that case here.
3039 (Ulrich Leodolter, 1/11/95). */
3040 char *
3041 sys_ctime (const time_t *t)
3043 char *str = (char *) ctime (t);
3044 return (str ? str : (char *)"Sun Jan 01 00:00:00 1970");
3047 /* Emulate sleep...we could have done this with a define, but that
3048 would necessitate including windows.h in the files that used it.
3049 This is much easier. */
3050 void
3051 sys_sleep (int seconds)
3053 Sleep (seconds * 1000);
3056 /* Internal MSVC functions for low-level descriptor munging */
3057 extern int __cdecl _set_osfhnd (int fd, long h);
3058 extern int __cdecl _free_osfhnd (int fd);
3060 /* parallel array of private info on file handles */
3061 filedesc fd_info [ MAXDESC ];
3063 typedef struct volume_info_data {
3064 struct volume_info_data * next;
3066 /* time when info was obtained */
3067 DWORD timestamp;
3069 /* actual volume info */
3070 char * root_dir;
3071 DWORD serialnum;
3072 DWORD maxcomp;
3073 DWORD flags;
3074 char * name;
3075 char * type;
3076 } volume_info_data;
3078 /* Global referenced by various functions. */
3079 static volume_info_data volume_info;
3081 /* Vector to indicate which drives are local and fixed (for which cached
3082 data never expires). */
3083 static BOOL fixed_drives[26];
3085 /* Consider cached volume information to be stale if older than 10s,
3086 at least for non-local drives. Info for fixed drives is never stale. */
3087 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
3088 #define VOLINFO_STILL_VALID( root_dir, info ) \
3089 ( ( isalpha (root_dir[0]) && \
3090 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
3091 || GetTickCount () - info->timestamp < 10000 )
3093 /* Cache support functions. */
3095 /* Simple linked list with linear search is sufficient. */
3096 static volume_info_data *volume_cache = NULL;
3098 static volume_info_data *
3099 lookup_volume_info (char * root_dir)
3101 volume_info_data * info;
3103 for (info = volume_cache; info; info = info->next)
3104 if (xstrcasecmp (info->root_dir, root_dir) == 0)
3105 break;
3106 return info;
3109 static void
3110 add_volume_info (char * root_dir, volume_info_data * info)
3112 info->root_dir = xstrdup (root_dir);
3113 unixtodos_filename (info->root_dir);
3114 info->next = volume_cache;
3115 volume_cache = info;
3119 /* Wrapper for GetVolumeInformation, which uses caching to avoid
3120 performance penalty (~2ms on 486 for local drives, 7.5ms for local
3121 cdrom drive, ~5-10ms or more for remote drives on LAN). */
3122 static volume_info_data *
3123 GetCachedVolumeInformation (char * root_dir)
3125 volume_info_data * info;
3126 char default_root[ MAX_UTF8_PATH ];
3127 char name[MAX_PATH+1];
3128 char type[MAX_PATH+1];
3130 /* NULL for root_dir means use root from current directory. */
3131 if (root_dir == NULL)
3133 if (w32_unicode_filenames)
3135 wchar_t curdirw[MAX_PATH];
3137 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
3138 return NULL;
3139 filename_from_utf16 (curdirw, default_root);
3141 else
3143 char curdira[MAX_PATH];
3145 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
3146 return NULL;
3147 filename_from_ansi (curdira, default_root);
3149 parse_root (default_root, (const char **)&root_dir);
3150 *root_dir = 0;
3151 root_dir = default_root;
3154 /* Local fixed drives can be cached permanently. Removable drives
3155 cannot be cached permanently, since the volume name and serial
3156 number (if nothing else) can change. Remote drives should be
3157 treated as if they are removable, since there is no sure way to
3158 tell whether they are or not. Also, the UNC association of drive
3159 letters mapped to remote volumes can be changed at any time (even
3160 by other processes) without notice.
3162 As a compromise, so we can benefit from caching info for remote
3163 volumes, we use a simple expiry mechanism to invalidate cache
3164 entries that are more than ten seconds old. */
3166 #if 0
3167 /* No point doing this, because WNetGetConnection is even slower than
3168 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
3169 GetDriveType is about the only call of this type which does not
3170 involve network access, and so is extremely quick). */
3172 /* Map drive letter to UNC if remote. */
3173 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
3175 char remote_name[ 256 ];
3176 char drive[3] = { root_dir[0], ':' };
3178 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
3179 == NO_ERROR)
3180 /* do something */ ;
3182 #endif
3184 info = lookup_volume_info (root_dir);
3186 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
3188 DWORD serialnum;
3189 DWORD maxcomp;
3190 DWORD flags;
3192 /* Info is not cached, or is stale. */
3193 if (w32_unicode_filenames)
3195 wchar_t root_w[MAX_PATH];
3196 wchar_t name_w[MAX_PATH+1];
3197 wchar_t type_w[MAX_PATH+1];
3199 filename_to_utf16 (root_dir, root_w);
3200 if (!GetVolumeInformationW (root_w,
3201 name_w, sizeof (name_w),
3202 &serialnum,
3203 &maxcomp,
3204 &flags,
3205 type_w, sizeof (type_w)))
3206 return NULL;
3207 /* Hmm... not really 100% correct, as these 2 are not file
3208 names... */
3209 filename_from_utf16 (name_w, name);
3210 filename_from_utf16 (type_w, type);
3212 else
3214 char root_a[MAX_PATH];
3215 char name_a[MAX_PATH+1];
3216 char type_a[MAX_PATH+1];
3218 filename_to_ansi (root_dir, root_a);
3219 if (!GetVolumeInformationA (root_a,
3220 name_a, sizeof (name_a),
3221 &serialnum,
3222 &maxcomp,
3223 &flags,
3224 type_a, sizeof (type_a)))
3225 return NULL;
3226 filename_from_ansi (name_a, name);
3227 filename_from_ansi (type_a, type);
3230 /* Cache the volume information for future use, overwriting existing
3231 entry if present. */
3232 if (info == NULL)
3234 info = xmalloc (sizeof (volume_info_data));
3235 add_volume_info (root_dir, info);
3237 else
3239 xfree (info->name);
3240 xfree (info->type);
3243 info->name = xstrdup (name);
3244 unixtodos_filename (info->name);
3245 info->serialnum = serialnum;
3246 info->maxcomp = maxcomp;
3247 info->flags = flags;
3248 info->type = xstrdup (type);
3249 info->timestamp = GetTickCount ();
3252 return info;
3255 /* Get information on the volume where NAME is held; set path pointer to
3256 start of pathname in NAME (past UNC header\volume header if present),
3257 if pPath is non-NULL.
3259 Note: if NAME includes symlinks, the information is for the volume
3260 of the symlink, not of its target. That's because, even though
3261 GetVolumeInformation returns information about the symlink target
3262 of its argument, we only pass the root directory to
3263 GetVolumeInformation, not the full NAME. */
3264 static int
3265 get_volume_info (const char * name, const char ** pPath)
3267 char temp[MAX_UTF8_PATH];
3268 char *rootname = NULL; /* default to current volume */
3269 volume_info_data * info;
3270 int root_len = parse_root (name, pPath);
3272 if (name == NULL)
3273 return FALSE;
3275 /* Copy the root name of the volume, if given. */
3276 if (root_len)
3278 strncpy (temp, name, root_len);
3279 temp[root_len] = '\0';
3280 unixtodos_filename (temp);
3281 rootname = temp;
3284 info = GetCachedVolumeInformation (rootname);
3285 if (info != NULL)
3287 /* Set global referenced by other functions. */
3288 volume_info = *info;
3289 return TRUE;
3291 return FALSE;
3294 /* Determine if volume is FAT format (ie. only supports short 8.3
3295 names); also set path pointer to start of pathname in name, if
3296 pPath is non-NULL. */
3297 static int
3298 is_fat_volume (const char * name, const char ** pPath)
3300 if (get_volume_info (name, pPath))
3301 return (volume_info.maxcomp == 12);
3302 return FALSE;
3305 /* Convert all slashes in a filename to backslashes, and map filename
3306 to a valid 8.3 name if necessary. The result is a pointer to a
3307 static buffer, so CAVEAT EMPTOR! */
3308 const char *map_w32_filename (const char *, const char **);
3310 const char *
3311 map_w32_filename (const char * name, const char ** pPath)
3313 static char shortname[MAX_UTF8_PATH];
3314 char * str = shortname;
3315 char c;
3316 char * path;
3317 const char * save_name = name;
3319 if (strlen (name) >= sizeof (shortname))
3321 /* Return a filename which will cause callers to fail. */
3322 strcpy (shortname, "?");
3323 return shortname;
3326 if (!fatal_error_in_progress /* disable fancy processing during crash */
3327 && is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3329 register int left = 8; /* maximum number of chars in part */
3330 register int extn = 0; /* extension added? */
3331 register int dots = 2; /* maximum number of dots allowed */
3333 while (name < path)
3334 *str++ = *name++; /* skip past UNC header */
3336 while ((c = *name++))
3338 switch ( c )
3340 case ':':
3341 case '\\':
3342 case '/':
3343 *str++ = (c == ':' ? ':' : '\\');
3344 extn = 0; /* reset extension flags */
3345 dots = 2; /* max 2 dots */
3346 left = 8; /* max length 8 for main part */
3347 break;
3348 case '.':
3349 if ( dots )
3351 /* Convert path components of the form .xxx to _xxx,
3352 but leave . and .. as they are. This allows .emacs
3353 to be read as _emacs, for example. */
3355 if (! *name ||
3356 *name == '.' ||
3357 IS_DIRECTORY_SEP (*name))
3359 *str++ = '.';
3360 dots--;
3362 else
3364 *str++ = '_';
3365 left--;
3366 dots = 0;
3369 else if ( !extn )
3371 *str++ = '.';
3372 extn = 1; /* we've got an extension */
3373 left = 3; /* 3 chars in extension */
3375 else
3377 /* any embedded dots after the first are converted to _ */
3378 *str++ = '_';
3380 break;
3381 case '~':
3382 case '#': /* don't lose these, they're important */
3383 if ( ! left )
3384 str[-1] = c; /* replace last character of part */
3385 /* FALLTHRU */
3386 FALLTHROUGH;
3387 default:
3388 if ( left && 'A' <= c && c <= 'Z' )
3390 *str++ = tolower (c); /* map to lower case (looks nicer) */
3391 left--;
3392 dots = 0; /* started a path component */
3394 break;
3397 *str = '\0';
3399 else
3401 strcpy (shortname, name);
3402 unixtodos_filename (shortname);
3405 if (pPath)
3406 *pPath = shortname + (path - save_name);
3408 return shortname;
3411 static int
3412 is_exec (const char * name)
3414 char * p = strrchr (name, '.');
3415 return
3416 (p != NULL
3417 && (xstrcasecmp (p, ".exe") == 0 ||
3418 xstrcasecmp (p, ".com") == 0 ||
3419 xstrcasecmp (p, ".bat") == 0 ||
3420 xstrcasecmp (p, ".cmd") == 0));
3423 /* Emulate the Unix directory procedures opendir, closedir, and
3424 readdir. We rename them to sys_* names because some versions of
3425 MinGW startup code call opendir and readdir to glob wildcards, and
3426 the code that calls them doesn't grok UTF-8 encoded file names we
3427 produce in dirent->d_name[]. */
3429 struct dirent dir_static; /* simulated directory contents */
3430 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3431 static int dir_is_fat;
3432 static char dir_pathname[MAX_UTF8_PATH];
3433 static WIN32_FIND_DATAW dir_find_data_w;
3434 static WIN32_FIND_DATAA dir_find_data_a;
3435 #define DIR_FIND_DATA_W 1
3436 #define DIR_FIND_DATA_A 2
3437 static int last_dir_find_data = -1;
3439 /* Support shares on a network resource as subdirectories of a read-only
3440 root directory. */
3441 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3442 static HANDLE open_unc_volume (const char *);
3443 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3444 static void close_unc_volume (HANDLE);
3446 DIR *
3447 sys_opendir (const char *filename)
3449 DIR *dirp;
3451 /* Opening is done by FindFirstFile. However, a read is inherent to
3452 this operation, so we defer the open until read time. */
3454 if (dir_find_handle != INVALID_HANDLE_VALUE)
3455 return NULL;
3456 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3457 return NULL;
3459 /* Note: We don't support traversal of UNC volumes via symlinks.
3460 Doing so would mean punishing 99.99% of use cases by resolving
3461 all the possible symlinks in FILENAME, recursively. */
3462 if (is_unc_volume (filename))
3464 wnet_enum_handle = open_unc_volume (filename);
3465 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3466 return NULL;
3469 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3470 return NULL;
3472 dirp->dd_fd = 0;
3473 dirp->dd_loc = 0;
3474 dirp->dd_size = 0;
3476 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3477 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3478 /* Note: We don't support symlinks to file names on FAT volumes.
3479 Doing so would mean punishing 99.99% of use cases by resolving
3480 all the possible symlinks in FILENAME, recursively. */
3481 dir_is_fat = is_fat_volume (filename, NULL);
3483 return dirp;
3486 void
3487 sys_closedir (DIR *dirp)
3489 /* If we have a find-handle open, close it. */
3490 if (dir_find_handle != INVALID_HANDLE_VALUE)
3492 FindClose (dir_find_handle);
3493 dir_find_handle = INVALID_HANDLE_VALUE;
3495 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3497 close_unc_volume (wnet_enum_handle);
3498 wnet_enum_handle = INVALID_HANDLE_VALUE;
3500 xfree ((char *) dirp);
3503 struct dirent *
3504 sys_readdir (DIR *dirp)
3506 int downcase = !NILP (Vw32_downcase_file_names);
3508 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3510 if (!read_unc_volume (wnet_enum_handle,
3511 dir_find_data_w.cFileName,
3512 dir_find_data_a.cFileName,
3513 MAX_PATH))
3514 return NULL;
3516 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3517 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3519 char filename[MAX_UTF8_PATH];
3520 int ln;
3521 bool last_slash = true;
3523 /* Note: We don't need to worry about dir_pathname being longer
3524 than MAX_UTF8_PATH, as sys_opendir already took care of that
3525 when it called map_w32_filename: that function will put a "?"
3526 in its return value in that case, thus failing all the calls
3527 below. */
3528 strcpy (filename, dir_pathname);
3529 ln = strlen (filename);
3530 if (!IS_DIRECTORY_SEP (filename[ln - 1]))
3531 last_slash = false;
3533 /* Note: No need to resolve symlinks in FILENAME, because
3534 FindFirst opens the directory that is the target of a
3535 symlink. */
3536 if (w32_unicode_filenames)
3538 wchar_t fnw[MAX_PATH + 2];
3540 filename_to_utf16 (filename, fnw);
3541 if (!last_slash)
3542 wcscat (fnw, L"\\");
3543 wcscat (fnw, L"*");
3544 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3546 else
3548 char fna[MAX_PATH + 2];
3550 filename_to_ansi (filename, fna);
3551 if (!last_slash)
3552 strcat (fna, "\\");
3553 strcat (fna, "*");
3554 /* If FILENAME is not representable by the current ANSI
3555 codepage, we don't want FindFirstFileA to interpret the
3556 '?' characters as a wildcard. */
3557 if (_mbspbrk (fna, "?"))
3558 dir_find_handle = INVALID_HANDLE_VALUE;
3559 else
3560 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3563 if (dir_find_handle == INVALID_HANDLE_VALUE)
3565 /* Any changes in the value of errno here should be in sync
3566 with what directory_files_internal does when it calls
3567 readdir. */
3568 switch (GetLastError ())
3570 /* Windows uses this value when FindFirstFile finds no
3571 files that match the wildcard. This is not supposed
3572 to happen, since our wildcard is "*", but just in
3573 case, if there's some weird empty directory with not
3574 even "." and ".." entries... */
3575 case ERROR_FILE_NOT_FOUND:
3576 errno = 0;
3577 /* FALLTHRU */
3578 default:
3579 break;
3580 case ERROR_ACCESS_DENIED:
3581 case ERROR_NETWORK_ACCESS_DENIED:
3582 errno = EACCES;
3583 break;
3584 case ERROR_PATH_NOT_FOUND:
3585 case ERROR_INVALID_DRIVE:
3586 case ERROR_NOT_READY:
3587 case ERROR_BAD_NETPATH:
3588 case ERROR_BAD_NET_NAME:
3589 errno = ENOENT;
3590 break;
3592 return NULL;
3595 else if (w32_unicode_filenames)
3597 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3599 errno = 0;
3600 return NULL;
3603 else
3605 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3607 errno = 0;
3608 return NULL;
3612 /* Emacs never uses this value, so don't bother making it match
3613 value returned by stat(). */
3614 dir_static.d_ino = 1;
3616 if (w32_unicode_filenames)
3618 if (downcase || dir_is_fat)
3620 wchar_t tem[MAX_PATH];
3622 wcscpy (tem, dir_find_data_w.cFileName);
3623 CharLowerW (tem);
3624 filename_from_utf16 (tem, dir_static.d_name);
3626 else
3627 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3628 last_dir_find_data = DIR_FIND_DATA_W;
3630 else
3632 char tem[MAX_PATH];
3634 /* If the file name in cFileName[] includes `?' characters, it
3635 means the original file name used characters that cannot be
3636 represented by the current ANSI codepage. To avoid total
3637 lossage, retrieve the short 8+3 alias of the long file
3638 name. */
3639 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3641 strcpy (tem, dir_find_data_a.cAlternateFileName);
3642 /* 8+3 aliases are returned in all caps, which could break
3643 various alists that look at filenames' extensions. */
3644 downcase = 1;
3646 else if (downcase || dir_is_fat)
3647 strcpy (tem, dir_find_data_a.cFileName);
3648 else
3649 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3650 if (downcase || dir_is_fat)
3652 _mbslwr (tem);
3653 filename_from_ansi (tem, dir_static.d_name);
3655 last_dir_find_data = DIR_FIND_DATA_A;
3658 dir_static.d_namlen = strlen (dir_static.d_name);
3659 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3660 dir_static.d_namlen - dir_static.d_namlen % 4;
3662 return &dir_static;
3665 static HANDLE
3666 open_unc_volume (const char *path)
3668 const char *fn = map_w32_filename (path, NULL);
3669 DWORD result;
3670 HANDLE henum;
3672 if (w32_unicode_filenames)
3674 NETRESOURCEW nrw;
3675 wchar_t fnw[MAX_PATH];
3677 nrw.dwScope = RESOURCE_GLOBALNET;
3678 nrw.dwType = RESOURCETYPE_DISK;
3679 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3680 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3681 nrw.lpLocalName = NULL;
3682 filename_to_utf16 (fn, fnw);
3683 nrw.lpRemoteName = fnw;
3684 nrw.lpComment = NULL;
3685 nrw.lpProvider = NULL;
3687 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3688 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3690 else
3692 NETRESOURCEA nra;
3693 char fna[MAX_PATH];
3695 nra.dwScope = RESOURCE_GLOBALNET;
3696 nra.dwType = RESOURCETYPE_DISK;
3697 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3698 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3699 nra.lpLocalName = NULL;
3700 filename_to_ansi (fn, fna);
3701 nra.lpRemoteName = fna;
3702 nra.lpComment = NULL;
3703 nra.lpProvider = NULL;
3705 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3706 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3708 if (result == NO_ERROR)
3709 return henum;
3710 else
3712 /* Make sure directory_files_internal reports a sensible error. */
3713 errno = ENOENT;
3714 return INVALID_HANDLE_VALUE;
3718 static void *
3719 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3721 DWORD count;
3722 int result;
3723 char *buffer;
3724 DWORD bufsize = 512;
3725 void *retval;
3727 count = 1;
3728 if (w32_unicode_filenames)
3730 wchar_t *ptrw;
3732 bufsize *= 2;
3733 buffer = alloca (bufsize);
3734 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3735 if (result != NO_ERROR)
3736 return NULL;
3737 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3738 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3739 ptrw += 2;
3740 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3741 ptrw++;
3742 wcsncpy (fname_w, ptrw, size);
3743 retval = fname_w;
3745 else
3747 int dbcs_p = max_filename_mbslen () > 1;
3748 char *ptra;
3750 buffer = alloca (bufsize);
3751 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3752 if (result != NO_ERROR)
3753 return NULL;
3754 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3755 ptra += 2;
3756 if (!dbcs_p)
3757 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3758 else
3760 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3761 ptra = CharNextExA (file_name_codepage, ptra, 0);
3763 ptra++;
3764 strncpy (fname_a, ptra, size);
3765 retval = fname_a;
3768 return retval;
3771 static void
3772 close_unc_volume (HANDLE henum)
3774 if (henum != INVALID_HANDLE_VALUE)
3775 WNetCloseEnum (henum);
3778 static DWORD
3779 unc_volume_file_attributes (const char *path)
3781 HANDLE henum;
3782 DWORD attrs;
3784 henum = open_unc_volume (path);
3785 if (henum == INVALID_HANDLE_VALUE)
3786 return -1;
3788 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3790 close_unc_volume (henum);
3792 return attrs;
3795 /* Ensure a network connection is authenticated. */
3796 static void
3797 logon_network_drive (const char *path)
3799 char share[MAX_UTF8_PATH];
3800 int n_slashes;
3801 char drive[4];
3802 UINT drvtype;
3803 char *p;
3804 DWORD val;
3806 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3807 drvtype = DRIVE_REMOTE;
3808 else if (path[0] == '\0' || path[1] != ':')
3809 drvtype = GetDriveType (NULL);
3810 else
3812 drive[0] = path[0];
3813 drive[1] = ':';
3814 drive[2] = '\\';
3815 drive[3] = '\0';
3816 drvtype = GetDriveType (drive);
3819 /* Only logon to networked drives. */
3820 if (drvtype != DRIVE_REMOTE)
3821 return;
3823 n_slashes = 2;
3824 strncpy (share, path, MAX_UTF8_PATH);
3825 /* Truncate to just server and share name. */
3826 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3828 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3830 *p = '\0';
3831 break;
3835 if (w32_unicode_filenames)
3837 NETRESOURCEW resourcew;
3838 wchar_t share_w[MAX_PATH];
3840 resourcew.dwScope = RESOURCE_GLOBALNET;
3841 resourcew.dwType = RESOURCETYPE_DISK;
3842 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3843 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3844 resourcew.lpLocalName = NULL;
3845 filename_to_utf16 (share, share_w);
3846 resourcew.lpRemoteName = share_w;
3847 resourcew.lpProvider = NULL;
3849 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3851 else
3853 NETRESOURCEA resourcea;
3854 char share_a[MAX_PATH];
3856 resourcea.dwScope = RESOURCE_GLOBALNET;
3857 resourcea.dwType = RESOURCETYPE_DISK;
3858 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3859 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3860 resourcea.lpLocalName = NULL;
3861 filename_to_ansi (share, share_a);
3862 resourcea.lpRemoteName = share_a;
3863 resourcea.lpProvider = NULL;
3865 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3868 switch (val)
3870 case NO_ERROR:
3871 case ERROR_ALREADY_ASSIGNED:
3872 break;
3873 case ERROR_ACCESS_DENIED:
3874 case ERROR_LOGON_FAILURE:
3875 errno = EACCES;
3876 break;
3877 case ERROR_BUSY:
3878 errno = EAGAIN;
3879 break;
3880 case ERROR_BAD_NET_NAME:
3881 case ERROR_NO_NET_OR_BAD_PATH:
3882 case ERROR_NO_NETWORK:
3883 case ERROR_CANCELLED:
3884 default:
3885 errno = ENOENT;
3886 break;
3890 /* Emulate faccessat(2). */
3892 faccessat (int dirfd, const char * path, int mode, int flags)
3894 DWORD attributes;
3895 char fullname[MAX_UTF8_PATH];
3897 /* Rely on a hack: an open directory is modeled as file descriptor 0,
3898 and its actual file name is stored in dir_pathname by opendir.
3899 This is good enough for the current usage in Emacs, but is fragile. */
3900 if (dirfd != AT_FDCWD
3901 && !(IS_DIRECTORY_SEP (path[0])
3902 || IS_DEVICE_SEP (path[1])))
3904 char lastc = dir_pathname[strlen (dir_pathname) - 1];
3906 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
3907 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", path)
3908 < 0)
3910 errno = ENAMETOOLONG;
3911 return -1;
3913 path = fullname;
3916 /* When dired.c calls us with F_OK and a trailing slash, it actually
3917 wants to know whether PATH is a directory. */
3918 if (IS_DIRECTORY_SEP (path[strlen (path) - 1]) && mode == F_OK)
3919 mode |= D_OK;
3921 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3922 newer versions blow up when passed D_OK. */
3923 path = map_w32_filename (path, NULL);
3924 /* If the last element of PATH is a symlink, we need to resolve it
3925 to get the attributes of its target file. Note: any symlinks in
3926 PATH elements other than the last one are transparently resolved
3927 by GetFileAttributes below. */
3928 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3929 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3930 path = chase_symlinks (path);
3932 if (w32_unicode_filenames)
3934 wchar_t path_w[MAX_PATH];
3936 filename_to_utf16 (path, path_w);
3937 attributes = GetFileAttributesW (path_w);
3939 else
3941 char path_a[MAX_PATH];
3943 filename_to_ansi (path, path_a);
3944 attributes = GetFileAttributesA (path_a);
3947 if (attributes == -1)
3949 DWORD w32err = GetLastError ();
3951 switch (w32err)
3953 case ERROR_INVALID_NAME:
3954 case ERROR_BAD_PATHNAME:
3955 if (is_unc_volume (path))
3957 attributes = unc_volume_file_attributes (path);
3958 if (attributes == -1)
3960 errno = EACCES;
3961 return -1;
3963 goto check_attrs;
3965 /* FALLTHROUGH */
3966 FALLTHROUGH;
3967 case ERROR_FILE_NOT_FOUND:
3968 case ERROR_BAD_NETPATH:
3969 errno = ENOENT;
3970 break;
3971 default:
3972 errno = EACCES;
3973 break;
3975 return -1;
3978 check_attrs:
3979 if ((mode & X_OK) != 0
3980 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3982 errno = EACCES;
3983 return -1;
3985 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3987 errno = EACCES;
3988 return -1;
3990 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3992 errno = EACCES;
3993 return -1;
3995 return 0;
3998 /* A special test for DIRNAME being a directory accessible by the
3999 current user. This is needed because the security permissions in
4000 directory's ACLs are not visible in the Posix-style mode bits
4001 returned by 'stat' and in attributes returned by GetFileAttributes.
4002 So a directory would seem like it's readable by the current user,
4003 but will in fact error out with EACCES when they actually try. */
4005 w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
4007 char pattern[MAX_UTF8_PATH];
4008 bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
4009 HANDLE dh;
4011 /* Network volumes need a different reading method. */
4012 if (is_unc_volume (dirname))
4014 void *read_result = NULL;
4015 wchar_t fnw[MAX_PATH];
4016 char fna[MAX_PATH];
4018 dh = open_unc_volume (dirname);
4019 if (dh != INVALID_HANDLE_VALUE)
4021 read_result = read_unc_volume (dh, fnw, fna, MAX_PATH);
4022 close_unc_volume (dh);
4024 /* Treat empty volumes as accessible. */
4025 return read_result != NULL || GetLastError () == ERROR_NO_MORE_ITEMS;
4028 /* Note: map_w32_filename makes sure DIRNAME is not longer than
4029 MAX_UTF8_PATH. */
4030 strcpy (pattern, map_w32_filename (dirname, NULL));
4032 /* Note: No need to resolve symlinks in FILENAME, because FindFirst
4033 opens the directory that is the target of a symlink. */
4034 if (w32_unicode_filenames)
4036 wchar_t pat_w[MAX_PATH + 2];
4037 WIN32_FIND_DATAW dfd_w;
4039 filename_to_utf16 (pattern, pat_w);
4040 if (!last_slash)
4041 wcscat (pat_w, L"\\");
4042 wcscat (pat_w, L"*");
4043 dh = FindFirstFileW (pat_w, &dfd_w);
4045 else
4047 char pat_a[MAX_PATH + 2];
4048 WIN32_FIND_DATAA dfd_a;
4050 filename_to_ansi (pattern, pat_a);
4051 if (!last_slash)
4052 strcpy (pat_a, "\\");
4053 strcat (pat_a, "*");
4054 /* In case DIRNAME cannot be expressed in characters from the
4055 current ANSI codepage. */
4056 if (_mbspbrk (pat_a, "?"))
4057 dh = INVALID_HANDLE_VALUE;
4058 else
4059 dh = FindFirstFileA (pat_a, &dfd_a);
4062 if (dh == INVALID_HANDLE_VALUE)
4063 return 0;
4064 FindClose (dh);
4065 return 1;
4068 /* A version of 'access' to be used locally with file names in
4069 locale-specific encoding. Does not resolve symlinks and does not
4070 support file names on FAT12 and FAT16 volumes, but that's OK, since
4071 we only invoke this function for files inside the Emacs source or
4072 installation tree, on directories (so any symlinks should have the
4073 directory bit set), and on short file names such as "C:/.emacs". */
4074 static int
4075 sys_access (const char *fname, int mode)
4077 char fname_copy[MAX_PATH], *p;
4078 DWORD attributes;
4080 strcpy (fname_copy, fname);
4081 /* Do the equivalent of unixtodos_filename. */
4082 for (p = fname_copy; *p; p = CharNext (p))
4083 if (*p == '/')
4084 *p = '\\';
4086 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
4088 DWORD w32err = GetLastError ();
4090 switch (w32err)
4092 case ERROR_INVALID_NAME:
4093 case ERROR_BAD_PATHNAME:
4094 case ERROR_FILE_NOT_FOUND:
4095 case ERROR_BAD_NETPATH:
4096 errno = ENOENT;
4097 break;
4098 default:
4099 errno = EACCES;
4100 break;
4102 return -1;
4104 if ((mode & X_OK) != 0
4105 && !(is_exec (fname_copy)
4106 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
4108 errno = EACCES;
4109 return -1;
4111 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
4113 errno = EACCES;
4114 return -1;
4116 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
4118 errno = EACCES;
4119 return -1;
4121 return 0;
4124 /* Shadow some MSVC runtime functions to map requests for long filenames
4125 to reasonable short names if necessary. This was originally added to
4126 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
4127 long file names. */
4130 sys_chdir (const char * path)
4132 path = map_w32_filename (path, NULL);
4133 if (w32_unicode_filenames)
4135 wchar_t newdir_w[MAX_PATH];
4137 if (filename_to_utf16 (path, newdir_w) == 0)
4138 return _wchdir (newdir_w);
4139 return -1;
4141 else
4143 char newdir_a[MAX_PATH];
4145 if (filename_to_ansi (path, newdir_a) == 0)
4146 return _chdir (newdir_a);
4147 return -1;
4152 sys_chmod (const char * path, int mode)
4154 path = chase_symlinks (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 _wchmod (path_w, mode);
4162 else
4164 char path_a[MAX_PATH];
4166 filename_to_ansi (path, path_a);
4167 return _chmod (path_a, mode);
4172 sys_creat (const char * path, int mode)
4174 path = map_w32_filename (path, NULL);
4175 if (w32_unicode_filenames)
4177 wchar_t path_w[MAX_PATH];
4179 filename_to_utf16 (path, path_w);
4180 return _wcreat (path_w, mode);
4182 else
4184 char path_a[MAX_PATH];
4186 filename_to_ansi (path, path_a);
4187 return _creat (path_a, mode);
4191 FILE *
4192 sys_fopen (const char * path, const char * mode)
4194 int fd;
4195 int oflag;
4196 const char * mode_save = mode;
4198 /* Force all file handles to be non-inheritable. This is necessary to
4199 ensure child processes don't unwittingly inherit handles that might
4200 prevent future file access. */
4202 if (mode[0] == 'r')
4203 oflag = O_RDONLY;
4204 else if (mode[0] == 'w' || mode[0] == 'a')
4205 oflag = O_WRONLY | O_CREAT | O_TRUNC;
4206 else
4207 return NULL;
4209 /* Only do simplistic option parsing. */
4210 while (*++mode)
4211 if (mode[0] == '+')
4213 oflag &= ~(O_RDONLY | O_WRONLY);
4214 oflag |= O_RDWR;
4216 else if (mode[0] == 'b')
4218 oflag &= ~O_TEXT;
4219 oflag |= O_BINARY;
4221 else if (mode[0] == 't')
4223 oflag &= ~O_BINARY;
4224 oflag |= O_TEXT;
4226 else break;
4228 path = map_w32_filename (path, NULL);
4229 if (w32_unicode_filenames)
4231 wchar_t path_w[MAX_PATH];
4233 filename_to_utf16 (path, path_w);
4234 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
4236 else
4238 char path_a[MAX_PATH];
4240 filename_to_ansi (path, path_a);
4241 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
4243 if (fd < 0)
4244 return NULL;
4246 return _fdopen (fd, mode_save);
4249 /* This only works on NTFS volumes, but is useful to have. */
4251 sys_link (const char * old, const char * new)
4253 HANDLE fileh;
4254 int result = -1;
4255 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
4256 wchar_t oldname_w[MAX_PATH];
4257 char oldname_a[MAX_PATH];
4259 if (old == NULL || new == NULL)
4261 errno = ENOENT;
4262 return -1;
4265 strcpy (oldname, map_w32_filename (old, NULL));
4266 strcpy (newname, map_w32_filename (new, NULL));
4268 if (w32_unicode_filenames)
4270 filename_to_utf16 (oldname, oldname_w);
4271 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
4272 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4274 else
4276 filename_to_ansi (oldname, oldname_a);
4277 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
4278 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4280 if (fileh != INVALID_HANDLE_VALUE)
4282 int wlen;
4284 /* Confusingly, the "alternate" stream name field does not apply
4285 when restoring a hard link, and instead contains the actual
4286 stream data for the link (ie. the name of the link to create).
4287 The WIN32_STREAM_ID structure before the cStreamName field is
4288 the stream header, which is then immediately followed by the
4289 stream data. */
4291 struct {
4292 WIN32_STREAM_ID wid;
4293 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
4294 } data;
4296 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
4297 indicates that flag is unsupported for CP_UTF8, and OTOH says
4298 it is the default anyway. */
4299 wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
4300 data.wid.cStreamName, MAX_PATH);
4301 if (wlen > 0)
4303 LPVOID context = NULL;
4304 DWORD wbytes = 0;
4306 data.wid.dwStreamId = BACKUP_LINK;
4307 data.wid.dwStreamAttributes = 0;
4308 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
4309 data.wid.Size.HighPart = 0;
4310 data.wid.dwStreamNameSize = 0;
4312 if (BackupWrite (fileh, (LPBYTE)&data,
4313 offsetof (WIN32_STREAM_ID, cStreamName)
4314 + data.wid.Size.LowPart,
4315 &wbytes, FALSE, FALSE, &context)
4316 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
4318 /* succeeded */
4319 result = 0;
4321 else
4323 DWORD err = GetLastError ();
4324 DWORD attributes;
4326 switch (err)
4328 case ERROR_ACCESS_DENIED:
4329 /* This is what happens when OLDNAME is a directory,
4330 since Windows doesn't support hard links to
4331 directories. Posix says to set errno to EPERM in
4332 that case. */
4333 if (w32_unicode_filenames)
4334 attributes = GetFileAttributesW (oldname_w);
4335 else
4336 attributes = GetFileAttributesA (oldname_a);
4337 if (attributes != -1
4338 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
4339 errno = EPERM;
4340 else if (attributes == -1
4341 && is_unc_volume (oldname)
4342 && unc_volume_file_attributes (oldname) != -1)
4343 errno = EPERM;
4344 else
4345 errno = EACCES;
4346 break;
4347 case ERROR_TOO_MANY_LINKS:
4348 errno = EMLINK;
4349 break;
4350 case ERROR_NOT_SAME_DEVICE:
4351 errno = EXDEV;
4352 break;
4353 default:
4354 errno = EINVAL;
4355 break;
4360 CloseHandle (fileh);
4362 else
4363 errno = ENOENT;
4365 return result;
4369 sys_mkdir (const char * path, mode_t mode)
4371 path = map_w32_filename (path, NULL);
4373 if (w32_unicode_filenames)
4375 wchar_t path_w[MAX_PATH];
4377 filename_to_utf16 (path, path_w);
4378 return _wmkdir (path_w);
4380 else
4382 char path_a[MAX_PATH];
4384 filename_to_ansi (path, path_a);
4385 return _mkdir (path_a);
4390 sys_open (const char * path, int oflag, int mode)
4392 const char* mpath = map_w32_filename (path, NULL);
4393 int res = -1;
4395 if (w32_unicode_filenames)
4397 wchar_t mpath_w[MAX_PATH];
4399 filename_to_utf16 (mpath, mpath_w);
4400 /* If possible, try to open file without _O_CREAT, to be able to
4401 write to existing hidden and system files. Force all file
4402 handles to be non-inheritable. */
4403 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4404 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4405 if (res < 0)
4406 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4408 else
4410 char mpath_a[MAX_PATH];
4412 filename_to_ansi (mpath, mpath_a);
4413 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4414 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4415 if (res < 0)
4416 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4419 return res;
4423 fchmod (int fd, mode_t mode)
4425 return 0;
4429 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4431 BOOL result;
4432 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4433 int newname_dev;
4434 int oldname_dev;
4435 bool have_temp_a = false;
4437 /* MoveFile on Windows 95 doesn't correctly change the short file name
4438 alias in a number of circumstances (it is not easy to predict when
4439 just by looking at oldname and newname, unfortunately). In these
4440 cases, renaming through a temporary name avoids the problem.
4442 A second problem on Windows 95 is that renaming through a temp name when
4443 newname is uppercase fails (the final long name ends up in
4444 lowercase, although the short alias might be uppercase) UNLESS the
4445 long temp name is not 8.3.
4447 So, on Windows 95 we always rename through a temp name, and we make sure
4448 the temp name has a long extension to ensure correct renaming. */
4450 strcpy (temp, map_w32_filename (oldname, NULL));
4452 /* volume_info is set indirectly by map_w32_filename. */
4453 oldname_dev = volume_info.serialnum;
4455 if (os_subtype == OS_9X)
4457 char * o;
4458 char * p;
4459 int i = 0;
4460 char oldname_a[MAX_PATH];
4462 oldname = map_w32_filename (oldname, NULL);
4463 filename_to_ansi (oldname, oldname_a);
4464 filename_to_ansi (temp, temp_a);
4465 if ((o = strrchr (oldname_a, '\\')))
4466 o++;
4467 else
4468 o = (char *) oldname_a;
4470 if ((p = strrchr (temp_a, '\\')))
4471 p++;
4472 else
4473 p = temp_a;
4477 /* Force temp name to require a manufactured 8.3 alias - this
4478 seems to make the second rename work properly. */
4479 sprintf (p, "_.%s.%d", o, i);
4480 i++;
4481 result = rename (oldname_a, temp_a);
4483 /* This loop must surely terminate! */
4484 while (result < 0 && errno == EEXIST);
4485 if (result < 0)
4486 return -1;
4487 have_temp_a = true;
4490 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4491 (at least if it is a file; don't do this for directories).
4493 Since we mustn't do this if we are just changing the case of the
4494 file name (we would end up deleting the file we are trying to
4495 rename!), we let rename detect if the destination file already
4496 exists - that way we avoid the possible pitfalls of trying to
4497 determine ourselves whether two names really refer to the same
4498 file, which is not always possible in the general case. (Consider
4499 all the permutations of shared or subst'd drives, etc.) */
4501 newname = map_w32_filename (newname, NULL);
4503 /* volume_info is set indirectly by map_w32_filename. */
4504 newname_dev = volume_info.serialnum;
4506 if (w32_unicode_filenames)
4508 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4510 filename_to_utf16 (temp, temp_w);
4511 filename_to_utf16 (newname, newname_w);
4512 result = _wrename (temp_w, newname_w);
4513 if (result < 0)
4515 DWORD w32err = GetLastError ();
4517 if (errno == EACCES
4518 && newname_dev != oldname_dev)
4520 DWORD attributes;
4521 /* The implementation of `rename' on Windows does not return
4522 errno = EXDEV when you are moving a directory to a
4523 different storage device (ex. logical disk). It returns
4524 EACCES instead. So here we handle such situations and
4525 return EXDEV. */
4526 if ((attributes = GetFileAttributesW (temp_w)) != -1
4527 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4528 errno = EXDEV;
4530 else if (errno == EEXIST && force)
4532 DWORD attributes_old;
4533 DWORD attributes_new;
4535 if (_wchmod (newname_w, 0666) != 0)
4536 return result;
4537 attributes_old = GetFileAttributesW (temp_w);
4538 attributes_new = GetFileAttributesW (newname_w);
4539 if (attributes_old != -1 && attributes_new != -1
4540 && ((attributes_old & FILE_ATTRIBUTE_DIRECTORY)
4541 != (attributes_new & FILE_ATTRIBUTE_DIRECTORY)))
4543 if ((attributes_old & FILE_ATTRIBUTE_DIRECTORY) != 0)
4544 errno = ENOTDIR;
4545 else
4546 errno = EISDIR;
4547 return -1;
4549 if ((attributes_new & FILE_ATTRIBUTE_DIRECTORY) != 0)
4551 if (_wrmdir (newname_w) != 0)
4552 return result;
4554 else if (_wunlink (newname_w) != 0)
4555 return result;
4556 result = _wrename (temp_w, newname_w);
4558 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4559 && is_symlink (temp))
4561 /* This is Windows prohibiting the user from creating a
4562 symlink in another place, since that requires
4563 privileges. */
4564 errno = EPERM;
4568 else
4570 char newname_a[MAX_PATH];
4572 if (!have_temp_a)
4573 filename_to_ansi (temp, temp_a);
4574 filename_to_ansi (newname, newname_a);
4575 result = rename (temp_a, newname_a);
4576 if (result < 0)
4578 DWORD w32err = GetLastError ();
4580 if (errno == EACCES
4581 && newname_dev != oldname_dev)
4583 DWORD attributes;
4584 if ((attributes = GetFileAttributesA (temp_a)) != -1
4585 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4586 errno = EXDEV;
4588 else if (errno == EEXIST && force)
4590 DWORD attributes_old;
4591 DWORD attributes_new;
4593 if (_chmod (newname_a, 0666) != 0)
4594 return result;
4595 attributes_old = GetFileAttributesA (temp_a);
4596 attributes_new = GetFileAttributesA (newname_a);
4597 if (attributes_old != -1 && attributes_new != -1
4598 && ((attributes_old & FILE_ATTRIBUTE_DIRECTORY)
4599 != (attributes_new & FILE_ATTRIBUTE_DIRECTORY)))
4601 if ((attributes_old & FILE_ATTRIBUTE_DIRECTORY) != 0)
4602 errno = ENOTDIR;
4603 else
4604 errno = EISDIR;
4605 return -1;
4607 if ((attributes_new & FILE_ATTRIBUTE_DIRECTORY) != 0)
4609 if (_rmdir (newname_a) != 0)
4610 return result;
4612 else if (_unlink (newname_a) != 0)
4613 return result;
4614 result = rename (temp_a, newname_a);
4616 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4617 && is_symlink (temp))
4618 errno = EPERM;
4622 return result;
4626 sys_rename (char const *old, char const *new)
4628 return sys_rename_replace (old, new, TRUE);
4632 sys_rmdir (const char * path)
4634 path = map_w32_filename (path, NULL);
4636 if (w32_unicode_filenames)
4638 wchar_t path_w[MAX_PATH];
4640 filename_to_utf16 (path, path_w);
4641 return _wrmdir (path_w);
4643 else
4645 char path_a[MAX_PATH];
4647 filename_to_ansi (path, path_a);
4648 return _rmdir (path_a);
4653 sys_unlink (const char * path)
4655 int rmstatus, e;
4657 path = map_w32_filename (path, NULL);
4659 if (w32_unicode_filenames)
4661 wchar_t path_w[MAX_PATH];
4663 filename_to_utf16 (path, path_w);
4664 /* On Unix, unlink works without write permission. */
4665 _wchmod (path_w, 0666);
4666 rmstatus = _wunlink (path_w);
4667 e = errno;
4668 /* Symlinks to directories can only be deleted by _rmdir;
4669 _unlink returns EACCES. */
4670 if (rmstatus != 0
4671 && errno == EACCES
4672 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4673 rmstatus = _wrmdir (path_w);
4674 else
4675 errno = e;
4677 else
4679 char path_a[MAX_PATH];
4681 filename_to_ansi (path, path_a);
4682 _chmod (path_a, 0666);
4683 rmstatus = _unlink (path_a);
4684 e = errno;
4685 if (rmstatus != 0
4686 && errno == EACCES
4687 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4688 rmstatus = _rmdir (path_a);
4689 else
4690 errno = e;
4693 return rmstatus;
4696 static FILETIME utc_base_ft;
4697 static ULONGLONG utc_base; /* In 100ns units */
4698 static int init = 0;
4700 #define FILETIME_TO_U64(result, ft) \
4701 do { \
4702 ULARGE_INTEGER uiTemp; \
4703 uiTemp.LowPart = (ft).dwLowDateTime; \
4704 uiTemp.HighPart = (ft).dwHighDateTime; \
4705 result = uiTemp.QuadPart; \
4706 } while (0)
4708 static void
4709 initialize_utc_base (void)
4711 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4712 SYSTEMTIME st;
4714 st.wYear = 1970;
4715 st.wMonth = 1;
4716 st.wDay = 1;
4717 st.wHour = 0;
4718 st.wMinute = 0;
4719 st.wSecond = 0;
4720 st.wMilliseconds = 0;
4722 SystemTimeToFileTime (&st, &utc_base_ft);
4723 FILETIME_TO_U64 (utc_base, utc_base_ft);
4726 static time_t
4727 convert_time (FILETIME ft)
4729 ULONGLONG tmp;
4731 if (!init)
4733 initialize_utc_base ();
4734 init = 1;
4737 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4738 return 0;
4740 FILETIME_TO_U64 (tmp, ft);
4741 return (time_t) ((tmp - utc_base) / 10000000L);
4744 static void
4745 convert_from_time_t (time_t time, FILETIME * pft)
4747 ULARGE_INTEGER tmp;
4749 if (!init)
4751 initialize_utc_base ();
4752 init = 1;
4755 /* time in 100ns units since 1-Jan-1601 */
4756 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4757 pft->dwHighDateTime = tmp.HighPart;
4758 pft->dwLowDateTime = tmp.LowPart;
4761 static PSECURITY_DESCRIPTOR
4762 get_file_security_desc_by_handle (HANDLE h)
4764 PSECURITY_DESCRIPTOR psd = NULL;
4765 DWORD err;
4766 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4767 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4769 err = get_security_info (h, SE_FILE_OBJECT, si,
4770 NULL, NULL, NULL, NULL, &psd);
4771 if (err != ERROR_SUCCESS)
4772 return NULL;
4774 return psd;
4777 static PSECURITY_DESCRIPTOR
4778 get_file_security_desc_by_name (const char *fname)
4780 PSECURITY_DESCRIPTOR psd = NULL;
4781 DWORD sd_len, err;
4782 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4783 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4785 if (!get_file_security (fname, si, psd, 0, &sd_len))
4787 err = GetLastError ();
4788 if (err != ERROR_INSUFFICIENT_BUFFER)
4789 return NULL;
4792 psd = xmalloc (sd_len);
4793 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4795 xfree (psd);
4796 return NULL;
4799 return psd;
4802 static DWORD
4803 get_rid (PSID sid)
4805 unsigned n_subauthorities;
4807 /* Use the last sub-authority value of the RID, the relative
4808 portion of the SID, as user/group ID. */
4809 n_subauthorities = *get_sid_sub_authority_count (sid);
4810 if (n_subauthorities < 1)
4811 return 0; /* the "World" RID */
4812 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4815 /* Caching SID and account values for faster lokup. */
4817 struct w32_id {
4818 unsigned rid;
4819 struct w32_id *next;
4820 char name[GNLEN+1];
4821 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4824 static struct w32_id *w32_idlist;
4826 static int
4827 w32_cached_id (PSID sid, unsigned *id, char *name)
4829 struct w32_id *tail, *found;
4831 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4833 if (equal_sid ((PSID)tail->sid, sid))
4835 found = tail;
4836 break;
4839 if (found)
4841 *id = found->rid;
4842 strcpy (name, found->name);
4843 return 1;
4845 else
4846 return 0;
4849 static void
4850 w32_add_to_cache (PSID sid, unsigned id, char *name)
4852 DWORD sid_len;
4853 struct w32_id *new_entry;
4855 /* We don't want to leave behind stale cache from when Emacs was
4856 dumped. */
4857 if (initialized)
4859 sid_len = get_length_sid (sid);
4860 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4861 if (new_entry)
4863 new_entry->rid = id;
4864 strcpy (new_entry->name, name);
4865 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4866 new_entry->next = w32_idlist;
4867 w32_idlist = new_entry;
4872 #define UID 1
4873 #define GID 2
4875 static int
4876 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4878 PSID sid = NULL;
4879 BOOL dflt;
4880 SID_NAME_USE ignore;
4881 char name[UNLEN+1];
4882 DWORD name_len = sizeof (name);
4883 char domain[1024];
4884 DWORD domain_len = sizeof (domain);
4885 int use_dflt = 0;
4886 int result;
4888 if (what == UID)
4889 result = get_security_descriptor_owner (psd, &sid, &dflt);
4890 else if (what == GID)
4891 result = get_security_descriptor_group (psd, &sid, &dflt);
4892 else
4893 result = 0;
4895 if (!result || !is_valid_sid (sid))
4896 use_dflt = 1;
4897 else if (!w32_cached_id (sid, id, nm))
4899 if (!lookup_account_sid (NULL, sid, name, &name_len,
4900 domain, &domain_len, &ignore)
4901 || name_len > UNLEN+1)
4902 use_dflt = 1;
4903 else
4905 *id = get_rid (sid);
4906 strcpy (nm, name);
4907 w32_add_to_cache (sid, *id, name);
4910 return use_dflt;
4913 static void
4914 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4916 int dflt_usr = 0, dflt_grp = 0;
4918 if (!psd)
4920 dflt_usr = 1;
4921 dflt_grp = 1;
4923 else
4925 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4926 dflt_usr = 1;
4927 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4928 dflt_grp = 1;
4930 /* Consider files to belong to current user/group, if we cannot get
4931 more accurate information. */
4932 if (dflt_usr)
4934 st->st_uid = dflt_passwd.pw_uid;
4935 strcpy (st->st_uname, dflt_passwd.pw_name);
4937 if (dflt_grp)
4939 st->st_gid = dflt_passwd.pw_gid;
4940 strcpy (st->st_gname, dflt_group.gr_name);
4944 /* Return non-zero if NAME is a potentially slow filesystem. */
4945 int is_slow_fs (const char *);
4948 is_slow_fs (const char *name)
4950 char drive_root[4];
4951 UINT devtype;
4953 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4954 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4955 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4956 devtype = GetDriveType (NULL); /* use root of current drive */
4957 else
4959 /* GetDriveType needs the root directory of the drive. */
4960 strncpy (drive_root, name, 2);
4961 drive_root[2] = '\\';
4962 drive_root[3] = '\0';
4963 devtype = GetDriveType (drive_root);
4965 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4968 /* If this is non-zero, the caller wants accurate information about
4969 file's owner and group, which could be expensive to get. dired.c
4970 uses this flag when needed for the job at hand. */
4971 int w32_stat_get_owner_group;
4973 /* MSVC stat function can't cope with UNC names and has other bugs, so
4974 replace it with our own. This also allows us to calculate consistent
4975 inode values and owner/group without hacks in the main Emacs code,
4976 and support file names encoded in UTF-8. */
4978 static int
4979 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4981 char *name, *save_name, *r;
4982 WIN32_FIND_DATAW wfd_w;
4983 WIN32_FIND_DATAA wfd_a;
4984 HANDLE fh;
4985 unsigned __int64 fake_inode = 0;
4986 int permission;
4987 int len;
4988 int rootdir = FALSE;
4989 PSECURITY_DESCRIPTOR psd = NULL;
4990 int is_a_symlink = 0;
4991 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4992 DWORD access_rights = 0;
4993 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4994 FILETIME ctime, atime, wtime;
4995 wchar_t name_w[MAX_PATH];
4996 char name_a[MAX_PATH];
4998 if (path == NULL || buf == NULL)
5000 errno = EFAULT;
5001 return -1;
5004 save_name = name = (char *) map_w32_filename (path, &path);
5005 /* Must be valid filename, no wild cards or other invalid
5006 characters. */
5007 if (strpbrk (name, "*?|<>\""))
5009 errno = ENOENT;
5010 return -1;
5013 len = strlen (name);
5014 /* Allocate 1 extra byte so that we could append a slash to a root
5015 directory, down below. */
5016 name = strcpy (alloca (len + 2), name);
5018 /* Avoid a somewhat costly call to is_symlink if the filesystem
5019 doesn't support symlinks. */
5020 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5021 is_a_symlink = is_symlink (name);
5023 /* Plan A: Open the file and get all the necessary information via
5024 the resulting handle. This solves several issues in one blow:
5026 . retrieves attributes for the target of a symlink, if needed
5027 . gets attributes of root directories and symlinks pointing to
5028 root directories, thus avoiding the need for special-casing
5029 these and detecting them by examining the file-name format
5030 . retrieves more accurate attributes (e.g., non-zero size for
5031 some directories, esp. directories that are junction points)
5032 . correctly resolves "c:/..", "/.." and similar file names
5033 . avoids run-time penalties for 99% of use cases
5035 Plan A is always tried first, unless the user asked not to (but
5036 if the file is a symlink and we need to follow links, we try Plan
5037 A even if the user asked not to).
5039 If Plan A fails, we go to Plan B (below), where various
5040 potentially expensive techniques must be used to handle "special"
5041 files such as UNC volumes etc. */
5042 if (!(NILP (Vw32_get_true_file_attributes)
5043 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
5044 /* Following symlinks requires getting the info by handle. */
5045 || (is_a_symlink && follow_symlinks))
5047 BY_HANDLE_FILE_INFORMATION info;
5049 if (is_a_symlink && !follow_symlinks)
5050 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
5051 /* READ_CONTROL access rights are required to get security info
5052 by handle. But if the OS doesn't support security in the
5053 first place, we don't need to try. */
5054 if (is_windows_9x () != TRUE)
5055 access_rights |= READ_CONTROL;
5057 if (w32_unicode_filenames)
5059 filename_to_utf16 (name, name_w);
5060 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
5061 file_flags, NULL);
5062 /* If CreateFile fails with READ_CONTROL, try again with
5063 zero as access rights. */
5064 if (fh == INVALID_HANDLE_VALUE && access_rights)
5065 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
5066 file_flags, NULL);
5068 else
5070 filename_to_ansi (name, name_a);
5071 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
5072 file_flags, NULL);
5073 if (fh == INVALID_HANDLE_VALUE && access_rights)
5074 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
5075 file_flags, NULL);
5077 if (fh == INVALID_HANDLE_VALUE)
5078 goto no_true_file_attributes;
5080 /* This is more accurate in terms of getting the correct number
5081 of links, but is quite slow (it is noticeable when Emacs is
5082 making a list of file name completions). */
5083 if (GetFileInformationByHandle (fh, &info))
5085 nlinks = info.nNumberOfLinks;
5086 /* Might as well use file index to fake inode values, but this
5087 is not guaranteed to be unique unless we keep a handle open
5088 all the time (even then there are situations where it is
5089 not unique). Reputedly, there are at most 48 bits of info
5090 (on NTFS, presumably less on FAT). */
5091 fake_inode = info.nFileIndexHigh;
5092 fake_inode <<= 32;
5093 fake_inode += info.nFileIndexLow;
5094 serialnum = info.dwVolumeSerialNumber;
5095 fs_high = info.nFileSizeHigh;
5096 fs_low = info.nFileSizeLow;
5097 ctime = info.ftCreationTime;
5098 atime = info.ftLastAccessTime;
5099 wtime = info.ftLastWriteTime;
5100 fattrs = info.dwFileAttributes;
5102 else
5104 /* We don't go to Plan B here, because it's not clear that
5105 it's a good idea. The only known use case where
5106 CreateFile succeeds, but GetFileInformationByHandle fails
5107 (with ERROR_INVALID_FUNCTION) is for character devices
5108 such as NUL, PRN, etc. For these, switching to Plan B is
5109 a net loss, because we lose the character device
5110 attribute returned by GetFileType below (FindFirstFile
5111 doesn't set that bit in the attributes), and the other
5112 fields don't make sense for character devices anyway.
5113 Emacs doesn't really care for non-file entities in the
5114 context of l?stat, so neither do we. */
5116 /* w32err is assigned so one could put a breakpoint here and
5117 examine its value, when GetFileInformationByHandle
5118 fails. */
5119 DWORD w32err = GetLastError ();
5121 switch (w32err)
5123 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
5124 errno = ENOENT;
5125 return -1;
5129 /* Test for a symlink before testing for a directory, since
5130 symlinks to directories have the directory bit set, but we
5131 don't want them to appear as directories. */
5132 if (is_a_symlink && !follow_symlinks)
5133 buf->st_mode = S_IFLNK;
5134 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5135 buf->st_mode = S_IFDIR;
5136 else
5138 DWORD ftype = GetFileType (fh);
5140 switch (ftype)
5142 case FILE_TYPE_DISK:
5143 buf->st_mode = S_IFREG;
5144 break;
5145 case FILE_TYPE_PIPE:
5146 buf->st_mode = S_IFIFO;
5147 break;
5148 case FILE_TYPE_CHAR:
5149 case FILE_TYPE_UNKNOWN:
5150 default:
5151 buf->st_mode = S_IFCHR;
5154 /* We produce the fallback owner and group data, based on the
5155 current user that runs Emacs, in the following cases:
5157 . caller didn't request owner and group info
5158 . this is Windows 9X
5159 . getting security by handle failed, and we need to produce
5160 information for the target of a symlink (this is better
5161 than producing a potentially misleading info about the
5162 symlink itself)
5164 If getting security by handle fails, and we don't need to
5165 resolve symlinks, we try getting security by name. */
5166 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5167 get_file_owner_and_group (NULL, buf);
5168 else
5170 psd = get_file_security_desc_by_handle (fh);
5171 if (psd)
5173 get_file_owner_and_group (psd, buf);
5174 LocalFree (psd);
5176 else if (!(is_a_symlink && follow_symlinks))
5178 psd = get_file_security_desc_by_name (name);
5179 get_file_owner_and_group (psd, buf);
5180 xfree (psd);
5182 else
5183 get_file_owner_and_group (NULL, buf);
5185 CloseHandle (fh);
5187 else
5189 no_true_file_attributes:
5190 /* Plan B: Either getting a handle on the file failed, or the
5191 caller explicitly asked us to not bother making this
5192 information more accurate.
5194 Implementation note: In Plan B, we never bother to resolve
5195 symlinks, even if we got here because we tried Plan A and
5196 failed. That's because, even if the caller asked for extra
5197 precision by setting Vw32_get_true_file_attributes to t,
5198 resolving symlinks requires acquiring a file handle to the
5199 symlink, which we already know will fail. And if the user
5200 did not ask for extra precision, resolving symlinks will fly
5201 in the face of that request, since the user then wants the
5202 lightweight version of the code. */
5203 rootdir = (path >= save_name + len - 1
5204 && (IS_DIRECTORY_SEP (*path) || *path == 0));
5206 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
5207 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
5208 if (IS_DIRECTORY_SEP (r[0])
5209 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
5210 r[1] = r[2] = '\0';
5212 /* Note: If NAME is a symlink to the root of a UNC volume
5213 (i.e. "\\SERVER"), we will not detect that here, and we will
5214 return data about the symlink as result of FindFirst below.
5215 This is unfortunate, but that marginal use case does not
5216 justify a call to chase_symlinks which would impose a penalty
5217 on all the other use cases. (We get here for symlinks to
5218 roots of UNC volumes because CreateFile above fails for them,
5219 unlike with symlinks to root directories X:\ of drives.) */
5220 if (is_unc_volume (name))
5222 fattrs = unc_volume_file_attributes (name);
5223 if (fattrs == -1)
5224 return -1;
5226 ctime = atime = wtime = utc_base_ft;
5228 else if (rootdir)
5230 /* Make sure root directories end in a slash. */
5231 if (!IS_DIRECTORY_SEP (name[len-1]))
5232 strcpy (name + len, "\\");
5233 if (GetDriveType (name) < 2)
5235 errno = ENOENT;
5236 return -1;
5239 fattrs = FILE_ATTRIBUTE_DIRECTORY;
5240 ctime = atime = wtime = utc_base_ft;
5242 else
5244 int have_wfd = -1;
5246 /* Make sure non-root directories do NOT end in a slash,
5247 otherwise FindFirstFile might fail. */
5248 if (IS_DIRECTORY_SEP (name[len-1]))
5249 name[len - 1] = 0;
5251 /* (This is hacky, but helps when doing file completions on
5252 network drives.) Optimize by using information available from
5253 active readdir if possible. */
5254 len = strlen (dir_pathname);
5255 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
5256 len--;
5257 if (dir_find_handle != INVALID_HANDLE_VALUE
5258 && last_dir_find_data != -1
5259 && !(is_a_symlink && follow_symlinks)
5260 /* The 2 file-name comparisons below support only ASCII
5261 characters, and will lose (compare not equal) when
5262 the file names include non-ASCII characters that are
5263 the same but for the case. However, doing this
5264 properly involves: (a) converting both file names to
5265 UTF-16, (b) lower-casing both names using CharLowerW,
5266 and (c) comparing the results; this would be quite a
5267 bit slower, whereas Plan B is for users who want
5268 lightweight albeit inaccurate version of 'stat'. */
5269 && c_strncasecmp (save_name, dir_pathname, len) == 0
5270 && IS_DIRECTORY_SEP (name[len])
5271 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
5273 have_wfd = last_dir_find_data;
5274 /* This was the last entry returned by readdir. */
5275 if (last_dir_find_data == DIR_FIND_DATA_W)
5276 wfd_w = dir_find_data_w;
5277 else
5278 wfd_a = dir_find_data_a;
5280 else
5282 logon_network_drive (name);
5284 if (w32_unicode_filenames)
5286 filename_to_utf16 (name, name_w);
5287 fh = FindFirstFileW (name_w, &wfd_w);
5288 have_wfd = DIR_FIND_DATA_W;
5290 else
5292 filename_to_ansi (name, name_a);
5293 /* If NAME includes characters not representable by
5294 the current ANSI codepage, filename_to_ansi
5295 usually replaces them with a '?'. We don't want
5296 to let FindFirstFileA interpret those as wildcards,
5297 and "succeed", returning us data from some random
5298 file in the same directory. */
5299 if (_mbspbrk (name_a, "?"))
5300 fh = INVALID_HANDLE_VALUE;
5301 else
5302 fh = FindFirstFileA (name_a, &wfd_a);
5303 have_wfd = DIR_FIND_DATA_A;
5305 if (fh == INVALID_HANDLE_VALUE)
5307 errno = ENOENT;
5308 return -1;
5310 FindClose (fh);
5312 /* Note: if NAME is a symlink, the information we get from
5313 FindFirstFile is for the symlink, not its target. */
5314 if (have_wfd == DIR_FIND_DATA_W)
5316 fattrs = wfd_w.dwFileAttributes;
5317 ctime = wfd_w.ftCreationTime;
5318 atime = wfd_w.ftLastAccessTime;
5319 wtime = wfd_w.ftLastWriteTime;
5320 fs_high = wfd_w.nFileSizeHigh;
5321 fs_low = wfd_w.nFileSizeLow;
5323 else
5325 fattrs = wfd_a.dwFileAttributes;
5326 ctime = wfd_a.ftCreationTime;
5327 atime = wfd_a.ftLastAccessTime;
5328 wtime = wfd_a.ftLastWriteTime;
5329 fs_high = wfd_a.nFileSizeHigh;
5330 fs_low = wfd_a.nFileSizeLow;
5332 fake_inode = 0;
5333 nlinks = 1;
5334 serialnum = volume_info.serialnum;
5336 if (is_a_symlink && !follow_symlinks)
5337 buf->st_mode = S_IFLNK;
5338 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5339 buf->st_mode = S_IFDIR;
5340 else
5341 buf->st_mode = S_IFREG;
5343 get_file_owner_and_group (NULL, buf);
5346 buf->st_ino = fake_inode;
5348 buf->st_dev = serialnum;
5349 buf->st_rdev = serialnum;
5351 buf->st_size = fs_high;
5352 buf->st_size <<= 32;
5353 buf->st_size += fs_low;
5354 buf->st_nlink = nlinks;
5356 /* Convert timestamps to Unix format. */
5357 buf->st_mtime = convert_time (wtime);
5358 buf->st_atime = convert_time (atime);
5359 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5360 buf->st_ctime = convert_time (ctime);
5361 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5363 /* determine rwx permissions */
5364 if (is_a_symlink && !follow_symlinks)
5365 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5366 else
5368 if (fattrs & FILE_ATTRIBUTE_READONLY)
5369 permission = S_IREAD;
5370 else
5371 permission = S_IREAD | S_IWRITE;
5373 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5374 permission |= S_IEXEC;
5375 else if (is_exec (name))
5376 permission |= S_IEXEC;
5379 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5381 return 0;
5385 stat (const char * path, struct stat * buf)
5387 return stat_worker (path, buf, 1);
5391 lstat (const char * path, struct stat * buf)
5393 return stat_worker (path, buf, 0);
5397 fstatat (int fd, char const *name, struct stat *st, int flags)
5399 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5400 This is good enough for the current usage in Emacs, but is fragile.
5402 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5403 Gnulib does this and can serve as a model. */
5404 char fullname[MAX_UTF8_PATH];
5406 if (fd != AT_FDCWD)
5408 char lastc = dir_pathname[strlen (dir_pathname) - 1];
5410 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
5411 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
5412 < 0)
5414 errno = ENAMETOOLONG;
5415 return -1;
5417 name = fullname;
5420 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5423 /* Provide fstat and utime as well as stat for consistent handling of
5424 file timestamps. */
5426 fstat (int desc, struct stat * buf)
5428 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5429 BY_HANDLE_FILE_INFORMATION info;
5430 unsigned __int64 fake_inode;
5431 int permission;
5433 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5435 case FILE_TYPE_DISK:
5436 buf->st_mode = S_IFREG;
5437 if (!GetFileInformationByHandle (fh, &info))
5439 errno = EACCES;
5440 return -1;
5442 break;
5443 case FILE_TYPE_PIPE:
5444 buf->st_mode = S_IFIFO;
5445 goto non_disk;
5446 case FILE_TYPE_CHAR:
5447 case FILE_TYPE_UNKNOWN:
5448 default:
5449 buf->st_mode = S_IFCHR;
5450 non_disk:
5451 memset (&info, 0, sizeof (info));
5452 info.dwFileAttributes = 0;
5453 info.ftCreationTime = utc_base_ft;
5454 info.ftLastAccessTime = utc_base_ft;
5455 info.ftLastWriteTime = utc_base_ft;
5458 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5459 buf->st_mode = S_IFDIR;
5461 buf->st_nlink = info.nNumberOfLinks;
5462 /* Might as well use file index to fake inode values, but this
5463 is not guaranteed to be unique unless we keep a handle open
5464 all the time (even then there are situations where it is
5465 not unique). Reputedly, there are at most 48 bits of info
5466 (on NTFS, presumably less on FAT). */
5467 fake_inode = info.nFileIndexHigh;
5468 fake_inode <<= 32;
5469 fake_inode += info.nFileIndexLow;
5471 /* MSVC defines _ino_t to be short; other libc's might not. */
5472 if (sizeof (buf->st_ino) == 2)
5473 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5474 else
5475 buf->st_ino = fake_inode;
5477 /* If the caller so requested, get the true file owner and group.
5478 Otherwise, consider the file to belong to the current user. */
5479 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5480 get_file_owner_and_group (NULL, buf);
5481 else
5483 PSECURITY_DESCRIPTOR psd = NULL;
5485 psd = get_file_security_desc_by_handle (fh);
5486 if (psd)
5488 get_file_owner_and_group (psd, buf);
5489 LocalFree (psd);
5491 else
5492 get_file_owner_and_group (NULL, buf);
5495 buf->st_dev = info.dwVolumeSerialNumber;
5496 buf->st_rdev = info.dwVolumeSerialNumber;
5498 buf->st_size = info.nFileSizeHigh;
5499 buf->st_size <<= 32;
5500 buf->st_size += info.nFileSizeLow;
5502 /* Convert timestamps to Unix format. */
5503 buf->st_mtime = convert_time (info.ftLastWriteTime);
5504 buf->st_atime = convert_time (info.ftLastAccessTime);
5505 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5506 buf->st_ctime = convert_time (info.ftCreationTime);
5507 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5509 /* determine rwx permissions */
5510 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5511 permission = S_IREAD;
5512 else
5513 permission = S_IREAD | S_IWRITE;
5515 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5516 permission |= S_IEXEC;
5517 else
5519 #if 0 /* no way of knowing the filename */
5520 char * p = strrchr (name, '.');
5521 if (p != NULL &&
5522 (xstrcasecmp (p, ".exe") == 0 ||
5523 xstrcasecmp (p, ".com") == 0 ||
5524 xstrcasecmp (p, ".bat") == 0 ||
5525 xstrcasecmp (p, ".cmd") == 0))
5526 permission |= S_IEXEC;
5527 #endif
5530 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5532 return 0;
5535 /* A version of 'utime' which handles directories as well as
5536 files. */
5539 utime (const char *name, struct utimbuf *times)
5541 struct utimbuf deftime;
5542 HANDLE fh;
5543 FILETIME mtime;
5544 FILETIME atime;
5546 if (times == NULL)
5548 deftime.modtime = deftime.actime = time (NULL);
5549 times = &deftime;
5552 if (w32_unicode_filenames)
5554 wchar_t name_utf16[MAX_PATH];
5556 if (filename_to_utf16 (name, name_utf16) != 0)
5557 return -1; /* errno set by filename_to_utf16 */
5559 /* Need write access to set times. */
5560 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5561 /* If NAME specifies a directory, FILE_SHARE_DELETE
5562 allows other processes to delete files inside it,
5563 while we have the directory open. */
5564 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5565 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5567 else
5569 char name_ansi[MAX_PATH];
5571 if (filename_to_ansi (name, name_ansi) != 0)
5572 return -1; /* errno set by filename_to_ansi */
5574 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5575 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5576 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5578 if (fh != INVALID_HANDLE_VALUE)
5580 convert_from_time_t (times->actime, &atime);
5581 convert_from_time_t (times->modtime, &mtime);
5582 if (!SetFileTime (fh, NULL, &atime, &mtime))
5584 CloseHandle (fh);
5585 errno = EACCES;
5586 return -1;
5588 CloseHandle (fh);
5590 else
5592 DWORD err = GetLastError ();
5594 switch (err)
5596 case ERROR_FILE_NOT_FOUND:
5597 case ERROR_PATH_NOT_FOUND:
5598 case ERROR_INVALID_DRIVE:
5599 case ERROR_BAD_NETPATH:
5600 case ERROR_DEV_NOT_EXIST:
5601 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5602 file name includes ?s, i.e. translation to ANSI failed. */
5603 case ERROR_INVALID_NAME:
5604 errno = ENOENT;
5605 break;
5606 case ERROR_TOO_MANY_OPEN_FILES:
5607 errno = ENFILE;
5608 break;
5609 case ERROR_ACCESS_DENIED:
5610 case ERROR_SHARING_VIOLATION:
5611 errno = EACCES;
5612 break;
5613 default:
5614 errno = EINVAL;
5615 break;
5617 return -1;
5619 return 0;
5623 sys_umask (int mode)
5625 static int current_mask;
5626 int retval, arg = 0;
5628 /* The only bit we really support is the write bit. Files are
5629 always readable on MS-Windows, and the execute bit does not exist
5630 at all. */
5631 /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
5632 to prevent access by other users on NTFS. */
5633 if ((mode & S_IWRITE) != 0)
5634 arg |= S_IWRITE;
5636 retval = _umask (arg);
5637 /* Merge into the return value the bits they've set the last time,
5638 which msvcrt.dll ignores and never returns. Emacs insists on its
5639 notion of mask being identical to what we return. */
5640 retval |= (current_mask & ~S_IWRITE);
5641 current_mask = mode;
5643 return retval;
5647 /* Symlink-related functions. */
5648 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5649 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5650 #endif
5653 symlink (char const *filename, char const *linkname)
5655 char linkfn[MAX_UTF8_PATH], *tgtfn;
5656 DWORD flags = 0;
5657 int dir_access, filename_ends_in_slash;
5659 /* Diagnostics follows Posix as much as possible. */
5660 if (filename == NULL || linkname == NULL)
5662 errno = EFAULT;
5663 return -1;
5665 if (!*filename)
5667 errno = ENOENT;
5668 return -1;
5670 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5672 errno = ENAMETOOLONG;
5673 return -1;
5676 strcpy (linkfn, map_w32_filename (linkname, NULL));
5677 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5679 errno = EPERM;
5680 return -1;
5683 /* Note: since empty FILENAME was already rejected, we can safely
5684 refer to FILENAME[1]. */
5685 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5687 /* Non-absolute FILENAME is understood as being relative to
5688 LINKNAME's directory. We need to prepend that directory to
5689 FILENAME to get correct results from faccessat below, since
5690 otherwise it will interpret FILENAME relative to the
5691 directory where the Emacs process runs. Note that
5692 make-symbolic-link always makes sure LINKNAME is a fully
5693 expanded file name. */
5694 char tem[MAX_UTF8_PATH];
5695 char *p = linkfn + strlen (linkfn);
5697 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5698 p--;
5699 if (p > linkfn)
5700 strncpy (tem, linkfn, p - linkfn);
5701 strcpy (tem + (p - linkfn), filename);
5702 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5704 else
5705 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5707 /* Since Windows distinguishes between symlinks to directories and
5708 to files, we provide a kludgy feature: if FILENAME doesn't
5709 exist, but ends in a slash, we create a symlink to directory. If
5710 FILENAME exists and is a directory, we always create a symlink to
5711 directory. */
5712 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5713 if (dir_access == 0 || filename_ends_in_slash)
5714 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5716 tgtfn = (char *)map_w32_filename (filename, NULL);
5717 if (filename_ends_in_slash)
5718 tgtfn[strlen (tgtfn) - 1] = '\0';
5720 errno = 0;
5721 if (!create_symbolic_link (linkfn, tgtfn, flags))
5723 /* ENOSYS is set by create_symbolic_link, when it detects that
5724 the OS doesn't support the CreateSymbolicLink API. */
5725 if (errno != ENOSYS)
5727 DWORD w32err = GetLastError ();
5729 switch (w32err)
5731 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5732 TGTFN point to the same file name, go figure. */
5733 case ERROR_SUCCESS:
5734 case ERROR_FILE_EXISTS:
5735 errno = EEXIST;
5736 break;
5737 case ERROR_ACCESS_DENIED:
5738 errno = EACCES;
5739 break;
5740 case ERROR_FILE_NOT_FOUND:
5741 case ERROR_PATH_NOT_FOUND:
5742 case ERROR_BAD_NETPATH:
5743 case ERROR_INVALID_REPARSE_DATA:
5744 errno = ENOENT;
5745 break;
5746 case ERROR_DIRECTORY:
5747 errno = EISDIR;
5748 break;
5749 case ERROR_PRIVILEGE_NOT_HELD:
5750 case ERROR_NOT_ALL_ASSIGNED:
5751 errno = EPERM;
5752 break;
5753 case ERROR_DISK_FULL:
5754 errno = ENOSPC;
5755 break;
5756 default:
5757 errno = EINVAL;
5758 break;
5761 return -1;
5763 return 0;
5766 /* A quick inexpensive test of whether FILENAME identifies a file that
5767 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5768 must already be in the normalized form returned by
5769 map_w32_filename. If the symlink is to a directory, the
5770 FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
5772 Note: for repeated operations on many files, it is best to test
5773 whether the underlying volume actually supports symlinks, by
5774 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5775 avoid the call to this function if it doesn't. That's because the
5776 call to GetFileAttributes takes a non-negligible time, especially
5777 on non-local or removable filesystems. See stat_worker for an
5778 example of how to do that. */
5779 static int
5780 is_symlink (const char *filename)
5782 DWORD attrs;
5783 wchar_t filename_w[MAX_PATH];
5784 char filename_a[MAX_PATH];
5785 WIN32_FIND_DATAW wfdw;
5786 WIN32_FIND_DATAA wfda;
5787 HANDLE fh;
5788 int attrs_mean_symlink;
5790 if (w32_unicode_filenames)
5792 filename_to_utf16 (filename, filename_w);
5793 attrs = GetFileAttributesW (filename_w);
5795 else
5797 filename_to_ansi (filename, filename_a);
5798 attrs = GetFileAttributesA (filename_a);
5800 if (attrs == -1)
5802 DWORD w32err = GetLastError ();
5804 switch (w32err)
5806 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5807 break;
5808 case ERROR_ACCESS_DENIED:
5809 errno = EACCES;
5810 break;
5811 case ERROR_FILE_NOT_FOUND:
5812 case ERROR_PATH_NOT_FOUND:
5813 default:
5814 errno = ENOENT;
5815 break;
5817 return 0;
5819 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5820 return 0;
5821 logon_network_drive (filename);
5822 if (w32_unicode_filenames)
5824 fh = FindFirstFileW (filename_w, &wfdw);
5825 attrs_mean_symlink =
5826 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5827 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5828 if (attrs_mean_symlink)
5829 attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5831 else if (_mbspbrk (filename_a, "?"))
5833 /* filename_to_ansi failed to convert the file name. */
5834 errno = ENOENT;
5835 return 0;
5837 else
5839 fh = FindFirstFileA (filename_a, &wfda);
5840 attrs_mean_symlink =
5841 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5842 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5843 if (attrs_mean_symlink)
5844 attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5846 if (fh == INVALID_HANDLE_VALUE)
5847 return 0;
5848 FindClose (fh);
5849 return attrs_mean_symlink;
5852 /* If NAME identifies a symbolic link, copy into BUF the file name of
5853 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5854 null-terminate the target name, even if it fits. Return the number
5855 of bytes copied, or -1 if NAME is not a symlink or any error was
5856 encountered while resolving it. The file name copied into BUF is
5857 encoded in the current ANSI codepage. */
5858 ssize_t
5859 readlink (const char *name, char *buf, size_t buf_size)
5861 const char *path;
5862 TOKEN_PRIVILEGES privs;
5863 int restore_privs = 0;
5864 HANDLE sh;
5865 ssize_t retval;
5866 char resolved[MAX_UTF8_PATH];
5868 if (name == NULL)
5870 errno = EFAULT;
5871 return -1;
5873 if (!*name)
5875 errno = ENOENT;
5876 return -1;
5879 path = map_w32_filename (name, NULL);
5881 if (strlen (path) > MAX_UTF8_PATH)
5883 errno = ENAMETOOLONG;
5884 return -1;
5887 errno = 0;
5888 if (is_windows_9x () == TRUE
5889 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5890 || !is_symlink (path))
5892 if (!errno)
5893 errno = EINVAL; /* not a symlink */
5894 return -1;
5897 /* Done with simple tests, now we're in for some _real_ work. */
5898 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5899 restore_privs = 1;
5900 /* Implementation note: From here and onward, don't return early,
5901 since that will fail to restore the original set of privileges of
5902 the calling thread. */
5904 retval = -1; /* not too optimistic, are we? */
5906 /* Note: In the next call to CreateFile, we use zero as the 2nd
5907 argument because, when the symlink is a hidden/system file,
5908 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5909 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5910 and directory symlinks. */
5911 if (w32_unicode_filenames)
5913 wchar_t path_w[MAX_PATH];
5915 filename_to_utf16 (path, path_w);
5916 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5917 FILE_FLAG_OPEN_REPARSE_POINT
5918 | FILE_FLAG_BACKUP_SEMANTICS,
5919 NULL);
5921 else
5923 char path_a[MAX_PATH];
5925 filename_to_ansi (path, path_a);
5926 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5927 FILE_FLAG_OPEN_REPARSE_POINT
5928 | FILE_FLAG_BACKUP_SEMANTICS,
5929 NULL);
5931 if (sh != INVALID_HANDLE_VALUE)
5933 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5934 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5935 DWORD retbytes;
5937 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5938 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5939 &retbytes, NULL))
5940 errno = EIO;
5941 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5942 errno = EINVAL;
5943 else
5945 /* Copy the link target name, in wide characters, from
5946 reparse_data, then convert it to multibyte encoding in
5947 the current locale's codepage. */
5948 WCHAR *lwname;
5949 size_t lname_size;
5950 USHORT lwname_len =
5951 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5952 WCHAR *lwname_src =
5953 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5954 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5955 size_t size_to_copy = buf_size;
5957 /* According to MSDN, PrintNameLength does not include the
5958 terminating null character. */
5959 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5960 memcpy (lwname, lwname_src, lwname_len);
5961 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5962 filename_from_utf16 (lwname, resolved);
5963 dostounix_filename (resolved);
5964 lname_size = strlen (resolved) + 1;
5965 if (lname_size <= buf_size)
5966 size_to_copy = lname_size;
5967 strncpy (buf, resolved, size_to_copy);
5968 /* Success! */
5969 retval = size_to_copy;
5971 CloseHandle (sh);
5973 else
5975 /* CreateFile failed. */
5976 DWORD w32err2 = GetLastError ();
5978 switch (w32err2)
5980 case ERROR_FILE_NOT_FOUND:
5981 case ERROR_PATH_NOT_FOUND:
5982 errno = ENOENT;
5983 break;
5984 case ERROR_ACCESS_DENIED:
5985 case ERROR_TOO_MANY_OPEN_FILES:
5986 errno = EACCES;
5987 break;
5988 default:
5989 errno = EPERM;
5990 break;
5993 if (restore_privs)
5995 restore_privilege (&privs);
5996 revert_to_self ();
5999 return retval;
6002 ssize_t
6003 readlinkat (int fd, char const *name, char *buffer,
6004 size_t buffer_size)
6006 /* Rely on a hack: an open directory is modeled as file descriptor 0,
6007 as in fstatat. FIXME: Add proper support for readlinkat. */
6008 char fullname[MAX_UTF8_PATH];
6010 if (fd != AT_FDCWD)
6012 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
6013 < 0)
6015 errno = ENAMETOOLONG;
6016 return -1;
6018 name = fullname;
6021 return readlink (name, buffer, buffer_size);
6024 /* If FILE is a symlink, return its target (stored in a static
6025 buffer); otherwise return FILE.
6027 This function repeatedly resolves symlinks in the last component of
6028 a chain of symlink file names, as in foo -> bar -> baz -> ...,
6029 until it arrives at a file whose last component is not a symlink,
6030 or some error occurs. It returns the target of the last
6031 successfully resolved symlink in the chain. If it succeeds to
6032 resolve even a single symlink, the value returned is an absolute
6033 file name with backslashes (result of GetFullPathName). By
6034 contrast, if the original FILE is returned, it is unaltered.
6036 Note: This function can set errno even if it succeeds.
6038 Implementation note: we only resolve the last portion ("basename")
6039 of the argument FILE and of each following file in the chain,
6040 disregarding any possible symlinks in its leading directories.
6041 This is because Windows system calls and library functions
6042 transparently resolve symlinks in leading directories and return
6043 correct information, as long as the basename is not a symlink. */
6044 static char *
6045 chase_symlinks (const char *file)
6047 static char target[MAX_UTF8_PATH];
6048 char link[MAX_UTF8_PATH];
6049 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
6050 char target_a[MAX_PATH], link_a[MAX_PATH];
6051 ssize_t res, link_len;
6052 int loop_count = 0;
6054 if (is_windows_9x () == TRUE || !is_symlink (file))
6055 return (char *)file;
6057 if (w32_unicode_filenames)
6059 wchar_t file_w[MAX_PATH];
6061 filename_to_utf16 (file, file_w);
6062 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
6063 return (char *)file;
6064 filename_from_utf16 (link_w, link);
6066 else
6068 char file_a[MAX_PATH];
6070 filename_to_ansi (file, file_a);
6071 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
6072 return (char *)file;
6073 filename_from_ansi (link_a, link);
6075 link_len = strlen (link);
6077 target[0] = '\0';
6078 do {
6080 /* Remove trailing slashes, as we want to resolve the last
6081 non-trivial part of the link name. */
6082 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
6083 link[link_len--] = '\0';
6085 res = readlink (link, target, MAX_UTF8_PATH);
6086 if (res > 0)
6088 target[res] = '\0';
6089 if (!(IS_DEVICE_SEP (target[1])
6090 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
6092 /* Target is relative. Append it to the directory part of
6093 the symlink, then copy the result back to target. */
6094 char *p = link + link_len;
6096 while (p > link && !IS_ANY_SEP (p[-1]))
6097 p--;
6098 strcpy (p, target);
6099 strcpy (target, link);
6101 /* Resolve any "." and ".." to get a fully-qualified file name
6102 in link[] again. */
6103 if (w32_unicode_filenames)
6105 filename_to_utf16 (target, target_w);
6106 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
6107 if (link_len > 0)
6108 filename_from_utf16 (link_w, link);
6110 else
6112 filename_to_ansi (target, target_a);
6113 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
6114 if (link_len > 0)
6115 filename_from_ansi (link_a, link);
6117 link_len = strlen (link);
6119 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
6121 if (loop_count > 100)
6122 errno = ELOOP;
6124 if (target[0] == '\0') /* not a single call to readlink succeeded */
6125 return (char *)file;
6126 return target;
6130 /* Posix ACL emulation. */
6133 acl_valid (acl_t acl)
6135 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
6138 char *
6139 acl_to_text (acl_t acl, ssize_t *size)
6141 LPTSTR str_acl;
6142 SECURITY_INFORMATION flags =
6143 OWNER_SECURITY_INFORMATION |
6144 GROUP_SECURITY_INFORMATION |
6145 DACL_SECURITY_INFORMATION;
6146 char *retval = NULL;
6147 ULONG local_size;
6148 int e = errno;
6150 errno = 0;
6152 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
6154 errno = e;
6155 /* We don't want to mix heaps, so we duplicate the string in our
6156 heap and free the one allocated by the API. */
6157 retval = xstrdup (str_acl);
6158 if (size)
6159 *size = local_size;
6160 LocalFree (str_acl);
6162 else if (errno != ENOTSUP)
6163 errno = EINVAL;
6165 return retval;
6168 acl_t
6169 acl_from_text (const char *acl_str)
6171 PSECURITY_DESCRIPTOR psd, retval = NULL;
6172 ULONG sd_size;
6173 int e = errno;
6175 errno = 0;
6177 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
6179 errno = e;
6180 retval = xmalloc (sd_size);
6181 memcpy (retval, psd, sd_size);
6182 LocalFree (psd);
6184 else if (errno != ENOTSUP)
6185 errno = EINVAL;
6187 return retval;
6191 acl_free (void *ptr)
6193 xfree (ptr);
6194 return 0;
6197 acl_t
6198 acl_get_file (const char *fname, acl_type_t type)
6200 PSECURITY_DESCRIPTOR psd = NULL;
6201 const char *filename;
6203 if (type == ACL_TYPE_ACCESS)
6205 DWORD sd_len, err;
6206 SECURITY_INFORMATION si =
6207 OWNER_SECURITY_INFORMATION |
6208 GROUP_SECURITY_INFORMATION |
6209 DACL_SECURITY_INFORMATION ;
6210 int e = errno;
6212 filename = map_w32_filename (fname, NULL);
6213 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6214 fname = chase_symlinks (filename);
6215 else
6216 fname = filename;
6218 errno = 0;
6219 if (!get_file_security (fname, si, psd, 0, &sd_len)
6220 && errno != ENOTSUP)
6222 err = GetLastError ();
6223 if (err == ERROR_INSUFFICIENT_BUFFER)
6225 psd = xmalloc (sd_len);
6226 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
6228 xfree (psd);
6229 errno = EIO;
6230 psd = NULL;
6233 else if (err == ERROR_FILE_NOT_FOUND
6234 || err == ERROR_PATH_NOT_FOUND
6235 /* ERROR_INVALID_NAME is what we get if
6236 w32-unicode-filenames is nil and the file cannot
6237 be encoded in the current ANSI codepage. */
6238 || err == ERROR_INVALID_NAME)
6239 errno = ENOENT;
6240 else
6241 errno = EIO;
6243 else if (!errno)
6244 errno = e;
6246 else if (type != ACL_TYPE_DEFAULT)
6247 errno = EINVAL;
6249 return psd;
6253 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
6255 TOKEN_PRIVILEGES old1, old2;
6256 DWORD err;
6257 int st = 0, retval = -1;
6258 SECURITY_INFORMATION flags = 0;
6259 PSID psidOwner, psidGroup;
6260 PACL pacl;
6261 BOOL dflt;
6262 BOOL dacl_present;
6263 int e;
6264 const char *filename;
6266 if (acl_valid (acl) != 0
6267 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
6269 errno = EINVAL;
6270 return -1;
6273 if (type == ACL_TYPE_DEFAULT)
6275 errno = ENOSYS;
6276 return -1;
6279 filename = map_w32_filename (fname, NULL);
6280 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6281 fname = chase_symlinks (filename);
6282 else
6283 fname = filename;
6285 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
6286 &dflt)
6287 && psidOwner)
6288 flags |= OWNER_SECURITY_INFORMATION;
6289 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
6290 &dflt)
6291 && psidGroup)
6292 flags |= GROUP_SECURITY_INFORMATION;
6293 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
6294 &pacl, &dflt)
6295 && dacl_present)
6296 flags |= DACL_SECURITY_INFORMATION;
6297 if (!flags)
6298 return 0;
6300 /* According to KB-245153, setting the owner will succeed if either:
6301 (1) the caller is the user who will be the new owner, and has the
6302 SE_TAKE_OWNERSHIP privilege, or
6303 (2) the caller has the SE_RESTORE privilege, in which case she can
6304 set any valid user or group as the owner
6306 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
6307 privileges, and disregard any failures in obtaining them. If
6308 these privileges cannot be obtained, and do not already exist in
6309 the calling thread's security token, this function could fail
6310 with EPERM. */
6311 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
6312 st++;
6313 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
6314 st++;
6316 e = errno;
6317 errno = 0;
6318 /* SetFileSecurity is deprecated by MS, and sometimes fails when
6319 DACL inheritance is involved, but it seems to preserve ownership
6320 better than SetNamedSecurityInfo, which is important e.g., in
6321 copy-file. */
6322 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
6324 err = GetLastError ();
6326 if (errno != ENOTSUP)
6327 err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
6328 psidOwner, psidGroup, pacl, NULL);
6330 else
6331 err = ERROR_SUCCESS;
6332 if (err != ERROR_SUCCESS)
6334 if (errno == ENOTSUP)
6336 else if (err == ERROR_INVALID_OWNER
6337 || err == ERROR_NOT_ALL_ASSIGNED
6338 || err == ERROR_ACCESS_DENIED)
6340 /* Maybe the requested ACL and the one the file already has
6341 are identical, in which case we can silently ignore the
6342 failure. (And no, Windows doesn't.) */
6343 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
6345 errno = EPERM;
6346 if (current_acl)
6348 char *acl_from = acl_to_text (current_acl, NULL);
6349 char *acl_to = acl_to_text (acl, NULL);
6351 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
6353 retval = 0;
6354 errno = e;
6356 if (acl_from)
6357 acl_free (acl_from);
6358 if (acl_to)
6359 acl_free (acl_to);
6360 acl_free (current_acl);
6363 else if (err == ERROR_FILE_NOT_FOUND
6364 || err == ERROR_PATH_NOT_FOUND
6365 /* ERROR_INVALID_NAME is what we get if
6366 w32-unicode-filenames is nil and the file cannot be
6367 encoded in the current ANSI codepage. */
6368 || err == ERROR_INVALID_NAME)
6369 errno = ENOENT;
6370 else
6371 errno = EACCES;
6373 else
6375 retval = 0;
6376 errno = e;
6379 if (st)
6381 if (st >= 2)
6382 restore_privilege (&old2);
6383 restore_privilege (&old1);
6384 revert_to_self ();
6387 return retval;
6390 /* Return true if errno value ERRNUM indicates that ACLs are well
6391 supported on this system. ERRNUM should be an errno value obtained
6392 after an ACL-related system call fails. */
6393 bool
6394 acl_errno_valid (int errnum)
6396 switch (errnum)
6398 case EBUSY:
6399 case EINVAL:
6400 case ENOTSUP:
6401 return false;
6402 default:
6403 return true;
6408 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
6409 have a fixed max size for file names, so we don't need the kind of
6410 alloc/malloc/realloc dance the gnulib version does. We also don't
6411 support FD-relative symlinks. */
6412 char *
6413 careadlinkat (int fd, char const *filename,
6414 char *buffer, size_t buffer_size,
6415 struct allocator const *alloc,
6416 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6418 char linkname[MAX_UTF8_PATH];
6419 ssize_t link_size;
6421 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6423 if (link_size > 0)
6425 char *retval = buffer;
6427 linkname[link_size++] = '\0';
6428 if (link_size > buffer_size)
6429 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6430 if (retval)
6431 memcpy (retval, linkname, link_size);
6433 return retval;
6435 return NULL;
6439 w32_copy_file (const char *from, const char *to,
6440 int keep_time, int preserve_ownership, int copy_acls)
6442 acl_t acl = NULL;
6443 BOOL copy_result;
6444 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6445 char from_a[MAX_PATH], to_a[MAX_PATH];
6447 /* We ignore preserve_ownership for now. */
6448 preserve_ownership = preserve_ownership;
6450 if (copy_acls)
6452 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6453 if (acl == NULL && acl_errno_valid (errno))
6454 return -2;
6456 if (w32_unicode_filenames)
6458 filename_to_utf16 (from, from_w);
6459 filename_to_utf16 (to, to_w);
6460 copy_result = CopyFileW (from_w, to_w, FALSE);
6462 else
6464 filename_to_ansi (from, from_a);
6465 filename_to_ansi (to, to_a);
6466 copy_result = CopyFileA (from_a, to_a, FALSE);
6468 if (!copy_result)
6470 /* CopyFile doesn't set errno when it fails. By far the most
6471 "popular" reason is that the target is read-only. */
6472 DWORD err = GetLastError ();
6474 switch (err)
6476 case ERROR_FILE_NOT_FOUND:
6477 errno = ENOENT;
6478 break;
6479 case ERROR_ACCESS_DENIED:
6480 errno = EACCES;
6481 break;
6482 case ERROR_ENCRYPTION_FAILED:
6483 errno = EIO;
6484 break;
6485 default:
6486 errno = EPERM;
6487 break;
6490 if (acl)
6491 acl_free (acl);
6492 return -1;
6494 /* CopyFile retains the timestamp by default. However, see
6495 "Community Additions" for CopyFile: it sounds like that is not
6496 entirely true. Testing on Windows XP confirms that modified time
6497 is copied, but creation and last-access times are not.
6498 FIXME? */
6499 else if (!keep_time)
6501 struct timespec now;
6502 DWORD attributes;
6504 if (w32_unicode_filenames)
6506 /* Ensure file is writable while its times are set. */
6507 attributes = GetFileAttributesW (to_w);
6508 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6509 now = current_timespec ();
6510 if (set_file_times (-1, to, now, now))
6512 /* Restore original attributes. */
6513 SetFileAttributesW (to_w, attributes);
6514 if (acl)
6515 acl_free (acl);
6516 return -3;
6518 /* Restore original attributes. */
6519 SetFileAttributesW (to_w, attributes);
6521 else
6523 attributes = GetFileAttributesA (to_a);
6524 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6525 now = current_timespec ();
6526 if (set_file_times (-1, to, now, now))
6528 SetFileAttributesA (to_a, attributes);
6529 if (acl)
6530 acl_free (acl);
6531 return -3;
6533 SetFileAttributesA (to_a, attributes);
6536 if (acl != NULL)
6538 bool fail =
6539 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6540 acl_free (acl);
6541 if (fail && acl_errno_valid (errno))
6542 return -4;
6545 return 0;
6549 /* Support for browsing other processes and their attributes. See
6550 process.c for the Lisp bindings. */
6552 /* Helper wrapper functions. */
6554 static HANDLE WINAPI
6555 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6557 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6559 if (g_b_init_create_toolhelp32_snapshot == 0)
6561 g_b_init_create_toolhelp32_snapshot = 1;
6562 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6563 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6564 "CreateToolhelp32Snapshot");
6566 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6568 return INVALID_HANDLE_VALUE;
6570 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6573 static BOOL WINAPI
6574 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6576 static Process32First_Proc s_pfn_Process32_First = NULL;
6578 if (g_b_init_process32_first == 0)
6580 g_b_init_process32_first = 1;
6581 s_pfn_Process32_First = (Process32First_Proc)
6582 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6583 "Process32First");
6585 if (s_pfn_Process32_First == NULL)
6587 return FALSE;
6589 return (s_pfn_Process32_First (hSnapshot, lppe));
6592 static BOOL WINAPI
6593 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6595 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6597 if (g_b_init_process32_next == 0)
6599 g_b_init_process32_next = 1;
6600 s_pfn_Process32_Next = (Process32Next_Proc)
6601 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6602 "Process32Next");
6604 if (s_pfn_Process32_Next == NULL)
6606 return FALSE;
6608 return (s_pfn_Process32_Next (hSnapshot, lppe));
6611 static BOOL WINAPI
6612 open_thread_token (HANDLE ThreadHandle,
6613 DWORD DesiredAccess,
6614 BOOL OpenAsSelf,
6615 PHANDLE TokenHandle)
6617 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6618 HMODULE hm_advapi32 = NULL;
6619 if (is_windows_9x () == TRUE)
6621 SetLastError (ERROR_NOT_SUPPORTED);
6622 return FALSE;
6624 if (g_b_init_open_thread_token == 0)
6626 g_b_init_open_thread_token = 1;
6627 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6628 s_pfn_Open_Thread_Token =
6629 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6631 if (s_pfn_Open_Thread_Token == NULL)
6633 SetLastError (ERROR_NOT_SUPPORTED);
6634 return FALSE;
6636 return (
6637 s_pfn_Open_Thread_Token (
6638 ThreadHandle,
6639 DesiredAccess,
6640 OpenAsSelf,
6641 TokenHandle)
6645 static BOOL WINAPI
6646 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6648 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6649 HMODULE hm_advapi32 = NULL;
6650 if (is_windows_9x () == TRUE)
6652 return FALSE;
6654 if (g_b_init_impersonate_self == 0)
6656 g_b_init_impersonate_self = 1;
6657 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6658 s_pfn_Impersonate_Self =
6659 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6661 if (s_pfn_Impersonate_Self == NULL)
6663 return FALSE;
6665 return s_pfn_Impersonate_Self (ImpersonationLevel);
6668 static BOOL WINAPI
6669 revert_to_self (void)
6671 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6672 HMODULE hm_advapi32 = NULL;
6673 if (is_windows_9x () == TRUE)
6675 return FALSE;
6677 if (g_b_init_revert_to_self == 0)
6679 g_b_init_revert_to_self = 1;
6680 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6681 s_pfn_Revert_To_Self =
6682 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6684 if (s_pfn_Revert_To_Self == NULL)
6686 return FALSE;
6688 return s_pfn_Revert_To_Self ();
6691 static BOOL WINAPI
6692 get_process_memory_info (HANDLE h_proc,
6693 PPROCESS_MEMORY_COUNTERS mem_counters,
6694 DWORD bufsize)
6696 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6697 HMODULE hm_psapi = NULL;
6698 if (is_windows_9x () == TRUE)
6700 return FALSE;
6702 if (g_b_init_get_process_memory_info == 0)
6704 g_b_init_get_process_memory_info = 1;
6705 hm_psapi = LoadLibrary ("Psapi.dll");
6706 if (hm_psapi)
6707 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6708 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6710 if (s_pfn_Get_Process_Memory_Info == NULL)
6712 return FALSE;
6714 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6717 static BOOL WINAPI
6718 get_process_working_set_size (HANDLE h_proc,
6719 PSIZE_T minrss,
6720 PSIZE_T maxrss)
6722 static GetProcessWorkingSetSize_Proc
6723 s_pfn_Get_Process_Working_Set_Size = NULL;
6725 if (is_windows_9x () == TRUE)
6727 return FALSE;
6729 if (g_b_init_get_process_working_set_size == 0)
6731 g_b_init_get_process_working_set_size = 1;
6732 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6733 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6734 "GetProcessWorkingSetSize");
6736 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6738 return FALSE;
6740 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6743 static BOOL WINAPI
6744 global_memory_status (MEMORYSTATUS *buf)
6746 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6748 if (is_windows_9x () == TRUE)
6750 return FALSE;
6752 if (g_b_init_global_memory_status == 0)
6754 g_b_init_global_memory_status = 1;
6755 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6756 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6757 "GlobalMemoryStatus");
6759 if (s_pfn_Global_Memory_Status == NULL)
6761 return FALSE;
6763 return s_pfn_Global_Memory_Status (buf);
6766 static BOOL WINAPI
6767 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6769 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6771 if (is_windows_9x () == TRUE)
6773 return FALSE;
6775 if (g_b_init_global_memory_status_ex == 0)
6777 g_b_init_global_memory_status_ex = 1;
6778 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6779 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6780 "GlobalMemoryStatusEx");
6782 if (s_pfn_Global_Memory_Status_Ex == NULL)
6784 return FALSE;
6786 return s_pfn_Global_Memory_Status_Ex (buf);
6789 Lisp_Object
6790 list_system_processes (void)
6792 Lisp_Object proclist = Qnil;
6793 HANDLE h_snapshot;
6795 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6797 if (h_snapshot != INVALID_HANDLE_VALUE)
6799 PROCESSENTRY32 proc_entry;
6800 DWORD proc_id;
6801 BOOL res;
6803 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6804 for (res = process32_first (h_snapshot, &proc_entry); res;
6805 res = process32_next (h_snapshot, &proc_entry))
6807 proc_id = proc_entry.th32ProcessID;
6808 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6811 CloseHandle (h_snapshot);
6812 proclist = Fnreverse (proclist);
6815 return proclist;
6818 static int
6819 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6821 TOKEN_PRIVILEGES priv;
6822 DWORD priv_size = sizeof (priv);
6823 DWORD opriv_size = sizeof (*old_priv);
6824 HANDLE h_token = NULL;
6825 HANDLE h_thread = GetCurrentThread ();
6826 int ret_val = 0;
6827 BOOL res;
6829 res = open_thread_token (h_thread,
6830 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6831 FALSE, &h_token);
6832 if (!res && GetLastError () == ERROR_NO_TOKEN)
6834 if (impersonate_self (SecurityImpersonation))
6835 res = open_thread_token (h_thread,
6836 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6837 FALSE, &h_token);
6839 if (res)
6841 priv.PrivilegeCount = 1;
6842 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6843 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6844 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6845 old_priv, &opriv_size)
6846 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6847 ret_val = 1;
6849 if (h_token)
6850 CloseHandle (h_token);
6852 return ret_val;
6855 static int
6856 restore_privilege (TOKEN_PRIVILEGES *priv)
6858 DWORD priv_size = sizeof (*priv);
6859 HANDLE h_token = NULL;
6860 int ret_val = 0;
6862 if (open_thread_token (GetCurrentThread (),
6863 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6864 FALSE, &h_token))
6866 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6867 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6868 ret_val = 1;
6870 if (h_token)
6871 CloseHandle (h_token);
6873 return ret_val;
6876 static Lisp_Object
6877 ltime (ULONGLONG time_100ns)
6879 ULONGLONG time_sec = time_100ns / 10000000;
6880 int subsec = time_100ns % 10000000;
6881 return list4i (time_sec >> 16, time_sec & 0xffff,
6882 subsec / 10, subsec % 10 * 100000);
6885 #define U64_TO_LISP_TIME(time) ltime (time)
6887 static int
6888 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6889 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6890 double *pcpu)
6892 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6893 ULONGLONG tem1, tem2, tem3, tem;
6895 if (!h_proc
6896 || !get_process_times_fn
6897 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6898 &ft_kernel, &ft_user))
6899 return 0;
6901 GetSystemTimeAsFileTime (&ft_current);
6903 FILETIME_TO_U64 (tem1, ft_kernel);
6904 *stime = U64_TO_LISP_TIME (tem1);
6906 FILETIME_TO_U64 (tem2, ft_user);
6907 *utime = U64_TO_LISP_TIME (tem2);
6909 tem3 = tem1 + tem2;
6910 *ttime = U64_TO_LISP_TIME (tem3);
6912 FILETIME_TO_U64 (tem, ft_creation);
6913 /* Process no 4 (System) returns zero creation time. */
6914 if (tem)
6915 tem -= utc_base;
6916 *ctime = U64_TO_LISP_TIME (tem);
6918 if (tem)
6920 FILETIME_TO_U64 (tem3, ft_current);
6921 tem = (tem3 - utc_base) - tem;
6923 *etime = U64_TO_LISP_TIME (tem);
6925 if (tem)
6927 *pcpu = 100.0 * (tem1 + tem2) / tem;
6928 if (*pcpu > 100)
6929 *pcpu = 100.0;
6931 else
6932 *pcpu = 0;
6934 return 1;
6937 Lisp_Object
6938 system_process_attributes (Lisp_Object pid)
6940 Lisp_Object attrs = Qnil;
6941 Lisp_Object cmd_str, decoded_cmd, tem;
6942 HANDLE h_snapshot, h_proc;
6943 DWORD proc_id;
6944 int found_proc = 0;
6945 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
6946 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
6947 DWORD glength = sizeof (gname);
6948 HANDLE token = NULL;
6949 SID_NAME_USE user_type;
6950 unsigned char *buf = NULL;
6951 DWORD blen = 0;
6952 TOKEN_USER user_token;
6953 TOKEN_PRIMARY_GROUP group_token;
6954 unsigned euid;
6955 unsigned egid;
6956 PROCESS_MEMORY_COUNTERS mem;
6957 PROCESS_MEMORY_COUNTERS_EX mem_ex;
6958 SIZE_T minrss, maxrss;
6959 MEMORYSTATUS memst;
6960 MEMORY_STATUS_EX memstex;
6961 double totphys = 0.0;
6962 Lisp_Object ctime, stime, utime, etime, ttime;
6963 double pcpu;
6964 BOOL result = FALSE;
6966 CHECK_NUMBER_OR_FLOAT (pid);
6967 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
6969 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6971 if (h_snapshot != INVALID_HANDLE_VALUE)
6973 PROCESSENTRY32 pe;
6974 BOOL res;
6976 pe.dwSize = sizeof (PROCESSENTRY32);
6977 for (res = process32_first (h_snapshot, &pe); res;
6978 res = process32_next (h_snapshot, &pe))
6980 if (proc_id == pe.th32ProcessID)
6982 if (proc_id == 0)
6983 decoded_cmd = build_string ("Idle");
6984 else
6986 /* Decode the command name from locale-specific
6987 encoding. */
6988 cmd_str = build_unibyte_string (pe.szExeFile);
6990 decoded_cmd =
6991 code_convert_string_norecord (cmd_str,
6992 Vlocale_coding_system, 0);
6994 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
6995 attrs = Fcons (Fcons (Qppid,
6996 make_fixnum_or_float (pe.th32ParentProcessID)),
6997 attrs);
6998 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
6999 attrs);
7000 attrs = Fcons (Fcons (Qthcount,
7001 make_fixnum_or_float (pe.cntThreads)),
7002 attrs);
7003 found_proc = 1;
7004 break;
7008 CloseHandle (h_snapshot);
7011 if (!found_proc)
7012 return Qnil;
7014 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
7015 FALSE, proc_id);
7016 /* If we were denied a handle to the process, try again after
7017 enabling the SeDebugPrivilege in our process. */
7018 if (!h_proc)
7020 TOKEN_PRIVILEGES priv_current;
7022 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
7024 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
7025 FALSE, proc_id);
7026 restore_privilege (&priv_current);
7027 revert_to_self ();
7030 if (h_proc)
7032 result = open_process_token (h_proc, TOKEN_QUERY, &token);
7033 if (result)
7035 result = get_token_information (token, TokenUser, NULL, 0, &blen);
7036 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7038 buf = xmalloc (blen);
7039 result = get_token_information (token, TokenUser,
7040 (LPVOID)buf, blen, &needed);
7041 if (result)
7043 memcpy (&user_token, buf, sizeof (user_token));
7044 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
7046 euid = get_rid (user_token.User.Sid);
7047 result = lookup_account_sid (NULL, user_token.User.Sid,
7048 uname, &ulength,
7049 domain, &dlength,
7050 &user_type);
7051 if (result)
7052 w32_add_to_cache (user_token.User.Sid, euid, uname);
7053 else
7055 strcpy (uname, "unknown");
7056 result = TRUE;
7059 ulength = strlen (uname);
7063 if (result)
7065 /* Determine a reasonable euid and gid values. */
7066 if (xstrcasecmp ("administrator", uname) == 0)
7068 euid = 500; /* well-known Administrator uid */
7069 egid = 513; /* well-known None gid */
7071 else
7073 /* Get group id and name. */
7074 result = get_token_information (token, TokenPrimaryGroup,
7075 (LPVOID)buf, blen, &needed);
7076 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7078 buf = xrealloc (buf, blen = needed);
7079 result = get_token_information (token, TokenPrimaryGroup,
7080 (LPVOID)buf, blen, &needed);
7082 if (result)
7084 memcpy (&group_token, buf, sizeof (group_token));
7085 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
7087 egid = get_rid (group_token.PrimaryGroup);
7088 dlength = sizeof (domain);
7089 result =
7090 lookup_account_sid (NULL, group_token.PrimaryGroup,
7091 gname, &glength, NULL, &dlength,
7092 &user_type);
7093 if (result)
7094 w32_add_to_cache (group_token.PrimaryGroup,
7095 egid, gname);
7096 else
7098 strcpy (gname, "None");
7099 result = TRUE;
7102 glength = strlen (gname);
7106 xfree (buf);
7108 if (!result)
7110 if (!is_windows_9x ())
7112 /* We couldn't open the process token, presumably because of
7113 insufficient access rights. Assume this process is run
7114 by the system. */
7115 strcpy (uname, "SYSTEM");
7116 strcpy (gname, "None");
7117 euid = 18; /* SYSTEM */
7118 egid = 513; /* None */
7119 glength = strlen (gname);
7120 ulength = strlen (uname);
7122 /* If we are running under Windows 9X, where security calls are
7123 not supported, we assume all processes are run by the current
7124 user. */
7125 else if (GetUserName (uname, &ulength))
7127 if (xstrcasecmp ("administrator", uname) == 0)
7128 euid = 0;
7129 else
7130 euid = 123;
7131 egid = euid;
7132 strcpy (gname, "None");
7133 glength = strlen (gname);
7134 ulength = strlen (uname);
7136 else
7138 euid = 123;
7139 egid = 123;
7140 strcpy (uname, "administrator");
7141 ulength = strlen (uname);
7142 strcpy (gname, "None");
7143 glength = strlen (gname);
7145 if (token)
7146 CloseHandle (token);
7149 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
7150 tem = make_unibyte_string (uname, ulength);
7151 attrs = Fcons (Fcons (Quser,
7152 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7153 attrs);
7154 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
7155 tem = make_unibyte_string (gname, glength);
7156 attrs = Fcons (Fcons (Qgroup,
7157 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7158 attrs);
7160 if (global_memory_status_ex (&memstex))
7161 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
7162 totphys = memstex.ullTotalPhys / 1024.0;
7163 #else
7164 /* Visual Studio 6 cannot convert an unsigned __int64 type to
7165 double, so we need to do this for it... */
7167 DWORD tot_hi = memstex.ullTotalPhys >> 32;
7168 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
7169 DWORD tot_lo = memstex.ullTotalPhys % 1024;
7171 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
7173 #endif /* __GNUC__ || _MSC_VER >= 1300 */
7174 else if (global_memory_status (&memst))
7175 totphys = memst.dwTotalPhys / 1024.0;
7177 if (h_proc
7178 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
7179 sizeof (mem_ex)))
7181 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7183 attrs = Fcons (Fcons (Qmajflt,
7184 make_fixnum_or_float (mem_ex.PageFaultCount)),
7185 attrs);
7186 attrs = Fcons (Fcons (Qvsize,
7187 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
7188 attrs);
7189 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7190 if (totphys)
7191 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7193 else if (h_proc
7194 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
7196 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7198 attrs = Fcons (Fcons (Qmajflt,
7199 make_fixnum_or_float (mem.PageFaultCount)),
7200 attrs);
7201 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7202 if (totphys)
7203 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7205 else if (h_proc
7206 && get_process_working_set_size (h_proc, &minrss, &maxrss))
7208 DWORD rss = maxrss / 1024;
7210 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
7211 if (totphys)
7212 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7215 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
7217 attrs = Fcons (Fcons (Qutime, utime), attrs);
7218 attrs = Fcons (Fcons (Qstime, stime), attrs);
7219 attrs = Fcons (Fcons (Qtime, ttime), attrs);
7220 attrs = Fcons (Fcons (Qstart, ctime), attrs);
7221 attrs = Fcons (Fcons (Qetime, etime), attrs);
7222 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
7225 /* FIXME: Retrieve command line by walking the PEB of the process. */
7227 if (h_proc)
7228 CloseHandle (h_proc);
7229 return attrs;
7233 w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
7234 unsigned long long *totalswap, unsigned long long *freeswap)
7236 MEMORYSTATUS memst;
7237 MEMORY_STATUS_EX memstex;
7239 /* Use GlobalMemoryStatusEx if available, as it can report more than
7240 2GB of memory. */
7241 if (global_memory_status_ex (&memstex))
7243 *totalram = memstex.ullTotalPhys;
7244 *freeram = memstex.ullAvailPhys;
7245 *totalswap = memstex.ullTotalPageFile;
7246 *freeswap = memstex.ullAvailPageFile;
7247 return 0;
7249 else if (global_memory_status (&memst))
7251 *totalram = memst.dwTotalPhys;
7252 *freeram = memst.dwAvailPhys;
7253 *totalswap = memst.dwTotalPageFile;
7254 *freeswap = memst.dwAvailPageFile;
7255 return 0;
7257 else
7258 return -1;
7262 /* Wrappers for winsock functions to map between our file descriptors
7263 and winsock's handles; also set h_errno for convenience.
7265 To allow Emacs to run on systems which don't have winsock support
7266 installed, we dynamically link to winsock on startup if present, and
7267 otherwise provide the minimum necessary functionality
7268 (eg. gethostname). */
7270 /* function pointers for relevant socket functions */
7271 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
7272 void (PASCAL *pfn_WSASetLastError) (int iError);
7273 int (PASCAL *pfn_WSAGetLastError) (void);
7274 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
7275 int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject,
7276 WSANETWORKEVENTS *NetworkEvents);
7278 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
7279 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
7280 int (PASCAL *pfn_socket) (int af, int type, int protocol);
7281 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
7282 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
7283 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
7284 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
7285 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
7286 int (PASCAL *pfn_closesocket) (SOCKET s);
7287 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
7288 int (PASCAL *pfn_WSACleanup) (void);
7290 u_short (PASCAL *pfn_htons) (u_short hostshort);
7291 u_short (PASCAL *pfn_ntohs) (u_short netshort);
7292 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
7293 int (PASCAL *pfn_gethostname) (char * name, int namelen);
7294 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
7295 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
7296 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
7297 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
7298 const char * optval, int optlen);
7299 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
7300 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
7301 int * namelen);
7302 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
7303 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
7304 struct sockaddr * from, int * fromlen);
7305 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
7306 const struct sockaddr * to, int tolen);
7308 int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
7309 const struct addrinfo *, struct addrinfo **);
7310 void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
7312 /* SetHandleInformation is only needed to make sockets non-inheritable. */
7313 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7314 #ifndef HANDLE_FLAG_INHERIT
7315 #define HANDLE_FLAG_INHERIT 1
7316 #endif
7318 HANDLE winsock_lib;
7319 static int winsock_inuse;
7321 BOOL term_winsock (void);
7323 BOOL
7324 term_winsock (void)
7326 if (winsock_lib != NULL && winsock_inuse == 0)
7328 release_listen_threads ();
7329 /* Not sure what would cause WSAENETDOWN, or even if it can happen
7330 after WSAStartup returns successfully, but it seems reasonable
7331 to allow unloading winsock anyway in that case. */
7332 if (pfn_WSACleanup () == 0 ||
7333 pfn_WSAGetLastError () == WSAENETDOWN)
7335 if (FreeLibrary (winsock_lib))
7336 winsock_lib = NULL;
7337 return TRUE;
7340 return FALSE;
7343 BOOL
7344 init_winsock (int load_now)
7346 WSADATA winsockData;
7348 if (winsock_lib != NULL)
7349 return TRUE;
7351 pfn_SetHandleInformation
7352 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
7353 "SetHandleInformation");
7355 winsock_lib = LoadLibrary ("Ws2_32.dll");
7357 if (winsock_lib != NULL)
7359 /* dynamically link to socket functions */
7361 #define LOAD_PROC(fn) \
7362 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
7363 goto fail;
7365 LOAD_PROC (WSAStartup);
7366 LOAD_PROC (WSASetLastError);
7367 LOAD_PROC (WSAGetLastError);
7368 LOAD_PROC (WSAEventSelect);
7369 LOAD_PROC (WSAEnumNetworkEvents);
7370 LOAD_PROC (WSACreateEvent);
7371 LOAD_PROC (WSACloseEvent);
7372 LOAD_PROC (socket);
7373 LOAD_PROC (bind);
7374 LOAD_PROC (connect);
7375 LOAD_PROC (ioctlsocket);
7376 LOAD_PROC (recv);
7377 LOAD_PROC (send);
7378 LOAD_PROC (closesocket);
7379 LOAD_PROC (shutdown);
7380 LOAD_PROC (htons);
7381 LOAD_PROC (ntohs);
7382 LOAD_PROC (inet_addr);
7383 LOAD_PROC (gethostname);
7384 LOAD_PROC (gethostbyname);
7385 LOAD_PROC (getservbyname);
7386 LOAD_PROC (getpeername);
7387 LOAD_PROC (WSACleanup);
7388 LOAD_PROC (setsockopt);
7389 LOAD_PROC (listen);
7390 LOAD_PROC (getsockname);
7391 LOAD_PROC (accept);
7392 LOAD_PROC (recvfrom);
7393 LOAD_PROC (sendto);
7394 #undef LOAD_PROC
7396 /* Try loading functions not available before XP. */
7397 pfn_getaddrinfo = (void *) GetProcAddress (winsock_lib, "getaddrinfo");
7398 pfn_freeaddrinfo = (void *) GetProcAddress (winsock_lib, "freeaddrinfo");
7399 /* Paranoia: these two functions should go together, so if one
7400 is absent, we cannot use the other. */
7401 if (pfn_getaddrinfo == NULL)
7402 pfn_freeaddrinfo = NULL;
7403 else if (pfn_freeaddrinfo == NULL)
7404 pfn_getaddrinfo = NULL;
7406 /* specify version 1.1 of winsock */
7407 if (pfn_WSAStartup (0x101, &winsockData) == 0)
7409 if (winsockData.wVersion != 0x101)
7410 goto fail;
7412 if (!load_now)
7414 /* Report that winsock exists and is usable, but leave
7415 socket functions disabled. I am assuming that calling
7416 WSAStartup does not require any network interaction,
7417 and in particular does not cause or require a dial-up
7418 connection to be established. */
7420 pfn_WSACleanup ();
7421 FreeLibrary (winsock_lib);
7422 winsock_lib = NULL;
7424 winsock_inuse = 0;
7425 return TRUE;
7428 fail:
7429 FreeLibrary (winsock_lib);
7430 winsock_lib = NULL;
7433 return FALSE;
7437 int h_errno = 0;
7439 /* Function to map winsock error codes to errno codes for those errno
7440 code defined in errno.h (errno values not defined by errno.h are
7441 already in nt/inc/sys/socket.h). */
7442 static void
7443 set_errno (void)
7445 int wsa_err;
7447 h_errno = 0;
7448 if (winsock_lib == NULL)
7449 wsa_err = EINVAL;
7450 else
7451 wsa_err = pfn_WSAGetLastError ();
7453 switch (wsa_err)
7455 case WSAEACCES: errno = EACCES; break;
7456 case WSAEBADF: errno = EBADF; break;
7457 case WSAEFAULT: errno = EFAULT; break;
7458 case WSAEINTR: errno = EINTR; break;
7459 case WSAEINVAL: errno = EINVAL; break;
7460 case WSAEMFILE: errno = EMFILE; break;
7461 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7462 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7463 case WSAEWOULDBLOCK: errno = EWOULDBLOCK; break;
7464 case WSAENOTCONN: errno = ENOTCONN; break;
7465 default: errno = wsa_err; break;
7469 static void
7470 check_errno (void)
7472 h_errno = 0;
7473 if (winsock_lib != NULL)
7474 pfn_WSASetLastError (0);
7477 /* Extend strerror to handle the winsock-specific error codes. */
7478 struct {
7479 int errnum;
7480 const char * msg;
7481 } _wsa_errlist[] = {
7482 {WSAEINTR , "Interrupted function call"},
7483 {WSAEBADF , "Bad file descriptor"},
7484 {WSAEACCES , "Permission denied"},
7485 {WSAEFAULT , "Bad address"},
7486 {WSAEINVAL , "Invalid argument"},
7487 {WSAEMFILE , "Too many open files"},
7489 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7490 {WSAEINPROGRESS , "Operation now in progress"},
7491 {WSAEALREADY , "Operation already in progress"},
7492 {WSAENOTSOCK , "Socket operation on non-socket"},
7493 {WSAEDESTADDRREQ , "Destination address required"},
7494 {WSAEMSGSIZE , "Message too long"},
7495 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7496 {WSAENOPROTOOPT , "Bad protocol option"},
7497 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7498 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7499 {WSAEOPNOTSUPP , "Operation not supported"},
7500 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7501 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7502 {WSAEADDRINUSE , "Address already in use"},
7503 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7504 {WSAENETDOWN , "Network is down"},
7505 {WSAENETUNREACH , "Network is unreachable"},
7506 {WSAENETRESET , "Network dropped connection on reset"},
7507 {WSAECONNABORTED , "Software caused connection abort"},
7508 {WSAECONNRESET , "Connection reset by peer"},
7509 {WSAENOBUFS , "No buffer space available"},
7510 {WSAEISCONN , "Socket is already connected"},
7511 {WSAENOTCONN , "Socket is not connected"},
7512 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7513 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7514 {WSAETIMEDOUT , "Connection timed out"},
7515 {WSAECONNREFUSED , "Connection refused"},
7516 {WSAELOOP , "Network loop"}, /* not sure */
7517 {WSAENAMETOOLONG , "Name is too long"},
7518 {WSAEHOSTDOWN , "Host is down"},
7519 {WSAEHOSTUNREACH , "No route to host"},
7520 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7521 {WSAEPROCLIM , "Too many processes"},
7522 {WSAEUSERS , "Too many users"}, /* not sure */
7523 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7524 {WSAESTALE , "Data is stale"}, /* not sure */
7525 {WSAEREMOTE , "Remote error"}, /* not sure */
7527 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7528 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7529 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7530 {WSAEDISCON , "Graceful shutdown in progress"},
7531 #ifdef WSAENOMORE
7532 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7533 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7534 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7535 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7536 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7537 {WSASYSCALLFAILURE , "System call failure"},
7538 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7539 {WSATYPE_NOT_FOUND , "Class type not found"},
7540 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7541 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7542 {WSAEREFUSED , "Operation refused"}, /* not sure */
7543 #endif
7545 {WSAHOST_NOT_FOUND , "Host not found"},
7546 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7547 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7548 {WSANO_DATA , "Valid name, no data record of requested type"},
7550 {-1, NULL}
7553 char *
7554 sys_strerror (int error_no)
7556 int i;
7557 static char unknown_msg[40];
7559 if (error_no >= 0 && error_no < sys_nerr)
7560 return sys_errlist[error_no];
7562 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7563 if (_wsa_errlist[i].errnum == error_no)
7564 return (char *)_wsa_errlist[i].msg;
7566 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7567 return unknown_msg;
7570 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7571 but I believe the method of keeping the socket handle separate (and
7572 insuring it is not inheritable) is the correct one. */
7574 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7576 static int socket_to_fd (SOCKET s);
7579 sys_socket (int af, int type, int protocol)
7581 SOCKET s;
7583 if (winsock_lib == NULL)
7585 errno = ENETDOWN;
7586 return -1;
7589 check_errno ();
7591 /* call the real socket function */
7592 s = pfn_socket (af, type, protocol);
7594 if (s != INVALID_SOCKET)
7595 return socket_to_fd (s);
7597 set_errno ();
7598 return -1;
7601 /* Convert a SOCKET to a file descriptor. */
7602 static int
7603 socket_to_fd (SOCKET s)
7605 int fd;
7606 child_process * cp;
7608 /* Although under NT 3.5 _open_osfhandle will accept a socket
7609 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7610 that does not work under NT 3.1. However, we can get the same
7611 effect by using a backdoor function to replace an existing
7612 descriptor handle with the one we want. */
7614 /* allocate a file descriptor (with appropriate flags) */
7615 fd = _open ("NUL:", _O_RDWR);
7616 if (fd >= 0)
7618 /* Make a non-inheritable copy of the socket handle. Note
7619 that it is possible that sockets aren't actually kernel
7620 handles, which appears to be the case on Windows 9x when
7621 the MS Proxy winsock client is installed. */
7623 /* Apparently there is a bug in NT 3.51 with some service
7624 packs, which prevents using DuplicateHandle to make a
7625 socket handle non-inheritable (causes WSACleanup to
7626 hang). The work-around is to use SetHandleInformation
7627 instead if it is available and implemented. */
7628 if (pfn_SetHandleInformation)
7630 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7632 else
7634 HANDLE parent = GetCurrentProcess ();
7635 HANDLE new_s = INVALID_HANDLE_VALUE;
7637 if (DuplicateHandle (parent,
7638 (HANDLE) s,
7639 parent,
7640 &new_s,
7642 FALSE,
7643 DUPLICATE_SAME_ACCESS))
7645 /* It is possible that DuplicateHandle succeeds even
7646 though the socket wasn't really a kernel handle,
7647 because a real handle has the same value. So
7648 test whether the new handle really is a socket. */
7649 unsigned long nonblocking = 0;
7650 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7652 pfn_closesocket (s);
7653 s = (SOCKET) new_s;
7655 else
7657 CloseHandle (new_s);
7662 eassert (fd < MAXDESC);
7663 fd_info[fd].hnd = (HANDLE) s;
7665 /* set our own internal flags */
7666 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7668 cp = new_child ();
7669 if (cp)
7671 cp->fd = fd;
7672 cp->status = STATUS_READ_ACKNOWLEDGED;
7674 /* attach child_process to fd_info */
7675 if (fd_info[ fd ].cp != NULL)
7677 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7678 emacs_abort ();
7681 fd_info[ fd ].cp = cp;
7683 /* success! */
7684 winsock_inuse++; /* count open sockets */
7685 return fd;
7688 /* clean up */
7689 _close (fd);
7691 else
7692 pfn_closesocket (s);
7693 errno = EMFILE;
7694 return -1;
7698 sys_bind (int s, const struct sockaddr * addr, int namelen)
7700 if (winsock_lib == NULL)
7702 errno = ENOTSOCK;
7703 return SOCKET_ERROR;
7706 check_errno ();
7707 if (fd_info[s].flags & FILE_SOCKET)
7709 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7710 if (rc == SOCKET_ERROR)
7711 set_errno ();
7712 return rc;
7714 errno = ENOTSOCK;
7715 return SOCKET_ERROR;
7719 sys_connect (int s, const struct sockaddr * name, int namelen)
7721 if (winsock_lib == NULL)
7723 errno = ENOTSOCK;
7724 return SOCKET_ERROR;
7727 check_errno ();
7728 if (fd_info[s].flags & FILE_SOCKET)
7730 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7731 if (rc == SOCKET_ERROR)
7733 set_errno ();
7734 /* If this is a non-blocking 'connect', set the bit in flags
7735 that will tell reader_thread to wait for connection
7736 before trying to read. */
7737 if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0)
7739 errno = EINPROGRESS; /* that's what process.c expects */
7740 fd_info[s].flags |= FILE_CONNECT;
7743 return rc;
7745 errno = ENOTSOCK;
7746 return SOCKET_ERROR;
7749 u_short
7750 sys_htons (u_short hostshort)
7752 return (winsock_lib != NULL) ?
7753 pfn_htons (hostshort) : hostshort;
7756 u_short
7757 sys_ntohs (u_short netshort)
7759 return (winsock_lib != NULL) ?
7760 pfn_ntohs (netshort) : netshort;
7763 unsigned long
7764 sys_inet_addr (const char * cp)
7766 return (winsock_lib != NULL) ?
7767 pfn_inet_addr (cp) : INADDR_NONE;
7771 sys_gethostname (char * name, int namelen)
7773 if (winsock_lib != NULL)
7775 int retval;
7777 check_errno ();
7778 retval = pfn_gethostname (name, namelen);
7779 if (retval == SOCKET_ERROR)
7780 set_errno ();
7781 return retval;
7784 if (namelen > MAX_COMPUTERNAME_LENGTH)
7785 return !GetComputerName (name, (DWORD *)&namelen);
7787 errno = EFAULT;
7788 return SOCKET_ERROR;
7791 struct hostent *
7792 sys_gethostbyname (const char * name)
7794 struct hostent * host;
7795 int h_err = h_errno;
7797 if (winsock_lib == NULL)
7799 h_errno = NO_RECOVERY;
7800 errno = ENETDOWN;
7801 return NULL;
7804 check_errno ();
7805 host = pfn_gethostbyname (name);
7806 if (!host)
7808 set_errno ();
7809 h_errno = errno;
7811 else
7812 h_errno = h_err;
7813 return host;
7816 struct servent *
7817 sys_getservbyname (const char * name, const char * proto)
7819 struct servent * serv;
7821 if (winsock_lib == NULL)
7823 errno = ENETDOWN;
7824 return NULL;
7827 check_errno ();
7828 serv = pfn_getservbyname (name, proto);
7829 if (!serv)
7830 set_errno ();
7831 return serv;
7835 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7837 if (winsock_lib == NULL)
7839 errno = ENETDOWN;
7840 return SOCKET_ERROR;
7843 check_errno ();
7844 if (fd_info[s].flags & FILE_SOCKET)
7846 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7847 if (rc == SOCKET_ERROR)
7848 set_errno ();
7849 return rc;
7851 errno = ENOTSOCK;
7852 return SOCKET_ERROR;
7856 sys_getaddrinfo (const char *node, const char *service,
7857 const struct addrinfo *hints, struct addrinfo **res)
7859 int rc;
7861 if (winsock_lib == NULL)
7863 errno = ENETDOWN;
7864 return SOCKET_ERROR;
7867 check_errno ();
7868 if (pfn_getaddrinfo)
7869 rc = pfn_getaddrinfo (node, service, hints, res);
7870 else
7872 int port = 0;
7873 struct hostent *host_info;
7874 struct gai_storage {
7875 struct addrinfo addrinfo;
7876 struct sockaddr_in sockaddr_in;
7877 } *gai_storage;
7879 /* We don't (yet) support any flags, as Emacs doesn't need that. */
7880 if (hints && hints->ai_flags != 0)
7881 return WSAEINVAL;
7882 /* NODE cannot be NULL, since process.c has fallbacks for that. */
7883 if (!node)
7884 return WSAHOST_NOT_FOUND;
7886 if (service)
7888 const char *protocol =
7889 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
7890 struct servent *srv = sys_getservbyname (service, protocol);
7892 if (srv)
7893 port = srv->s_port;
7894 else if (*service >= '0' && *service <= '9')
7896 char *endp;
7898 port = strtoul (service, &endp, 10);
7899 if (*endp || port > 65536)
7900 return WSAHOST_NOT_FOUND;
7901 port = sys_htons ((unsigned short) port);
7903 else
7904 return WSAHOST_NOT_FOUND;
7907 gai_storage = xzalloc (sizeof *gai_storage);
7908 gai_storage->sockaddr_in.sin_port = port;
7909 host_info = sys_gethostbyname (node);
7910 if (host_info)
7912 memcpy (&gai_storage->sockaddr_in.sin_addr,
7913 host_info->h_addr, host_info->h_length);
7914 gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
7916 else
7918 /* Attempt to interpret host as numeric inet address. */
7919 unsigned long numeric_addr = sys_inet_addr (node);
7921 if (numeric_addr == -1)
7923 free (gai_storage);
7924 return WSAHOST_NOT_FOUND;
7927 memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
7928 sizeof (gai_storage->sockaddr_in.sin_addr));
7929 gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
7932 gai_storage->addrinfo.ai_addr =
7933 (struct sockaddr *)&gai_storage->sockaddr_in;
7934 gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
7935 gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
7936 gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
7937 gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
7938 gai_storage->addrinfo.ai_next = NULL;
7940 *res = &gai_storage->addrinfo;
7941 rc = 0;
7944 return rc;
7947 void
7948 sys_freeaddrinfo (struct addrinfo *ai)
7950 if (winsock_lib == NULL)
7952 errno = ENETDOWN;
7953 return;
7956 check_errno ();
7957 if (pfn_freeaddrinfo)
7958 pfn_freeaddrinfo (ai);
7959 else
7961 eassert (ai->ai_next == NULL);
7962 xfree (ai);
7967 sys_shutdown (int s, int how)
7969 if (winsock_lib == NULL)
7971 errno = ENETDOWN;
7972 return SOCKET_ERROR;
7975 check_errno ();
7976 if (fd_info[s].flags & FILE_SOCKET)
7978 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
7979 if (rc == SOCKET_ERROR)
7980 set_errno ();
7981 return rc;
7983 errno = ENOTSOCK;
7984 return SOCKET_ERROR;
7988 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
7990 if (winsock_lib == NULL)
7992 errno = ENETDOWN;
7993 return SOCKET_ERROR;
7996 check_errno ();
7997 if (fd_info[s].flags & FILE_SOCKET)
7999 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
8000 (const char *)optval, optlen);
8001 if (rc == SOCKET_ERROR)
8002 set_errno ();
8003 return rc;
8005 errno = ENOTSOCK;
8006 return SOCKET_ERROR;
8010 sys_listen (int s, int backlog)
8012 if (winsock_lib == NULL)
8014 errno = ENETDOWN;
8015 return SOCKET_ERROR;
8018 check_errno ();
8019 if (fd_info[s].flags & FILE_SOCKET)
8021 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
8022 if (rc == SOCKET_ERROR)
8023 set_errno ();
8024 else
8025 fd_info[s].flags |= FILE_LISTEN;
8026 return rc;
8028 errno = ENOTSOCK;
8029 return SOCKET_ERROR;
8033 sys_getsockname (int s, struct sockaddr * name, int * namelen)
8035 if (winsock_lib == NULL)
8037 errno = ENETDOWN;
8038 return SOCKET_ERROR;
8041 check_errno ();
8042 if (fd_info[s].flags & FILE_SOCKET)
8044 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
8045 if (rc == SOCKET_ERROR)
8046 set_errno ();
8047 return rc;
8049 errno = ENOTSOCK;
8050 return SOCKET_ERROR;
8054 sys_accept (int s, struct sockaddr * addr, int * addrlen)
8056 if (winsock_lib == NULL)
8058 errno = ENETDOWN;
8059 return -1;
8062 check_errno ();
8063 if (fd_info[s].flags & FILE_LISTEN)
8065 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
8066 int fd = -1;
8067 if (t == INVALID_SOCKET)
8068 set_errno ();
8069 else
8070 fd = socket_to_fd (t);
8072 if (fd >= 0)
8074 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
8075 ResetEvent (fd_info[s].cp->char_avail);
8077 return fd;
8079 errno = ENOTSOCK;
8080 return -1;
8084 sys_recvfrom (int s, char * buf, int len, int flags,
8085 struct sockaddr * from, int * fromlen)
8087 if (winsock_lib == NULL)
8089 errno = ENETDOWN;
8090 return SOCKET_ERROR;
8093 check_errno ();
8094 if (fd_info[s].flags & FILE_SOCKET)
8096 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
8097 if (rc == SOCKET_ERROR)
8098 set_errno ();
8099 return rc;
8101 errno = ENOTSOCK;
8102 return SOCKET_ERROR;
8106 sys_sendto (int s, const char * buf, int len, int flags,
8107 const struct sockaddr * to, int tolen)
8109 if (winsock_lib == NULL)
8111 errno = ENETDOWN;
8112 return SOCKET_ERROR;
8115 check_errno ();
8116 if (fd_info[s].flags & FILE_SOCKET)
8118 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
8119 if (rc == SOCKET_ERROR)
8120 set_errno ();
8121 return rc;
8123 errno = ENOTSOCK;
8124 return SOCKET_ERROR;
8127 /* Windows does not have an fcntl function. Provide an implementation
8128 good enough for Emacs. */
8130 fcntl (int s, int cmd, int options)
8132 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
8133 invoked in a context where fd1 is closed and all descriptors less
8134 than fd1 are open, so sys_dup is an adequate implementation. */
8135 if (cmd == F_DUPFD_CLOEXEC)
8136 return sys_dup (s);
8138 check_errno ();
8139 if (fd_info[s].flags & FILE_SOCKET)
8141 if (winsock_lib == NULL)
8143 errno = ENETDOWN;
8144 return -1;
8147 if (cmd == F_SETFL && options == O_NONBLOCK)
8149 unsigned long nblock = 1;
8150 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
8151 if (rc == SOCKET_ERROR)
8152 set_errno ();
8153 /* Keep track of the fact that we set this to non-blocking. */
8154 fd_info[s].flags |= FILE_NDELAY;
8155 return rc;
8157 else
8159 errno = EINVAL;
8160 return SOCKET_ERROR;
8163 else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE))
8164 == (FILE_PIPE | FILE_WRITE))
8166 /* Force our writes to pipes be non-blocking. */
8167 if (cmd == F_SETFL && options == O_NONBLOCK)
8169 HANDLE h = (HANDLE)_get_osfhandle (s);
8170 DWORD pipe_mode = PIPE_NOWAIT;
8172 if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL))
8174 DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ()));
8175 return SOCKET_ERROR;
8177 fd_info[s].flags |= FILE_NDELAY;
8178 return 0;
8180 else
8182 errno = EINVAL;
8183 return SOCKET_ERROR;
8186 errno = ENOTSOCK;
8187 return SOCKET_ERROR;
8191 /* Shadow main io functions: we need to handle pipes and sockets more
8192 intelligently. */
8195 sys_close (int fd)
8197 int rc;
8199 if (fd < 0)
8201 errno = EBADF;
8202 return -1;
8205 if (fd < MAXDESC && fd_info[fd].cp)
8207 child_process * cp = fd_info[fd].cp;
8209 fd_info[fd].cp = NULL;
8211 if (CHILD_ACTIVE (cp))
8213 /* if last descriptor to active child_process then cleanup */
8214 int i;
8215 for (i = 0; i < MAXDESC; i++)
8217 if (i == fd)
8218 continue;
8219 if (fd_info[i].cp == cp)
8220 break;
8222 if (i == MAXDESC)
8224 if (fd_info[fd].flags & FILE_SOCKET)
8226 if (winsock_lib == NULL) emacs_abort ();
8228 pfn_shutdown (SOCK_HANDLE (fd), 2);
8229 rc = pfn_closesocket (SOCK_HANDLE (fd));
8231 winsock_inuse--; /* count open sockets */
8233 /* If the process handle is NULL, it's either a socket
8234 or serial connection, or a subprocess that was
8235 already reaped by reap_subprocess, but whose
8236 resources were not yet freed, because its output was
8237 not fully read yet by the time it was reaped. (This
8238 usually happens with async subprocesses whose output
8239 is being read by Emacs.) Otherwise, this process was
8240 not reaped yet, so we set its FD to a negative value
8241 to make sure sys_select will eventually get to
8242 calling the SIGCHLD handler for it, which will then
8243 invoke waitpid and reap_subprocess. */
8244 if (cp->procinfo.hProcess == NULL)
8245 delete_child (cp);
8246 else
8247 cp->fd = -1;
8252 if (fd >= 0 && fd < MAXDESC)
8253 fd_info[fd].flags = 0;
8255 /* Note that sockets do not need special treatment here (at least on
8256 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
8257 closesocket is equivalent to CloseHandle, which is to be expected
8258 because socket handles are fully fledged kernel handles. */
8259 rc = _close (fd);
8261 return rc;
8265 sys_dup (int fd)
8267 int new_fd;
8269 new_fd = _dup (fd);
8270 if (new_fd >= 0 && new_fd < MAXDESC)
8272 /* duplicate our internal info as well */
8273 fd_info[new_fd] = fd_info[fd];
8275 return new_fd;
8279 sys_dup2 (int src, int dst)
8281 int rc;
8283 if (dst < 0 || dst >= MAXDESC)
8285 errno = EBADF;
8286 return -1;
8289 /* MS _dup2 seems to have weird side effect when invoked with 2
8290 identical arguments: an attempt to fclose the corresponding stdio
8291 stream after that hangs (we do close standard streams in
8292 init_ntproc). Attempt to avoid that by not calling _dup2 that
8293 way: if SRC is valid, we know that dup2 should be a no-op, so do
8294 nothing and return DST. */
8295 if (src == dst)
8297 if ((HANDLE)_get_osfhandle (src) == INVALID_HANDLE_VALUE)
8299 errno = EBADF;
8300 return -1;
8302 return dst;
8305 /* Make sure we close the destination first if it's a pipe or socket. */
8306 if (fd_info[dst].flags != 0)
8307 sys_close (dst);
8309 rc = _dup2 (src, dst);
8310 if (rc == 0)
8312 /* Duplicate our internal info as well. */
8313 fd_info[dst] = fd_info[src];
8315 return rc == 0 ? dst : rc;
8319 pipe2 (int * phandles, int pipe2_flags)
8321 int rc;
8322 unsigned flags;
8323 unsigned pipe_size = 0;
8325 eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
8327 /* Allow Lisp to override the default buffer size of the pipe. */
8328 if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
8329 pipe_size = w32_pipe_buffer_size;
8331 /* make pipe handles non-inheritable; when we spawn a child, we
8332 replace the relevant handle with an inheritable one. Also put
8333 pipes into binary mode; we will do text mode translation ourselves
8334 if required. */
8335 rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
8337 if (rc == 0)
8339 /* Protect against overflow, since Windows can open more handles than
8340 our fd_info array has room for. */
8341 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
8343 _close (phandles[0]);
8344 _close (phandles[1]);
8345 errno = EMFILE;
8346 rc = -1;
8348 else
8350 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
8351 fd_info[phandles[0]].flags = flags;
8353 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
8354 fd_info[phandles[1]].flags = flags;
8358 return rc;
8361 /* Function to do blocking read of one byte, needed to implement
8362 select. It is only allowed on communication ports, sockets, or
8363 pipes. */
8365 _sys_read_ahead (int fd)
8367 child_process * cp;
8368 int rc;
8370 if (fd < 0 || fd >= MAXDESC)
8371 return STATUS_READ_ERROR;
8373 cp = fd_info[fd].cp;
8375 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8376 return STATUS_READ_ERROR;
8378 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
8379 || (fd_info[fd].flags & FILE_READ) == 0)
8381 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
8382 emacs_abort ();
8385 if ((fd_info[fd].flags & FILE_CONNECT) != 0)
8386 DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd));
8387 cp->status = STATUS_READ_IN_PROGRESS;
8389 if (fd_info[fd].flags & FILE_PIPE)
8391 rc = _read (fd, &cp->chr, sizeof (char));
8393 /* Give subprocess time to buffer some more output for us before
8394 reporting that input is available; we need this because Windows 95
8395 connects DOS programs to pipes by making the pipe appear to be
8396 the normal console stdout - as a result most DOS programs will
8397 write to stdout without buffering, ie. one character at a
8398 time. Even some W32 programs do this - "dir" in a command
8399 shell on NT is very slow if we don't do this. */
8400 if (rc > 0)
8402 int wait = w32_pipe_read_delay;
8404 if (wait > 0)
8405 Sleep (wait);
8406 else if (wait < 0)
8407 while (++wait <= 0)
8408 /* Yield remainder of our time slice, effectively giving a
8409 temporary priority boost to the child process. */
8410 Sleep (0);
8413 else if (fd_info[fd].flags & FILE_SERIAL)
8415 HANDLE hnd = fd_info[fd].hnd;
8416 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8417 COMMTIMEOUTS ct;
8419 /* Configure timeouts for blocking read. */
8420 if (!GetCommTimeouts (hnd, &ct))
8422 cp->status = STATUS_READ_ERROR;
8423 return STATUS_READ_ERROR;
8425 ct.ReadIntervalTimeout = 0;
8426 ct.ReadTotalTimeoutMultiplier = 0;
8427 ct.ReadTotalTimeoutConstant = 0;
8428 if (!SetCommTimeouts (hnd, &ct))
8430 cp->status = STATUS_READ_ERROR;
8431 return STATUS_READ_ERROR;
8434 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
8436 if (GetLastError () != ERROR_IO_PENDING)
8438 cp->status = STATUS_READ_ERROR;
8439 return STATUS_READ_ERROR;
8441 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8443 cp->status = STATUS_READ_ERROR;
8444 return STATUS_READ_ERROR;
8448 else if (fd_info[fd].flags & FILE_SOCKET)
8450 unsigned long nblock = 0;
8451 /* We always want this to block, so temporarily disable NDELAY. */
8452 if (fd_info[fd].flags & FILE_NDELAY)
8453 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8455 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
8457 if (fd_info[fd].flags & FILE_NDELAY)
8459 nblock = 1;
8460 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8464 if (rc == sizeof (char))
8465 cp->status = STATUS_READ_SUCCEEDED;
8466 else
8467 cp->status = STATUS_READ_FAILED;
8469 return cp->status;
8473 _sys_wait_accept (int fd)
8475 HANDLE hEv;
8476 child_process * cp;
8477 int rc;
8479 if (fd < 0 || fd >= MAXDESC)
8480 return STATUS_READ_ERROR;
8482 cp = fd_info[fd].cp;
8484 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8485 return STATUS_READ_ERROR;
8487 cp->status = STATUS_READ_FAILED;
8489 hEv = pfn_WSACreateEvent ();
8490 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
8491 if (rc != SOCKET_ERROR)
8493 do {
8494 rc = WaitForSingleObject (hEv, 500);
8495 Sleep (5);
8496 } while (rc == WAIT_TIMEOUT
8497 && cp->status != STATUS_READ_ERROR
8498 && cp->char_avail);
8499 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8500 if (rc == WAIT_OBJECT_0)
8501 cp->status = STATUS_READ_SUCCEEDED;
8503 pfn_WSACloseEvent (hEv);
8505 return cp->status;
8509 _sys_wait_connect (int fd)
8511 HANDLE hEv;
8512 child_process * cp;
8513 int rc;
8515 if (fd < 0 || fd >= MAXDESC)
8516 return STATUS_READ_ERROR;
8518 cp = fd_info[fd].cp;
8519 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8520 return STATUS_READ_ERROR;
8522 cp->status = STATUS_READ_FAILED;
8524 hEv = pfn_WSACreateEvent ();
8525 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT);
8526 if (rc != SOCKET_ERROR)
8528 do {
8529 rc = WaitForSingleObject (hEv, 500);
8530 Sleep (5);
8531 } while (rc == WAIT_TIMEOUT
8532 && cp->status != STATUS_READ_ERROR
8533 && cp->char_avail);
8534 if (rc == WAIT_OBJECT_0)
8536 /* We've got an event, but it could be a successful
8537 connection, or it could be a failure. Find out
8538 which one is it. */
8539 WSANETWORKEVENTS events;
8541 pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events);
8542 if ((events.lNetworkEvents & FD_CONNECT) != 0
8543 && events.iErrorCode[FD_CONNECT_BIT])
8545 cp->status = STATUS_CONNECT_FAILED;
8546 cp->errcode = events.iErrorCode[FD_CONNECT_BIT];
8548 else
8550 cp->status = STATUS_READ_SUCCEEDED;
8551 cp->errcode = 0;
8554 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8556 else
8557 pfn_WSACloseEvent (hEv);
8559 return cp->status;
8563 sys_read (int fd, char * buffer, unsigned int count)
8565 int nchars;
8566 int to_read;
8567 DWORD waiting;
8568 char * orig_buffer = buffer;
8570 if (fd < 0)
8572 errno = EBADF;
8573 return -1;
8576 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8578 child_process *cp = fd_info[fd].cp;
8580 if ((fd_info[fd].flags & FILE_READ) == 0)
8582 errno = EBADF;
8583 return -1;
8586 nchars = 0;
8588 /* re-read CR carried over from last read */
8589 if (fd_info[fd].flags & FILE_LAST_CR)
8591 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
8592 *buffer++ = 0x0d;
8593 count--;
8594 nchars++;
8595 fd_info[fd].flags &= ~FILE_LAST_CR;
8598 /* presence of a child_process structure means we are operating in
8599 non-blocking mode - otherwise we just call _read directly.
8600 Note that the child_process structure might be missing because
8601 reap_subprocess has been called; in this case the pipe is
8602 already broken, so calling _read on it is okay. */
8603 if (cp)
8605 int current_status = cp->status;
8607 switch (current_status)
8609 case STATUS_READ_FAILED:
8610 case STATUS_READ_ERROR:
8611 /* report normal EOF if nothing in buffer */
8612 if (nchars <= 0)
8613 fd_info[fd].flags |= FILE_AT_EOF;
8614 return nchars;
8616 case STATUS_READ_READY:
8617 case STATUS_READ_IN_PROGRESS:
8618 #if 0
8619 /* This happens all the time during GnuTLS handshake
8620 with the remote, evidently because GnuTLS waits for
8621 the read to complete by retrying the read operation
8622 upon EAGAIN. So I'm disabling the DebPrint to avoid
8623 wasting cycles on something that is not a real
8624 problem. Enable if you need to debug something that
8625 bumps into this. */
8626 DebPrint (("sys_read called when read is in progress %d\n",
8627 current_status));
8628 #endif
8629 errno = EWOULDBLOCK;
8630 return -1;
8632 case STATUS_READ_SUCCEEDED:
8633 /* consume read-ahead char */
8634 *buffer++ = cp->chr;
8635 count--;
8636 nchars++;
8637 cp->status = STATUS_READ_ACKNOWLEDGED;
8638 ResetEvent (cp->char_avail);
8640 case STATUS_READ_ACKNOWLEDGED:
8641 case STATUS_CONNECT_FAILED:
8642 break;
8644 default:
8645 DebPrint (("sys_read: bad status %d\n", current_status));
8646 errno = EBADF;
8647 return -1;
8650 if (fd_info[fd].flags & FILE_PIPE)
8652 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
8653 to_read = min (waiting, (DWORD) count);
8655 if (to_read > 0)
8656 nchars += _read (fd, buffer, to_read);
8658 else if (fd_info[fd].flags & FILE_SERIAL)
8660 HANDLE hnd = fd_info[fd].hnd;
8661 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8662 int rc = 0;
8663 COMMTIMEOUTS ct;
8665 if (count > 0)
8667 /* Configure timeouts for non-blocking read. */
8668 if (!GetCommTimeouts (hnd, &ct))
8670 errno = EIO;
8671 return -1;
8673 ct.ReadIntervalTimeout = MAXDWORD;
8674 ct.ReadTotalTimeoutMultiplier = 0;
8675 ct.ReadTotalTimeoutConstant = 0;
8676 if (!SetCommTimeouts (hnd, &ct))
8678 errno = EIO;
8679 return -1;
8682 if (!ResetEvent (ovl->hEvent))
8684 errno = EIO;
8685 return -1;
8687 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8689 if (GetLastError () != ERROR_IO_PENDING)
8691 errno = EIO;
8692 return -1;
8694 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8696 errno = EIO;
8697 return -1;
8700 nchars += rc;
8703 else /* FILE_SOCKET */
8705 if (winsock_lib == NULL) emacs_abort ();
8707 /* When a non-blocking 'connect' call fails,
8708 wait_reading_process_output detects this by calling
8709 'getpeername', and then attempts to obtain the connection
8710 error code by trying to read 1 byte from the socket. If
8711 we try to serve that read by calling 'recv' below, the
8712 error we get is a generic WSAENOTCONN, not the actual
8713 connection error. So instead, we use the actual error
8714 code stashed by '_sys_wait_connect' in cp->errcode.
8715 Alternatively, we could have used 'getsockopt', like on
8716 GNU/Linux, but: (a) I have no idea whether the winsock
8717 version could hang, as it does "on some systems" (see the
8718 comment in process.c); and (b) 'getsockopt' on Windows is
8719 documented to clear the socket error for the entire
8720 process, which I'm not sure is TRT; FIXME. */
8721 if (current_status == STATUS_CONNECT_FAILED
8722 && (fd_info[fd].flags & FILE_CONNECT) != 0
8723 && cp->errcode != 0)
8725 pfn_WSASetLastError (cp->errcode);
8726 set_errno ();
8727 return -1;
8729 /* Do the equivalent of a non-blocking read. */
8730 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8731 if (waiting == 0 && nchars == 0)
8733 errno = EWOULDBLOCK;
8734 return -1;
8737 if (waiting)
8739 /* always use binary mode for sockets */
8740 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8741 if (res == SOCKET_ERROR)
8743 set_errno ();
8744 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8745 errno, SOCK_HANDLE (fd)));
8746 return -1;
8748 nchars += res;
8752 else
8754 int nread = _read (fd, buffer, count);
8755 if (nread >= 0)
8756 nchars += nread;
8757 else if (nchars == 0)
8758 nchars = nread;
8761 if (nchars <= 0)
8762 fd_info[fd].flags |= FILE_AT_EOF;
8763 /* Perform text mode translation if required. */
8764 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8766 nchars = crlf_to_lf (nchars, orig_buffer);
8767 /* If buffer contains only CR, return that. To be absolutely
8768 sure we should attempt to read the next char, but in
8769 practice a CR to be followed by LF would not appear by
8770 itself in the buffer. */
8771 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8773 fd_info[fd].flags |= FILE_LAST_CR;
8774 nchars--;
8778 else
8779 nchars = _read (fd, buffer, count);
8781 return nchars;
8784 /* From w32xfns.c */
8785 extern HANDLE interrupt_handle;
8788 sys_write (int fd, const void * buffer, unsigned int count)
8790 int nchars;
8791 USE_SAFE_ALLOCA;
8793 if (fd < 0)
8795 errno = EBADF;
8796 return -1;
8799 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8801 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8803 errno = EBADF;
8804 return -1;
8807 /* Perform text mode translation if required. */
8808 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8810 char * tmpbuf;
8811 const unsigned char * src = buffer;
8812 unsigned char * dst;
8813 int nbytes = count;
8815 SAFE_NALLOCA (tmpbuf, 2, count);
8816 dst = (unsigned char *)tmpbuf;
8818 while (1)
8820 unsigned char *next;
8821 /* Copy next line or remaining bytes. */
8822 next = _memccpy (dst, src, '\n', nbytes);
8823 if (next)
8825 /* Copied one line ending with '\n'. */
8826 int copied = next - dst;
8827 nbytes -= copied;
8828 src += copied;
8829 /* Insert '\r' before '\n'. */
8830 next[-1] = '\r';
8831 next[0] = '\n';
8832 dst = next + 1;
8833 count++;
8835 else
8836 /* Copied remaining partial line -> now finished. */
8837 break;
8839 buffer = tmpbuf;
8843 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8845 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8846 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8847 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8848 DWORD active = 0;
8850 /* This is async (a.k.a. "overlapped") I/O, so the return value
8851 of FALSE from WriteFile means either an error or the output
8852 will be completed asynchronously (ERROR_IO_PENDING). */
8853 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8855 if (GetLastError () != ERROR_IO_PENDING)
8857 errno = EIO;
8858 nchars = -1;
8860 else
8862 /* Wait for the write to complete, and watch C-g while
8863 at that. */
8864 if (detect_input_pending ())
8865 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
8866 INFINITE, QS_ALLINPUT);
8867 else
8868 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8869 switch (active)
8871 case WAIT_OBJECT_0:
8872 /* User pressed C-g, cancel write, then leave.
8873 Don't bother cleaning up as we may only get stuck
8874 in buggy drivers. */
8875 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8876 CancelIo (hnd);
8877 errno = EIO; /* Why not EINTR? */
8878 nchars = -1;
8879 break;
8880 case WAIT_OBJECT_0 + 1:
8881 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8883 errno = EIO;
8884 nchars = -1;
8886 break;
8891 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8893 unsigned long nblock = 0;
8894 if (winsock_lib == NULL) emacs_abort ();
8896 child_process *cp = fd_info[fd].cp;
8898 /* If this is a non-blocking socket whose connection is in
8899 progress or terminated with an error already, return the
8900 proper error code to the caller. */
8901 if (cp != NULL && (fd_info[fd].flags & FILE_CONNECT) != 0)
8903 /* In case connection is in progress, ENOTCONN that would
8904 result from calling pfn_send is not what callers expect. */
8905 if (cp->status != STATUS_CONNECT_FAILED)
8907 errno = EWOULDBLOCK;
8908 return -1;
8910 /* In case connection failed, use the actual error code
8911 stashed by '_sys_wait_connect' in cp->errcode. */
8912 else if (cp->errcode != 0)
8914 pfn_WSASetLastError (cp->errcode);
8915 set_errno ();
8916 return -1;
8920 /* TODO: implement select() properly so non-blocking I/O works. */
8921 /* For now, make sure the write blocks. */
8922 if (fd_info[fd].flags & FILE_NDELAY)
8923 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8925 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
8927 if (nchars == SOCKET_ERROR)
8929 set_errno ();
8930 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
8931 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8934 /* Set the socket back to non-blocking if it was before,
8935 for other operations that support it. */
8936 if (fd_info[fd].flags & FILE_NDELAY)
8938 nblock = 1;
8939 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8942 else
8944 /* Some networked filesystems don't like too large writes, so
8945 break them into smaller chunks. See the Comments section of
8946 the MSDN documentation of WriteFile for details behind the
8947 choice of the value of CHUNK below. See also the thread
8948 http://thread.gmane.org/gmane.comp.version-control.git/145294
8949 in the git mailing list. */
8950 const unsigned char *p = buffer;
8951 const bool is_pipe = (fd < MAXDESC
8952 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
8953 == (FILE_PIPE | FILE_NDELAY)));
8954 /* Some programs, notably Node.js's node.exe, seem to never
8955 completely empty the pipe, so writing more than the size of
8956 the pipe's buffer always returns ENOSPC, and we loop forever
8957 between send_process and here. As a workaround, write no
8958 more than the pipe's buffer can hold. */
8959 DWORD pipe_buffer_size;
8960 if (is_pipe)
8962 if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
8963 NULL, &pipe_buffer_size, NULL, NULL))
8965 DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
8966 pipe_buffer_size = 4096;
8969 const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
8971 nchars = 0;
8972 errno = 0;
8973 while (count > 0)
8975 unsigned this_chunk = count < chunk ? count : chunk;
8976 int n = _write (fd, p, this_chunk);
8978 if (n > 0)
8979 nchars += n;
8980 if (n < 0)
8982 /* When there's no buffer space in a pipe that is in the
8983 non-blocking mode, _write returns ENOSPC. We return
8984 EAGAIN instead, which should trigger the logic in
8985 send_process that enters waiting loop and calls
8986 wait_reading_process_output to allow process input to
8987 be accepted during the wait. Those calls to
8988 wait_reading_process_output allow sys_select to
8989 notice when process input becomes available, thus
8990 avoiding deadlock whereby each side of the pipe is
8991 blocked on write, waiting for the other party to read
8992 its end of the pipe. */
8993 if (errno == ENOSPC && is_pipe)
8994 errno = EAGAIN;
8995 if (nchars == 0)
8996 nchars = -1;
8997 break;
8999 else if (n < this_chunk)
9000 break;
9001 count -= n;
9002 p += n;
9006 SAFE_FREE ();
9007 return nchars;
9011 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
9013 /* Return information about network interface IFNAME, or about all
9014 interfaces (if IFNAME is nil). */
9015 static Lisp_Object
9016 network_interface_get_info (Lisp_Object ifname)
9018 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
9019 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
9020 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
9021 Lisp_Object res = Qnil;
9023 if (retval == ERROR_BUFFER_OVERFLOW)
9025 ainfo = xrealloc (ainfo, ainfo_len);
9026 retval = get_adapters_info (ainfo, &ainfo_len);
9029 if (retval == ERROR_SUCCESS)
9031 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
9032 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
9033 int if_num;
9034 struct sockaddr_in sa;
9036 /* For the below, we need some winsock functions, so make sure
9037 the winsock DLL is loaded. If we cannot successfully load
9038 it, they will have no use of the information we provide,
9039 anyway, so punt. */
9040 if (!winsock_lib && !init_winsock (1))
9041 goto done;
9043 for (adapter = ainfo; adapter; adapter = adapter->Next)
9045 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
9046 u_long ip_addr;
9047 /* Present Unix-compatible interface names, instead of the
9048 Windows names, which are really GUIDs not readable by
9049 humans. */
9050 static const char *ifmt[] = {
9051 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
9052 "lo", "ifx%d"
9054 enum {
9055 NONE = -1,
9056 ETHERNET = 0,
9057 TOKENRING = 1,
9058 FDDI = 2,
9059 PPP = 3,
9060 SLIP = 4,
9061 WLAN = 5,
9062 LOOPBACK = 6,
9063 OTHER_IF = 7
9064 } ifmt_idx;
9066 switch (adapter->Type)
9068 case MIB_IF_TYPE_ETHERNET:
9069 /* Windows before Vista reports wireless adapters as
9070 Ethernet. Work around by looking at the Description
9071 string. */
9072 if (strstr (adapter->Description, "Wireless "))
9074 ifmt_idx = WLAN;
9075 if_num = wlan_count++;
9077 else
9079 ifmt_idx = ETHERNET;
9080 if_num = eth_count++;
9082 break;
9083 case MIB_IF_TYPE_TOKENRING:
9084 ifmt_idx = TOKENRING;
9085 if_num = tr_count++;
9086 break;
9087 case MIB_IF_TYPE_FDDI:
9088 ifmt_idx = FDDI;
9089 if_num = fddi_count++;
9090 break;
9091 case MIB_IF_TYPE_PPP:
9092 ifmt_idx = PPP;
9093 if_num = ppp_count++;
9094 break;
9095 case MIB_IF_TYPE_SLIP:
9096 ifmt_idx = SLIP;
9097 if_num = sl_count++;
9098 break;
9099 case IF_TYPE_IEEE80211:
9100 ifmt_idx = WLAN;
9101 if_num = wlan_count++;
9102 break;
9103 case MIB_IF_TYPE_LOOPBACK:
9104 if (lo_count < 0)
9106 ifmt_idx = LOOPBACK;
9107 if_num = lo_count++;
9109 else
9110 ifmt_idx = NONE;
9111 break;
9112 default:
9113 ifmt_idx = OTHER_IF;
9114 if_num = ifx_count++;
9115 break;
9117 if (ifmt_idx == NONE)
9118 continue;
9119 sprintf (namebuf, ifmt[ifmt_idx], if_num);
9121 sa.sin_family = AF_INET;
9122 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
9123 if (ip_addr == INADDR_NONE)
9125 /* Bogus address, skip this interface. */
9126 continue;
9128 sa.sin_addr.s_addr = ip_addr;
9129 sa.sin_port = 0;
9130 if (NILP (ifname))
9131 res = Fcons (Fcons (build_string (namebuf),
9132 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9133 sizeof (struct sockaddr))),
9134 res);
9135 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
9137 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
9138 register struct Lisp_Vector *p = XVECTOR (hwaddr);
9139 Lisp_Object flags = Qnil;
9140 int n;
9141 u_long net_mask;
9143 /* Flags. We guess most of them by type, since the
9144 Windows flags are different and hard to get by. */
9145 flags = Fcons (intern ("up"), flags);
9146 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
9148 flags = Fcons (intern ("broadcast"), flags);
9149 flags = Fcons (intern ("multicast"), flags);
9151 flags = Fcons (intern ("running"), flags);
9152 if (ifmt_idx == PPP)
9154 flags = Fcons (intern ("pointopoint"), flags);
9155 flags = Fcons (intern ("noarp"), flags);
9157 if (adapter->HaveWins)
9158 flags = Fcons (intern ("WINS"), flags);
9159 if (adapter->DhcpEnabled)
9160 flags = Fcons (intern ("dynamic"), flags);
9162 res = Fcons (flags, res);
9164 /* Hardware address and its family. */
9165 for (n = 0; n < adapter->AddressLength; n++)
9166 p->contents[n] = make_number ((int) adapter->Address[n]);
9167 /* Windows does not support AF_LINK or AF_PACKET family
9168 of addresses. Use an arbitrary family number that is
9169 identical to what GNU/Linux returns. */
9170 res = Fcons (Fcons (make_number (1), hwaddr), res);
9172 /* Network mask. */
9173 sa.sin_family = AF_INET;
9174 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
9175 if (net_mask != INADDR_NONE)
9177 sa.sin_addr.s_addr = net_mask;
9178 sa.sin_port = 0;
9179 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9180 sizeof (struct sockaddr)),
9181 res);
9183 else
9184 res = Fcons (Qnil, res);
9186 sa.sin_family = AF_INET;
9187 if (ip_addr != INADDR_NONE)
9189 /* Broadcast address is only reported by
9190 GetAdaptersAddresses, which is of limited
9191 availability. Generate it on our own. */
9192 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
9194 sa.sin_addr.s_addr = bcast_addr;
9195 sa.sin_port = 0;
9196 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9197 sizeof (struct sockaddr)),
9198 res);
9200 /* IP address. */
9201 sa.sin_addr.s_addr = ip_addr;
9202 sa.sin_port = 0;
9203 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9204 sizeof (struct sockaddr)),
9205 res);
9207 else
9208 res = Fcons (Qnil, Fcons (Qnil, res));
9211 /* GetAdaptersInfo is documented to not report loopback
9212 interfaces, so we generate one out of thin air. */
9213 if (!lo_count)
9215 sa.sin_family = AF_INET;
9216 sa.sin_port = 0;
9217 if (NILP (ifname))
9219 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9220 res = Fcons (Fcons (build_string ("lo"),
9221 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9222 sizeof (struct sockaddr))),
9223 res);
9225 else if (strcmp (SSDATA (ifname), "lo") == 0)
9227 res = Fcons (Fcons (intern ("running"),
9228 Fcons (intern ("loopback"),
9229 Fcons (intern ("up"), Qnil))), Qnil);
9230 /* 772 is what 3 different GNU/Linux systems report for
9231 the loopback interface. */
9232 res = Fcons (Fcons (make_number (772),
9233 Fmake_vector (make_number (6),
9234 make_number (0))),
9235 res);
9236 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
9237 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9238 sizeof (struct sockaddr)),
9239 res);
9240 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
9241 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9242 sizeof (struct sockaddr)),
9243 res);
9244 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9245 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9246 sizeof (struct sockaddr)),
9247 res);
9253 done:
9254 xfree (ainfo);
9255 return res;
9258 Lisp_Object
9259 network_interface_list (void)
9261 return network_interface_get_info (Qnil);
9264 Lisp_Object
9265 network_interface_info (Lisp_Object ifname)
9267 CHECK_STRING (ifname);
9268 return network_interface_get_info (ifname);
9272 /* The Windows CRT functions are "optimized for speed", so they don't
9273 check for timezone and DST changes if they were last called less
9274 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
9275 all Emacs features that repeatedly call time functions (e.g.,
9276 display-time) are in real danger of missing timezone and DST
9277 changes. Calling tzset before each localtime call fixes that. */
9278 struct tm *
9279 sys_localtime (const time_t *t)
9281 tzset ();
9282 return localtime (t);
9287 /* Try loading LIBRARY_ID from the file(s) specified in
9288 Vdynamic_library_alist. If the library is loaded successfully,
9289 return the handle of the DLL, and record the filename in the
9290 property :loaded-from of LIBRARY_ID. If the library could not be
9291 found, or when it was already loaded (because the handle is not
9292 recorded anywhere, and so is lost after use), return NULL.
9294 We could also save the handle in :loaded-from, but currently
9295 there's no use case for it. */
9296 HMODULE
9297 w32_delayed_load (Lisp_Object library_id)
9299 HMODULE dll_handle = NULL;
9301 CHECK_SYMBOL (library_id);
9303 if (CONSP (Vdynamic_library_alist)
9304 && NILP (Fassq (library_id, Vlibrary_cache)))
9306 Lisp_Object found = Qnil;
9307 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
9309 if (CONSP (dlls))
9310 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
9312 Lisp_Object dll = XCAR (dlls);
9313 char name[MAX_UTF8_PATH];
9314 DWORD res = -1;
9316 CHECK_STRING (dll);
9317 dll = ENCODE_FILE (dll);
9318 if (w32_unicode_filenames)
9320 wchar_t name_w[MAX_PATH];
9322 filename_to_utf16 (SSDATA (dll), name_w);
9323 dll_handle = LoadLibraryW (name_w);
9324 if (dll_handle)
9326 res = GetModuleFileNameW (dll_handle, name_w,
9327 sizeof (name_w));
9328 if (res > 0)
9329 filename_from_utf16 (name_w, name);
9332 else
9334 char name_a[MAX_PATH];
9336 filename_to_ansi (SSDATA (dll), name_a);
9337 dll_handle = LoadLibraryA (name_a);
9338 if (dll_handle)
9340 res = GetModuleFileNameA (dll_handle, name_a,
9341 sizeof (name_a));
9342 if (res > 0)
9343 filename_from_ansi (name_a, name);
9346 if (dll_handle)
9348 ptrdiff_t len = strlen (name);
9349 found = Fcons (dll,
9350 (res > 0)
9351 /* Possibly truncated */
9352 ? make_specified_string (name, -1, len, 1)
9353 : Qnil);
9354 /* This prevents thread start and end notifications
9355 from being sent to the DLL, for every thread we
9356 start. We don't need those notifications because
9357 threads we create never use any of these DLLs, only
9358 the main thread uses them. This is supposed to
9359 speed up thread creation. */
9360 DisableThreadLibraryCalls (dll_handle);
9361 break;
9365 Fput (library_id, QCloaded_from, found);
9368 return dll_handle;
9372 void
9373 check_windows_init_file (void)
9375 /* A common indication that Emacs is not installed properly is when
9376 it cannot find the Windows installation file. If this file does
9377 not exist in the expected place, tell the user. */
9379 if (!noninteractive && !inhibit_window_system
9380 /* Vload_path is not yet initialized when we are loading
9381 loadup.el. */
9382 && NILP (Vpurify_flag))
9384 Lisp_Object init_file;
9385 int fd;
9387 /* Implementation note: this function runs early during Emacs
9388 startup, before startup.el is run. So Vload_path is still in
9389 its initial unibyte form, but it holds UTF-8 encoded file
9390 names, since init_callproc was already called. So we do not
9391 need to ENCODE_FILE here, but we do need to convert the file
9392 names from UTF-8 to ANSI. */
9393 init_file = build_string ("term/w32-win");
9394 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
9395 if (fd < 0)
9397 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
9398 char *init_file_name = SSDATA (init_file);
9399 char *load_path = SSDATA (load_path_print);
9400 char *buffer = alloca (1024
9401 + strlen (init_file_name)
9402 + strlen (load_path));
9403 char *msg = buffer;
9404 int needed;
9406 sprintf (buffer,
9407 "The Emacs Windows initialization file \"%s.el\" "
9408 "could not be found in your Emacs installation. "
9409 "Emacs checked the following directories for this file:\n"
9410 "\n%s\n\n"
9411 "When Emacs cannot find this file, it usually means that it "
9412 "was not installed properly, or its distribution file was "
9413 "not unpacked properly.\nSee the README.W32 file in the "
9414 "top-level Emacs directory for more information.",
9415 init_file_name, load_path);
9416 needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
9417 buffer, -1, NULL, 0);
9418 if (needed > 0)
9420 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
9422 pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
9423 -1, msg_w, needed);
9424 needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
9425 NULL, 0, NULL, NULL);
9426 if (needed > 0)
9428 char *msg_a = alloca (needed + 1);
9430 pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
9431 NULL, NULL);
9432 msg = msg_a;
9435 MessageBox (NULL,
9436 msg,
9437 "Emacs Abort Dialog",
9438 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
9439 /* Use the low-level system abort. */
9440 abort ();
9442 else
9444 _close (fd);
9449 void
9450 term_ntproc (int ignored)
9452 (void)ignored;
9454 term_timers ();
9456 /* shutdown the socket interface if necessary */
9457 term_winsock ();
9459 term_w32select ();
9462 void
9463 init_ntproc (int dumping)
9465 sigset_t initial_mask = 0;
9467 /* Initialize the socket interface now if available and requested by
9468 the user by defining PRELOAD_WINSOCK; otherwise loading will be
9469 delayed until open-network-stream is called (w32-has-winsock can
9470 also be used to dynamically load or reload winsock).
9472 Conveniently, init_environment is called before us, so
9473 PRELOAD_WINSOCK can be set in the registry. */
9475 /* Always initialize this correctly. */
9476 winsock_lib = NULL;
9478 if (getenv ("PRELOAD_WINSOCK") != NULL)
9479 init_winsock (TRUE);
9481 /* Initial preparation for subprocess support: replace our standard
9482 handles with non-inheritable versions. */
9484 HANDLE parent;
9485 HANDLE stdin_save = INVALID_HANDLE_VALUE;
9486 HANDLE stdout_save = INVALID_HANDLE_VALUE;
9487 HANDLE stderr_save = INVALID_HANDLE_VALUE;
9489 parent = GetCurrentProcess ();
9491 /* ignore errors when duplicating and closing; typically the
9492 handles will be invalid when running as a gui program. */
9493 DuplicateHandle (parent,
9494 GetStdHandle (STD_INPUT_HANDLE),
9495 parent,
9496 &stdin_save,
9498 FALSE,
9499 DUPLICATE_SAME_ACCESS);
9501 DuplicateHandle (parent,
9502 GetStdHandle (STD_OUTPUT_HANDLE),
9503 parent,
9504 &stdout_save,
9506 FALSE,
9507 DUPLICATE_SAME_ACCESS);
9509 DuplicateHandle (parent,
9510 GetStdHandle (STD_ERROR_HANDLE),
9511 parent,
9512 &stderr_save,
9514 FALSE,
9515 DUPLICATE_SAME_ACCESS);
9517 fclose (stdin);
9518 fclose (stdout);
9519 fclose (stderr);
9521 if (stdin_save != INVALID_HANDLE_VALUE)
9522 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
9523 else
9524 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
9525 _fdopen (0, "r");
9527 if (stdout_save != INVALID_HANDLE_VALUE)
9528 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
9529 else
9530 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9531 _fdopen (1, "w");
9533 if (stderr_save != INVALID_HANDLE_VALUE)
9534 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
9535 else
9536 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9537 _fdopen (2, "w");
9540 /* unfortunately, atexit depends on implementation of malloc */
9541 /* atexit (term_ntproc); */
9542 if (!dumping)
9544 /* Make sure we start with all signals unblocked. */
9545 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
9546 signal (SIGABRT, term_ntproc);
9548 init_timers ();
9550 /* determine which drives are fixed, for GetCachedVolumeInformation */
9552 /* GetDriveType must have trailing backslash. */
9553 char drive[] = "A:\\";
9555 /* Loop over all possible drive letters */
9556 while (*drive <= 'Z')
9558 /* Record if this drive letter refers to a fixed drive. */
9559 fixed_drives[DRIVE_INDEX (*drive)] =
9560 (GetDriveType (drive) == DRIVE_FIXED);
9562 (*drive)++;
9565 /* Reset the volume info cache. */
9566 volume_cache = NULL;
9571 shutdown_handler ensures that buffers' autosave files are
9572 up to date when the user logs off, or the system shuts down.
9574 static BOOL WINAPI
9575 shutdown_handler (DWORD type)
9577 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
9578 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
9579 || type == CTRL_LOGOFF_EVENT /* User logs off. */
9580 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
9582 /* Shut down cleanly, making sure autosave files are up to date. */
9583 shut_down_emacs (0, Qnil);
9586 /* Allow other handlers to handle this signal. */
9587 return FALSE;
9590 /* On Windows 9X, load UNICOWS.DLL and return its handle, or die. On
9591 NT, return a handle to GDI32.DLL. */
9592 HANDLE
9593 maybe_load_unicows_dll (void)
9595 if (os_subtype == OS_9X)
9597 HANDLE ret = LoadLibrary ("Unicows.dll");
9598 if (ret)
9600 /* These two functions are present on Windows 9X as stubs
9601 that always fail. We need the real implementations from
9602 UNICOWS.DLL, so we must call these functions through
9603 pointers, and assign the correct addresses to these
9604 pointers at program startup (see emacs.c, which calls
9605 this function early on). */
9606 pMultiByteToWideChar =
9607 (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
9608 pWideCharToMultiByte =
9609 (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
9610 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9611 return ret;
9613 else
9615 int button;
9617 button = MessageBox (NULL,
9618 "Emacs cannot load the UNICOWS.DLL library.\n"
9619 "This library is essential for using Emacs\n"
9620 "on this system. You need to install it.\n\n"
9621 "Emacs will exit when you click OK.",
9622 "Emacs cannot load UNICOWS.DLL",
9623 MB_ICONERROR | MB_TASKMODAL
9624 | MB_SETFOREGROUND | MB_OK);
9625 switch (button)
9627 case IDOK:
9628 default:
9629 exit (1);
9633 else
9635 /* On NT family of Windows, these two functions are always
9636 linked in, so we just assign their addresses to the 2
9637 pointers; no need for the LoadLibrary dance. */
9638 pMultiByteToWideChar = MultiByteToWideChar;
9639 pWideCharToMultiByte = WideCharToMultiByte;
9640 /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported. */
9641 if (w32_major_version < 5)
9642 multiByteToWideCharFlags = 0;
9643 else
9644 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9645 return LoadLibrary ("Gdi32.dll");
9650 globals_of_w32 is used to initialize those global variables that
9651 must always be initialized on startup even when the global variable
9652 initialized is non zero (see the function main in emacs.c).
9654 void
9655 globals_of_w32 (void)
9657 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
9659 get_process_times_fn = (GetProcessTimes_Proc)
9660 GetProcAddress (kernel32, "GetProcessTimes");
9662 DEFSYM (QCloaded_from, ":loaded-from");
9664 g_b_init_is_windows_9x = 0;
9665 g_b_init_open_process_token = 0;
9666 g_b_init_get_token_information = 0;
9667 g_b_init_lookup_account_sid = 0;
9668 g_b_init_get_sid_sub_authority = 0;
9669 g_b_init_get_sid_sub_authority_count = 0;
9670 g_b_init_get_security_info = 0;
9671 g_b_init_get_file_security_w = 0;
9672 g_b_init_get_file_security_a = 0;
9673 g_b_init_get_security_descriptor_owner = 0;
9674 g_b_init_get_security_descriptor_group = 0;
9675 g_b_init_is_valid_sid = 0;
9676 g_b_init_create_toolhelp32_snapshot = 0;
9677 g_b_init_process32_first = 0;
9678 g_b_init_process32_next = 0;
9679 g_b_init_open_thread_token = 0;
9680 g_b_init_impersonate_self = 0;
9681 g_b_init_revert_to_self = 0;
9682 g_b_init_get_process_memory_info = 0;
9683 g_b_init_get_process_working_set_size = 0;
9684 g_b_init_global_memory_status = 0;
9685 g_b_init_global_memory_status_ex = 0;
9686 g_b_init_equal_sid = 0;
9687 g_b_init_copy_sid = 0;
9688 g_b_init_get_length_sid = 0;
9689 g_b_init_get_native_system_info = 0;
9690 g_b_init_get_system_times = 0;
9691 g_b_init_create_symbolic_link_w = 0;
9692 g_b_init_create_symbolic_link_a = 0;
9693 g_b_init_get_security_descriptor_dacl = 0;
9694 g_b_init_convert_sd_to_sddl = 0;
9695 g_b_init_convert_sddl_to_sd = 0;
9696 g_b_init_is_valid_security_descriptor = 0;
9697 g_b_init_set_file_security_w = 0;
9698 g_b_init_set_file_security_a = 0;
9699 g_b_init_set_named_security_info_w = 0;
9700 g_b_init_set_named_security_info_a = 0;
9701 g_b_init_get_adapters_info = 0;
9702 g_b_init_compare_string_w = 0;
9703 g_b_init_debug_break_process = 0;
9704 num_of_processors = 0;
9705 /* The following sets a handler for shutdown notifications for
9706 console apps. This actually applies to Emacs in both console and
9707 GUI modes, since we had to fool windows into thinking emacs is a
9708 console application to get console mode to work. */
9709 SetConsoleCtrlHandler (shutdown_handler, TRUE);
9711 /* "None" is the default group name on standalone workstations. */
9712 strcpy (dflt_group_name, "None");
9714 /* Reset, in case it has some value inherited from dump time. */
9715 w32_stat_get_owner_group = 0;
9717 /* If w32_unicode_filenames is non-zero, we will be using Unicode
9718 (a.k.a. "wide") APIs to invoke functions that accept file
9719 names. */
9720 if (is_windows_9x ())
9721 w32_unicode_filenames = 0;
9722 else
9723 w32_unicode_filenames = 1;
9725 #ifdef HAVE_MODULES
9726 dynlib_reset_last_error ();
9727 #endif
9729 w32_crypto_hprov = (HCRYPTPROV)0;
9732 /* For make-serial-process */
9734 serial_open (Lisp_Object port_obj)
9736 char *port = SSDATA (port_obj);
9737 HANDLE hnd;
9738 child_process *cp;
9739 int fd = -1;
9741 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
9742 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
9743 if (hnd == INVALID_HANDLE_VALUE)
9744 error ("Could not open %s", port);
9745 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
9746 if (fd == -1)
9747 error ("Could not open %s", port);
9749 cp = new_child ();
9750 if (!cp)
9751 error ("Could not create child process");
9752 cp->fd = fd;
9753 cp->status = STATUS_READ_ACKNOWLEDGED;
9754 fd_info[ fd ].hnd = hnd;
9755 fd_info[ fd ].flags |=
9756 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
9757 if (fd_info[ fd ].cp != NULL)
9759 error ("fd_info[fd = %d] is already in use", fd);
9761 fd_info[ fd ].cp = cp;
9762 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9763 if (cp->ovl_read.hEvent == NULL)
9764 error ("Could not create read event");
9765 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9766 if (cp->ovl_write.hEvent == NULL)
9767 error ("Could not create write event");
9769 return fd;
9772 /* For serial-process-configure */
9773 void
9774 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
9776 Lisp_Object childp2 = Qnil;
9777 Lisp_Object tem = Qnil;
9778 HANDLE hnd;
9779 DCB dcb;
9780 COMMTIMEOUTS ct;
9781 char summary[4] = "???"; /* This usually becomes "8N1". */
9783 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
9784 error ("Not a serial process");
9785 hnd = fd_info[ p->outfd ].hnd;
9787 childp2 = Fcopy_sequence (p->childp);
9789 /* Initialize timeouts for blocking read and blocking write. */
9790 if (!GetCommTimeouts (hnd, &ct))
9791 error ("GetCommTimeouts() failed");
9792 ct.ReadIntervalTimeout = 0;
9793 ct.ReadTotalTimeoutMultiplier = 0;
9794 ct.ReadTotalTimeoutConstant = 0;
9795 ct.WriteTotalTimeoutMultiplier = 0;
9796 ct.WriteTotalTimeoutConstant = 0;
9797 if (!SetCommTimeouts (hnd, &ct))
9798 error ("SetCommTimeouts() failed");
9799 /* Read port attributes and prepare default configuration. */
9800 memset (&dcb, 0, sizeof (dcb));
9801 dcb.DCBlength = sizeof (DCB);
9802 if (!GetCommState (hnd, &dcb))
9803 error ("GetCommState() failed");
9804 dcb.fBinary = TRUE;
9805 dcb.fNull = FALSE;
9806 dcb.fAbortOnError = FALSE;
9807 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
9808 dcb.ErrorChar = 0;
9809 dcb.EofChar = 0;
9810 dcb.EvtChar = 0;
9812 /* Configure speed. */
9813 if (!NILP (Fplist_member (contact, QCspeed)))
9814 tem = Fplist_get (contact, QCspeed);
9815 else
9816 tem = Fplist_get (p->childp, QCspeed);
9817 CHECK_NUMBER (tem);
9818 dcb.BaudRate = XINT (tem);
9819 childp2 = Fplist_put (childp2, QCspeed, tem);
9821 /* Configure bytesize. */
9822 if (!NILP (Fplist_member (contact, QCbytesize)))
9823 tem = Fplist_get (contact, QCbytesize);
9824 else
9825 tem = Fplist_get (p->childp, QCbytesize);
9826 if (NILP (tem))
9827 tem = make_number (8);
9828 CHECK_NUMBER (tem);
9829 if (XINT (tem) != 7 && XINT (tem) != 8)
9830 error (":bytesize must be nil (8), 7, or 8");
9831 dcb.ByteSize = XINT (tem);
9832 summary[0] = XINT (tem) + '0';
9833 childp2 = Fplist_put (childp2, QCbytesize, tem);
9835 /* Configure parity. */
9836 if (!NILP (Fplist_member (contact, QCparity)))
9837 tem = Fplist_get (contact, QCparity);
9838 else
9839 tem = Fplist_get (p->childp, QCparity);
9840 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
9841 error (":parity must be nil (no parity), `even', or `odd'");
9842 dcb.fParity = FALSE;
9843 dcb.Parity = NOPARITY;
9844 dcb.fErrorChar = FALSE;
9845 if (NILP (tem))
9847 summary[1] = 'N';
9849 else if (EQ (tem, Qeven))
9851 summary[1] = 'E';
9852 dcb.fParity = TRUE;
9853 dcb.Parity = EVENPARITY;
9854 dcb.fErrorChar = TRUE;
9856 else if (EQ (tem, Qodd))
9858 summary[1] = 'O';
9859 dcb.fParity = TRUE;
9860 dcb.Parity = ODDPARITY;
9861 dcb.fErrorChar = TRUE;
9863 childp2 = Fplist_put (childp2, QCparity, tem);
9865 /* Configure stopbits. */
9866 if (!NILP (Fplist_member (contact, QCstopbits)))
9867 tem = Fplist_get (contact, QCstopbits);
9868 else
9869 tem = Fplist_get (p->childp, QCstopbits);
9870 if (NILP (tem))
9871 tem = make_number (1);
9872 CHECK_NUMBER (tem);
9873 if (XINT (tem) != 1 && XINT (tem) != 2)
9874 error (":stopbits must be nil (1 stopbit), 1, or 2");
9875 summary[2] = XINT (tem) + '0';
9876 if (XINT (tem) == 1)
9877 dcb.StopBits = ONESTOPBIT;
9878 else if (XINT (tem) == 2)
9879 dcb.StopBits = TWOSTOPBITS;
9880 childp2 = Fplist_put (childp2, QCstopbits, tem);
9882 /* Configure flowcontrol. */
9883 if (!NILP (Fplist_member (contact, QCflowcontrol)))
9884 tem = Fplist_get (contact, QCflowcontrol);
9885 else
9886 tem = Fplist_get (p->childp, QCflowcontrol);
9887 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
9888 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
9889 dcb.fOutxCtsFlow = FALSE;
9890 dcb.fOutxDsrFlow = FALSE;
9891 dcb.fDtrControl = DTR_CONTROL_DISABLE;
9892 dcb.fDsrSensitivity = FALSE;
9893 dcb.fTXContinueOnXoff = FALSE;
9894 dcb.fOutX = FALSE;
9895 dcb.fInX = FALSE;
9896 dcb.fRtsControl = RTS_CONTROL_DISABLE;
9897 dcb.XonChar = 17; /* Control-Q */
9898 dcb.XoffChar = 19; /* Control-S */
9899 if (NILP (tem))
9901 /* Already configured. */
9903 else if (EQ (tem, Qhw))
9905 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
9906 dcb.fOutxCtsFlow = TRUE;
9908 else if (EQ (tem, Qsw))
9910 dcb.fOutX = TRUE;
9911 dcb.fInX = TRUE;
9913 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
9915 /* Activate configuration. */
9916 if (!SetCommState (hnd, &dcb))
9917 error ("SetCommState() failed");
9919 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
9920 pset_childp (p, childp2);
9923 /* For make-pipe-process */
9924 void
9925 register_aux_fd (int infd)
9927 child_process *cp;
9929 cp = new_child ();
9930 if (!cp)
9931 error ("Could not create child process");
9932 cp->fd = infd;
9933 cp->status = STATUS_READ_ACKNOWLEDGED;
9935 if (fd_info[ infd ].cp != NULL)
9937 error ("fd_info[fd = %d] is already in use", infd);
9939 fd_info[ infd ].cp = cp;
9940 fd_info[ infd ].hnd = (HANDLE) _get_osfhandle (infd);
9943 #ifdef HAVE_GNUTLS
9945 ssize_t
9946 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
9948 int n, err;
9949 struct Lisp_Process *process = (struct Lisp_Process *)p;
9950 int fd = process->infd;
9952 n = sys_read (fd, (char*)buf, sz);
9954 if (n >= 0)
9955 return n;
9957 err = errno;
9959 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9960 if (err == EWOULDBLOCK)
9961 err = EAGAIN;
9963 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
9965 return -1;
9968 ssize_t
9969 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
9971 struct Lisp_Process *process = (struct Lisp_Process *)p;
9972 int fd = process->outfd;
9973 ssize_t n = sys_write (fd, buf, sz);
9975 /* 0 or more bytes written means everything went fine. */
9976 if (n >= 0)
9977 return n;
9979 /* Negative bytes written means we got an error in errno.
9980 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9981 emacs_gnutls_transport_set_errno (process->gnutls_state,
9982 errno == EWOULDBLOCK ? EAGAIN : errno);
9984 return -1;
9986 #endif /* HAVE_GNUTLS */
9988 /* end of w32.c */