1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
2 
3 Copyright (C) 1994-1995, 2000-2021 Free Software Foundation, Inc.
4 
5 This file is part of GNU Emacs.
6 
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.
11 
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.
16 
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/>.  */
19 
20 /*
21    Geoff Voelker (voelker@cs.washington.edu)                         7-29-94
22 */
23 
24 #define DEFER_MS_W32_H
25 #include <config.h>
26 
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>
42 
43 /* Include (most) CRT headers *before* ms-w32.h.  */
44 #include <ms-w32.h>
45 
46 #include <string.h>	/* for strerror, needed by sys_strerror */
47 #include <mbstring.h>	/* for _mbspbrk, _mbslwr, _mbsrchr, ... */
48 
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
61 
62 #undef close
63 #undef dup
64 #undef dup2
65 #undef pipe
66 #undef read
67 #undef write
68 
69 #undef strerror
70 
71 #undef localtime
72 
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);
89 
90 #ifdef HAVE_MODULES
91 extern void dynlib_reset_last_error (void);
92 #endif
93 
94 #include "lisp.h"
95 #include "epaths.h"	/* for PATH_EXEC */
96 
97 #include <pwd.h>
98 #include <grp.h>
99 
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;
114 
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;
129 
130 #include <lmcons.h>
131 #include <shlobj.h>
132 
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
158 
159 #include <winioctl.h>
160 #include <aclapi.h>
161 #include <sddl.h>
162 
163 #include <sys/acl.h>
164 #include <acl.h>
165 
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 */
171 
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.  */
177 
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;
203 
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
222 
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 htonl
231 #undef ntohl
232 #undef inet_addr
233 #undef gethostname
234 #undef gethostbyname
235 #undef getservbyname
236 #undef getpeername
237 #undef shutdown
238 #undef setsockopt
239 #undef listen
240 #undef getsockname
241 #undef accept
242 #undef recvfrom
243 #undef sendto
244 
245 /* We need at least XP level for GetAdaptersAddresses stuff.  */
246 #if _WIN32_WINNT < 0x0501
247 # undef ORIG_WIN32_WINNT
248 # define ORIG_WIN32_WINNT _WIN32_WINNT
249 # undef _WIN32_WINNT
250 # define _WIN32_WINNT 0x0501
251 #endif
252 
253 #include <iphlpapi.h>	/* should be after winsock2.h */
254 
255 #ifdef ORIG_WIN32_WINNT
256 # undef _WIN32_WINNT
257 # define _WIN32_WINNT ORIG_WIN32_WINNT
258 # undef ORIG_WIN32_WINNT
259 #endif
260 
261 #include <wincrypt.h>
262 
263 #include <c-strcase.h>
264 #include <utimens.h>	/* for fdutimens */
265 
266 #include "w32.h"
267 #include <dirent.h>
268 #include "w32common.h"
269 #include "w32select.h"
270 #include "systime.h"		/* for current_timespec, struct timespec */
271 #include "dispextern.h"		/* for xstrcasecmp */
272 #include "coding.h"		/* for Vlocale_coding_system */
273 
274 #include "careadlinkat.h"
275 #include "allocator.h"
276 
277 /* For Lisp_Process, serial_configure and serial_open.  */
278 #include "process.h"
279 #include "systty.h"
280 
281 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
282   (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
283 
284 static DWORD get_rid (PSID);
285 static int is_symlink (const char *);
286 static char * chase_symlinks (const char *);
287 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
288 static int restore_privilege (TOKEN_PRIVILEGES *);
289 static BOOL WINAPI revert_to_self (void);
290 
291 static int sys_access (const char *, int);
292 extern void *e_malloc (size_t);
293 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
294 		       const struct timespec *, const sigset_t *);
295 extern int sys_dup (int);
296 
297 
298 /* Initialization states.
299 
300    WARNING: If you add any more such variables for additional APIs,
301             you MUST add initialization for them to globals_of_w32
302             below.  This is because these variables might get set
303             to non-NULL values during dumping, but the dumped Emacs
304             cannot reuse those values, because it could be run on a
305             different version of the OS, where API addresses are
306             different.  */
307 static BOOL g_b_init_is_windows_9x;
308 static BOOL g_b_init_open_process_token;
309 static BOOL g_b_init_get_token_information;
310 static BOOL g_b_init_lookup_account_sid;
311 static BOOL g_b_init_get_sid_sub_authority;
312 static BOOL g_b_init_get_sid_sub_authority_count;
313 static BOOL g_b_init_get_security_info;
314 static BOOL g_b_init_get_file_security_w;
315 static BOOL g_b_init_get_file_security_a;
316 static BOOL g_b_init_get_security_descriptor_owner;
317 static BOOL g_b_init_get_security_descriptor_group;
318 static BOOL g_b_init_is_valid_sid;
319 static BOOL g_b_init_create_toolhelp32_snapshot;
320 static BOOL g_b_init_process32_first;
321 static BOOL g_b_init_process32_next;
322 static BOOL g_b_init_open_thread_token;
323 static BOOL g_b_init_impersonate_self;
324 static BOOL g_b_init_revert_to_self;
325 static BOOL g_b_init_get_process_memory_info;
326 static BOOL g_b_init_get_process_working_set_size;
327 static BOOL g_b_init_global_memory_status;
328 static BOOL g_b_init_global_memory_status_ex;
329 static BOOL g_b_init_get_length_sid;
330 static BOOL g_b_init_equal_sid;
331 static BOOL g_b_init_copy_sid;
332 static BOOL g_b_init_get_native_system_info;
333 static BOOL g_b_init_get_system_times;
334 static BOOL g_b_init_create_symbolic_link_w;
335 static BOOL g_b_init_create_symbolic_link_a;
336 static BOOL g_b_init_get_security_descriptor_dacl;
337 static BOOL g_b_init_convert_sd_to_sddl;
338 static BOOL g_b_init_convert_sddl_to_sd;
339 static BOOL g_b_init_is_valid_security_descriptor;
340 static BOOL g_b_init_set_file_security_w;
341 static BOOL g_b_init_set_file_security_a;
342 static BOOL g_b_init_set_named_security_info_w;
343 static BOOL g_b_init_set_named_security_info_a;
344 static BOOL g_b_init_get_adapters_info;
345 static BOOL g_b_init_get_adapters_addresses;
346 static BOOL g_b_init_reg_open_key_ex_w;
347 static BOOL g_b_init_reg_query_value_ex_w;
348 static BOOL g_b_init_expand_environment_strings_w;
349 static BOOL g_b_init_get_user_default_ui_language;
350 
351 BOOL g_b_init_compare_string_w;
352 BOOL g_b_init_debug_break_process;
353 
354 /*
355   BEGIN: Wrapper functions around OpenProcessToken
356   and other functions in advapi32.dll that are only
357   supported in Windows NT / 2k / XP
358 */
359   /* ** Function pointer typedefs ** */
360 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
361     HANDLE ProcessHandle,
362     DWORD DesiredAccess,
363     PHANDLE TokenHandle);
364 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
365     HANDLE TokenHandle,
366     TOKEN_INFORMATION_CLASS TokenInformationClass,
367     LPVOID TokenInformation,
368     DWORD TokenInformationLength,
369     PDWORD ReturnLength);
370 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
371     HANDLE process_handle,
372     LPFILETIME creation_time,
373     LPFILETIME exit_time,
374     LPFILETIME kernel_time,
375     LPFILETIME user_time);
376 
377 GetProcessTimes_Proc get_process_times_fn = NULL;
378 
379 #ifdef _UNICODE
380 const char * const LookupAccountSid_Name = "LookupAccountSidW";
381 #else
382 const char * const LookupAccountSid_Name = "LookupAccountSidA";
383 #endif
384 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
385     LPCTSTR lpSystemName,
386     PSID Sid,
387     LPTSTR Name,
388     LPDWORD cbName,
389     LPTSTR DomainName,
390     LPDWORD cbDomainName,
391     PSID_NAME_USE peUse);
392 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
393     PSID pSid,
394     DWORD n);
395 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
396     PSID pSid);
397 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
398     HANDLE handle,
399     SE_OBJECT_TYPE ObjectType,
400     SECURITY_INFORMATION SecurityInfo,
401     PSID *ppsidOwner,
402     PSID *ppsidGroup,
403     PACL *ppDacl,
404     PACL *ppSacl,
405     PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
406 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
407     LPCWSTR lpFileName,
408     SECURITY_INFORMATION RequestedInformation,
409     PSECURITY_DESCRIPTOR pSecurityDescriptor,
410     DWORD nLength,
411     LPDWORD lpnLengthNeeded);
412 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
413     LPCSTR lpFileName,
414     SECURITY_INFORMATION RequestedInformation,
415     PSECURITY_DESCRIPTOR pSecurityDescriptor,
416     DWORD nLength,
417     LPDWORD lpnLengthNeeded);
418 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
419     LPCWSTR lpFileName,
420     SECURITY_INFORMATION SecurityInformation,
421     PSECURITY_DESCRIPTOR pSecurityDescriptor);
422 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
423     LPCSTR lpFileName,
424     SECURITY_INFORMATION SecurityInformation,
425     PSECURITY_DESCRIPTOR pSecurityDescriptor);
426 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
427     LPCWSTR lpObjectName,
428     SE_OBJECT_TYPE ObjectType,
429     SECURITY_INFORMATION SecurityInformation,
430     PSID psidOwner,
431     PSID psidGroup,
432     PACL pDacl,
433     PACL pSacl);
434 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
435     LPCSTR lpObjectName,
436     SE_OBJECT_TYPE ObjectType,
437     SECURITY_INFORMATION SecurityInformation,
438     PSID psidOwner,
439     PSID psidGroup,
440     PACL pDacl,
441     PACL pSacl);
442 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
443     PSECURITY_DESCRIPTOR pSecurityDescriptor,
444     PSID *pOwner,
445     LPBOOL lpbOwnerDefaulted);
446 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
447     PSECURITY_DESCRIPTOR pSecurityDescriptor,
448     PSID *pGroup,
449     LPBOOL lpbGroupDefaulted);
450 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
451     PSECURITY_DESCRIPTOR pSecurityDescriptor,
452     LPBOOL lpbDaclPresent,
453     PACL *pDacl,
454     LPBOOL lpbDaclDefaulted);
455 typedef BOOL (WINAPI * IsValidSid_Proc) (
456     PSID sid);
457 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
458     DWORD dwFlags,
459     DWORD th32ProcessID);
460 typedef BOOL (WINAPI * Process32First_Proc) (
461     HANDLE hSnapshot,
462     LPPROCESSENTRY32 lppe);
463 typedef BOOL (WINAPI * Process32Next_Proc) (
464     HANDLE hSnapshot,
465     LPPROCESSENTRY32 lppe);
466 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
467     HANDLE ThreadHandle,
468     DWORD DesiredAccess,
469     BOOL OpenAsSelf,
470     PHANDLE TokenHandle);
471 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
472     SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
473 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
474 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
475     HANDLE Process,
476     PPROCESS_MEMORY_COUNTERS ppsmemCounters,
477     DWORD cb);
478 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
479     HANDLE hProcess,
480     PSIZE_T lpMinimumWorkingSetSize,
481     PSIZE_T lpMaximumWorkingSetSize);
482 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
483     LPMEMORYSTATUS lpBuffer);
484 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
485     LPMEMORY_STATUS_EX lpBuffer);
486 typedef BOOL (WINAPI * CopySid_Proc) (
487     DWORD nDestinationSidLength,
488     PSID pDestinationSid,
489     PSID pSourceSid);
490 typedef BOOL (WINAPI * EqualSid_Proc) (
491     PSID pSid1,
492     PSID pSid2);
493 typedef DWORD (WINAPI * GetLengthSid_Proc) (
494     PSID pSid);
495 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
496     LPSYSTEM_INFO lpSystemInfo);
497 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
498     LPFILETIME lpIdleTime,
499     LPFILETIME lpKernelTime,
500     LPFILETIME lpUserTime);
501 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
502     LPCWSTR lpSymlinkFileName,
503     LPCWSTR lpTargetFileName,
504     DWORD  dwFlags);
505 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
506     LPCSTR lpSymlinkFileName,
507     LPCSTR lpTargetFileName,
508     DWORD  dwFlags);
509 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
510     LPCTSTR StringSecurityDescriptor,
511     DWORD StringSDRevision,
512     PSECURITY_DESCRIPTOR  *SecurityDescriptor,
513     PULONG  SecurityDescriptorSize);
514 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
515     PSECURITY_DESCRIPTOR  SecurityDescriptor,
516     DWORD RequestedStringSDRevision,
517     SECURITY_INFORMATION SecurityInformation,
518     LPTSTR  *StringSecurityDescriptor,
519     PULONG StringSecurityDescriptorLen);
520 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
521 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
522     PIP_ADAPTER_INFO pAdapterInfo,
523     PULONG pOutBufLen);
524 typedef DWORD (WINAPI *GetAdaptersAddresses_Proc) (
525     ULONG,
526     ULONG,
527     PVOID,
528     PIP_ADAPTER_ADDRESSES,
529     PULONG);
530 
531 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
532 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
533 DWORD multiByteToWideCharFlags;
534 typedef LONG (WINAPI *RegOpenKeyExW_Proc) (HKEY,LPCWSTR,DWORD,REGSAM,PHKEY);
535 typedef LONG (WINAPI *RegQueryValueExW_Proc) (HKEY,LPCWSTR,LPDWORD,LPDWORD,LPBYTE,LPDWORD);
536 typedef DWORD (WINAPI *ExpandEnvironmentStringsW_Proc) (LPCWSTR,LPWSTR,DWORD);
537 typedef LANGID (WINAPI *GetUserDefaultUILanguage_Proc) (void);
538 
539   /* ** A utility function ** */
540 static BOOL
is_windows_9x(void)541 is_windows_9x (void)
542 {
543   static BOOL s_b_ret = 0;
544   OSVERSIONINFO os_ver;
545   if (g_b_init_is_windows_9x == 0)
546     {
547       g_b_init_is_windows_9x = 1;
548       ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
549       os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
550       if (GetVersionEx (&os_ver))
551         {
552           s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
553         }
554     }
555   return s_b_ret;
556 }
557 
558 static Lisp_Object ltime (ULONGLONG);
559 
560 /* Get total user and system times for get-internal-run-time.
561    Returns a list of integers if the times are provided by the OS
562    (NT derivatives), otherwise it returns the result of current-time. */
563 Lisp_Object
w32_get_internal_run_time(void)564 w32_get_internal_run_time (void)
565 {
566   if (get_process_times_fn)
567     {
568       FILETIME create, exit, kernel, user;
569       HANDLE proc = GetCurrentProcess ();
570       if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
571         {
572           LARGE_INTEGER user_int, kernel_int, total;
573           user_int.LowPart = user.dwLowDateTime;
574           user_int.HighPart = user.dwHighDateTime;
575           kernel_int.LowPart = kernel.dwLowDateTime;
576           kernel_int.HighPart = kernel.dwHighDateTime;
577           total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
578 	  return ltime (total.QuadPart);
579         }
580     }
581 
582   return Fcurrent_time ();
583 }
584 
585   /* ** The wrapper functions ** */
586 
587 static BOOL WINAPI
open_process_token(HANDLE ProcessHandle,DWORD DesiredAccess,PHANDLE TokenHandle)588 open_process_token (HANDLE ProcessHandle,
589 		    DWORD DesiredAccess,
590 		    PHANDLE TokenHandle)
591 {
592   static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
593   HMODULE hm_advapi32 = NULL;
594   if (is_windows_9x () == TRUE)
595     {
596       return FALSE;
597     }
598   if (g_b_init_open_process_token == 0)
599     {
600       g_b_init_open_process_token = 1;
601       hm_advapi32 = LoadLibrary ("Advapi32.dll");
602       s_pfn_Open_Process_Token = (OpenProcessToken_Proc)
603         get_proc_addr (hm_advapi32, "OpenProcessToken");
604     }
605   if (s_pfn_Open_Process_Token == NULL)
606     {
607       return FALSE;
608     }
609   return (
610       s_pfn_Open_Process_Token (
611           ProcessHandle,
612           DesiredAccess,
613           TokenHandle)
614       );
615 }
616 
617 static BOOL WINAPI
get_token_information(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength,PDWORD ReturnLength)618 get_token_information (HANDLE TokenHandle,
619 		       TOKEN_INFORMATION_CLASS TokenInformationClass,
620 		       LPVOID TokenInformation,
621 		       DWORD TokenInformationLength,
622 		       PDWORD ReturnLength)
623 {
624   static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
625   HMODULE hm_advapi32 = NULL;
626   if (is_windows_9x () == TRUE)
627     {
628       return FALSE;
629     }
630   if (g_b_init_get_token_information == 0)
631     {
632       g_b_init_get_token_information = 1;
633       hm_advapi32 = LoadLibrary ("Advapi32.dll");
634       s_pfn_Get_Token_Information = (GetTokenInformation_Proc)
635         get_proc_addr (hm_advapi32, "GetTokenInformation");
636     }
637   if (s_pfn_Get_Token_Information == NULL)
638     {
639       return FALSE;
640     }
641   return (
642       s_pfn_Get_Token_Information (
643           TokenHandle,
644           TokenInformationClass,
645           TokenInformation,
646           TokenInformationLength,
647           ReturnLength)
648       );
649 }
650 
651 static BOOL WINAPI
lookup_account_sid(LPCTSTR lpSystemName,PSID Sid,LPTSTR Name,LPDWORD cbName,LPTSTR DomainName,LPDWORD cbDomainName,PSID_NAME_USE peUse)652 lookup_account_sid (LPCTSTR lpSystemName,
653 		    PSID Sid,
654 		    LPTSTR Name,
655 		    LPDWORD cbName,
656 		    LPTSTR DomainName,
657 		    LPDWORD cbDomainName,
658 		    PSID_NAME_USE peUse)
659 {
660   static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
661   HMODULE hm_advapi32 = NULL;
662   if (is_windows_9x () == TRUE)
663     {
664       return FALSE;
665     }
666   if (g_b_init_lookup_account_sid == 0)
667     {
668       g_b_init_lookup_account_sid = 1;
669       hm_advapi32 = LoadLibrary ("Advapi32.dll");
670       s_pfn_Lookup_Account_Sid = (LookupAccountSid_Proc)
671         get_proc_addr (hm_advapi32, LookupAccountSid_Name);
672     }
673   if (s_pfn_Lookup_Account_Sid == NULL)
674     {
675       return FALSE;
676     }
677   return (
678       s_pfn_Lookup_Account_Sid (
679           lpSystemName,
680           Sid,
681           Name,
682           cbName,
683           DomainName,
684           cbDomainName,
685           peUse)
686       );
687 }
688 
689 static PDWORD WINAPI
get_sid_sub_authority(PSID pSid,DWORD n)690 get_sid_sub_authority (PSID pSid, DWORD n)
691 {
692   static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
693   static DWORD zero = 0U;
694   HMODULE hm_advapi32 = NULL;
695   if (is_windows_9x () == TRUE)
696     {
697       return &zero;
698     }
699   if (g_b_init_get_sid_sub_authority == 0)
700     {
701       g_b_init_get_sid_sub_authority = 1;
702       hm_advapi32 = LoadLibrary ("Advapi32.dll");
703       s_pfn_Get_Sid_Sub_Authority = (GetSidSubAuthority_Proc)
704         get_proc_addr (hm_advapi32, "GetSidSubAuthority");
705     }
706   if (s_pfn_Get_Sid_Sub_Authority == NULL)
707     {
708       return &zero;
709     }
710   return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
711 }
712 
713 static PUCHAR WINAPI
get_sid_sub_authority_count(PSID pSid)714 get_sid_sub_authority_count (PSID pSid)
715 {
716   static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
717   static UCHAR zero = 0U;
718   HMODULE hm_advapi32 = NULL;
719   if (is_windows_9x () == TRUE)
720     {
721       return &zero;
722     }
723   if (g_b_init_get_sid_sub_authority_count == 0)
724     {
725       g_b_init_get_sid_sub_authority_count = 1;
726       hm_advapi32 = LoadLibrary ("Advapi32.dll");
727       s_pfn_Get_Sid_Sub_Authority_Count = (GetSidSubAuthorityCount_Proc)
728         get_proc_addr (hm_advapi32, "GetSidSubAuthorityCount");
729     }
730   if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
731     {
732       return &zero;
733     }
734   return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
735 }
736 
737 static DWORD WINAPI
get_security_info(HANDLE handle,SE_OBJECT_TYPE ObjectType,SECURITY_INFORMATION SecurityInfo,PSID * ppsidOwner,PSID * ppsidGroup,PACL * ppDacl,PACL * ppSacl,PSECURITY_DESCRIPTOR * ppSecurityDescriptor)738 get_security_info (HANDLE handle,
739 		   SE_OBJECT_TYPE ObjectType,
740 		   SECURITY_INFORMATION SecurityInfo,
741 		   PSID *ppsidOwner,
742 		   PSID *ppsidGroup,
743 		   PACL *ppDacl,
744 		   PACL *ppSacl,
745 		   PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
746 {
747   static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
748   HMODULE hm_advapi32 = NULL;
749   if (is_windows_9x () == TRUE)
750     {
751       return FALSE;
752     }
753   if (g_b_init_get_security_info == 0)
754     {
755       g_b_init_get_security_info = 1;
756       hm_advapi32 = LoadLibrary ("Advapi32.dll");
757       s_pfn_Get_Security_Info = (GetSecurityInfo_Proc)
758         get_proc_addr (hm_advapi32, "GetSecurityInfo");
759     }
760   if (s_pfn_Get_Security_Info == NULL)
761     {
762       return FALSE;
763     }
764   return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
765 				   ppsidOwner, ppsidGroup, ppDacl, ppSacl,
766 				   ppSecurityDescriptor));
767 }
768 
769 static BOOL WINAPI
get_file_security(const char * lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded)770 get_file_security (const char *lpFileName,
771 		   SECURITY_INFORMATION RequestedInformation,
772 		   PSECURITY_DESCRIPTOR pSecurityDescriptor,
773 		   DWORD nLength,
774 		   LPDWORD lpnLengthNeeded)
775 {
776   static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
777   static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
778   HMODULE hm_advapi32 = NULL;
779   if (is_windows_9x () == TRUE)
780     {
781       errno = ENOTSUP;
782       return FALSE;
783     }
784   if (w32_unicode_filenames)
785     {
786       wchar_t filename_w[MAX_PATH];
787 
788       if (g_b_init_get_file_security_w == 0)
789 	{
790 	  g_b_init_get_file_security_w = 1;
791 	  hm_advapi32 = LoadLibrary ("Advapi32.dll");
792 	  s_pfn_Get_File_SecurityW = (GetFileSecurityW_Proc)
793             get_proc_addr (hm_advapi32, "GetFileSecurityW");
794 	}
795       if (s_pfn_Get_File_SecurityW == NULL)
796 	{
797 	  errno = ENOTSUP;
798 	  return FALSE;
799 	}
800       filename_to_utf16 (lpFileName, filename_w);
801       return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
802 					pSecurityDescriptor, nLength,
803 					lpnLengthNeeded));
804     }
805   else
806     {
807       char filename_a[MAX_PATH];
808 
809       if (g_b_init_get_file_security_a == 0)
810 	{
811 	  g_b_init_get_file_security_a = 1;
812 	  hm_advapi32 = LoadLibrary ("Advapi32.dll");
813 	  s_pfn_Get_File_SecurityA = (GetFileSecurityA_Proc)
814             get_proc_addr (hm_advapi32, "GetFileSecurityA");
815 	}
816       if (s_pfn_Get_File_SecurityA == NULL)
817 	{
818 	  errno = ENOTSUP;
819 	  return FALSE;
820 	}
821       filename_to_ansi (lpFileName, filename_a);
822       return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
823 					pSecurityDescriptor, nLength,
824 					lpnLengthNeeded));
825     }
826 }
827 
828 static BOOL WINAPI
set_file_security(const char * lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor)829 set_file_security (const char *lpFileName,
830 		   SECURITY_INFORMATION SecurityInformation,
831 		   PSECURITY_DESCRIPTOR pSecurityDescriptor)
832 {
833   static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
834   static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
835   HMODULE hm_advapi32 = NULL;
836   if (is_windows_9x () == TRUE)
837     {
838       errno = ENOTSUP;
839       return FALSE;
840     }
841   if (w32_unicode_filenames)
842     {
843       wchar_t filename_w[MAX_PATH];
844 
845       if (g_b_init_set_file_security_w == 0)
846 	{
847 	  g_b_init_set_file_security_w = 1;
848 	  hm_advapi32 = LoadLibrary ("Advapi32.dll");
849 	  s_pfn_Set_File_SecurityW = (SetFileSecurityW_Proc)
850             get_proc_addr (hm_advapi32, "SetFileSecurityW");
851 	}
852       if (s_pfn_Set_File_SecurityW == NULL)
853 	{
854 	  errno = ENOTSUP;
855 	  return FALSE;
856 	}
857       filename_to_utf16 (lpFileName, filename_w);
858       return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
859 					pSecurityDescriptor));
860     }
861   else
862     {
863       char filename_a[MAX_PATH];
864 
865       if (g_b_init_set_file_security_a == 0)
866 	{
867 	  g_b_init_set_file_security_a = 1;
868 	  hm_advapi32 = LoadLibrary ("Advapi32.dll");
869 	  s_pfn_Set_File_SecurityA = (SetFileSecurityA_Proc)
870             get_proc_addr (hm_advapi32, "SetFileSecurityA");
871 	}
872       if (s_pfn_Set_File_SecurityA == NULL)
873 	{
874 	  errno = ENOTSUP;
875 	  return FALSE;
876 	}
877       filename_to_ansi (lpFileName, filename_a);
878       return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
879 					pSecurityDescriptor));
880     }
881 }
882 
883 static DWORD WINAPI
set_named_security_info(LPCTSTR lpObjectName,SE_OBJECT_TYPE ObjectType,SECURITY_INFORMATION SecurityInformation,PSID psidOwner,PSID psidGroup,PACL pDacl,PACL pSacl)884 set_named_security_info (LPCTSTR lpObjectName,
885 			 SE_OBJECT_TYPE ObjectType,
886 			 SECURITY_INFORMATION SecurityInformation,
887 			 PSID psidOwner,
888 			 PSID psidGroup,
889 			 PACL pDacl,
890 			 PACL pSacl)
891 {
892   static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
893   static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
894   HMODULE hm_advapi32 = NULL;
895   if (is_windows_9x () == TRUE)
896     {
897       errno = ENOTSUP;
898       return ENOTSUP;
899     }
900   if (w32_unicode_filenames)
901     {
902       wchar_t filename_w[MAX_PATH];
903 
904       if (g_b_init_set_named_security_info_w == 0)
905 	{
906 	  g_b_init_set_named_security_info_w = 1;
907 	  hm_advapi32 = LoadLibrary ("Advapi32.dll");
908 	  s_pfn_Set_Named_Security_InfoW = (SetNamedSecurityInfoW_Proc)
909             get_proc_addr (hm_advapi32, "SetNamedSecurityInfoW");
910 	}
911       if (s_pfn_Set_Named_Security_InfoW == NULL)
912 	{
913 	  errno = ENOTSUP;
914 	  return ENOTSUP;
915 	}
916       filename_to_utf16 (lpObjectName, filename_w);
917       return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
918 					      SecurityInformation, psidOwner,
919 					      psidGroup, pDacl, pSacl));
920     }
921   else
922     {
923       char filename_a[MAX_PATH];
924 
925       if (g_b_init_set_named_security_info_a == 0)
926 	{
927 	  g_b_init_set_named_security_info_a = 1;
928 	  hm_advapi32 = LoadLibrary ("Advapi32.dll");
929 	  s_pfn_Set_Named_Security_InfoA = (SetNamedSecurityInfoA_Proc)
930             get_proc_addr (hm_advapi32, "SetNamedSecurityInfoA");
931 	}
932       if (s_pfn_Set_Named_Security_InfoA == NULL)
933 	{
934 	  errno = ENOTSUP;
935 	  return ENOTSUP;
936 	}
937       filename_to_ansi (lpObjectName, filename_a);
938       return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
939 					      SecurityInformation, psidOwner,
940 					      psidGroup, pDacl, pSacl));
941     }
942 }
943 
944 static BOOL WINAPI
get_security_descriptor_owner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID * pOwner,LPBOOL lpbOwnerDefaulted)945 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
946 			       PSID *pOwner,
947 			       LPBOOL lpbOwnerDefaulted)
948 {
949   static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
950   HMODULE hm_advapi32 = NULL;
951   if (is_windows_9x () == TRUE)
952     {
953       errno = ENOTSUP;
954       return FALSE;
955     }
956   if (g_b_init_get_security_descriptor_owner == 0)
957     {
958       g_b_init_get_security_descriptor_owner = 1;
959       hm_advapi32 = LoadLibrary ("Advapi32.dll");
960       s_pfn_Get_Security_Descriptor_Owner = (GetSecurityDescriptorOwner_Proc)
961         get_proc_addr (hm_advapi32, "GetSecurityDescriptorOwner");
962     }
963   if (s_pfn_Get_Security_Descriptor_Owner == NULL)
964     {
965       errno = ENOTSUP;
966       return FALSE;
967     }
968   return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
969 					       lpbOwnerDefaulted));
970 }
971 
972 static BOOL WINAPI
get_security_descriptor_group(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID * pGroup,LPBOOL lpbGroupDefaulted)973 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
974 			       PSID *pGroup,
975 			       LPBOOL lpbGroupDefaulted)
976 {
977   static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
978   HMODULE hm_advapi32 = NULL;
979   if (is_windows_9x () == TRUE)
980     {
981       errno = ENOTSUP;
982       return FALSE;
983     }
984   if (g_b_init_get_security_descriptor_group == 0)
985     {
986       g_b_init_get_security_descriptor_group = 1;
987       hm_advapi32 = LoadLibrary ("Advapi32.dll");
988       s_pfn_Get_Security_Descriptor_Group = (GetSecurityDescriptorGroup_Proc)
989         get_proc_addr (hm_advapi32, "GetSecurityDescriptorGroup");
990     }
991   if (s_pfn_Get_Security_Descriptor_Group == NULL)
992     {
993       errno = ENOTSUP;
994       return FALSE;
995     }
996   return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
997 					       lpbGroupDefaulted));
998 }
999 
1000 static BOOL WINAPI
get_security_descriptor_dacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbDaclPresent,PACL * pDacl,LPBOOL lpbDaclDefaulted)1001 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
1002 			      LPBOOL lpbDaclPresent,
1003 			      PACL *pDacl,
1004 			      LPBOOL lpbDaclDefaulted)
1005 {
1006   static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
1007   HMODULE hm_advapi32 = NULL;
1008   if (is_windows_9x () == TRUE)
1009     {
1010       errno = ENOTSUP;
1011       return FALSE;
1012     }
1013   if (g_b_init_get_security_descriptor_dacl == 0)
1014     {
1015       g_b_init_get_security_descriptor_dacl = 1;
1016       hm_advapi32 = LoadLibrary ("Advapi32.dll");
1017       s_pfn_Get_Security_Descriptor_Dacl = (GetSecurityDescriptorDacl_Proc)
1018         get_proc_addr (hm_advapi32, "GetSecurityDescriptorDacl");
1019     }
1020   if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
1021     {
1022       errno = ENOTSUP;
1023       return FALSE;
1024     }
1025   return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
1026 					      lpbDaclPresent, pDacl,
1027 					      lpbDaclDefaulted));
1028 }
1029 
1030 static BOOL WINAPI
is_valid_sid(PSID sid)1031 is_valid_sid (PSID sid)
1032 {
1033   static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
1034   HMODULE hm_advapi32 = NULL;
1035   if (is_windows_9x () == TRUE)
1036     {
1037       return FALSE;
1038     }
1039   if (g_b_init_is_valid_sid == 0)
1040     {
1041       g_b_init_is_valid_sid = 1;
1042       hm_advapi32 = LoadLibrary ("Advapi32.dll");
1043       s_pfn_Is_Valid_Sid = (IsValidSid_Proc)
1044         get_proc_addr (hm_advapi32, "IsValidSid");
1045     }
1046   if (s_pfn_Is_Valid_Sid == NULL)
1047     {
1048       return FALSE;
1049     }
1050   return (s_pfn_Is_Valid_Sid (sid));
1051 }
1052 
1053 static BOOL WINAPI
equal_sid(PSID sid1,PSID sid2)1054 equal_sid (PSID sid1, PSID sid2)
1055 {
1056   static EqualSid_Proc s_pfn_Equal_Sid = NULL;
1057   HMODULE hm_advapi32 = NULL;
1058   if (is_windows_9x () == TRUE)
1059     {
1060       return FALSE;
1061     }
1062   if (g_b_init_equal_sid == 0)
1063     {
1064       g_b_init_equal_sid = 1;
1065       hm_advapi32 = LoadLibrary ("Advapi32.dll");
1066       s_pfn_Equal_Sid = (EqualSid_Proc)
1067         get_proc_addr (hm_advapi32, "EqualSid");
1068     }
1069   if (s_pfn_Equal_Sid == NULL)
1070     {
1071       return FALSE;
1072     }
1073   return (s_pfn_Equal_Sid (sid1, sid2));
1074 }
1075 
1076 static DWORD WINAPI
get_length_sid(PSID sid)1077 get_length_sid (PSID sid)
1078 {
1079   static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
1080   HMODULE hm_advapi32 = NULL;
1081   if (is_windows_9x () == TRUE)
1082     {
1083       return 0;
1084     }
1085   if (g_b_init_get_length_sid == 0)
1086     {
1087       g_b_init_get_length_sid = 1;
1088       hm_advapi32 = LoadLibrary ("Advapi32.dll");
1089       s_pfn_Get_Length_Sid = (GetLengthSid_Proc)
1090         get_proc_addr (hm_advapi32, "GetLengthSid");
1091     }
1092   if (s_pfn_Get_Length_Sid == NULL)
1093     {
1094       return 0;
1095     }
1096   return (s_pfn_Get_Length_Sid (sid));
1097 }
1098 
1099 static BOOL WINAPI
copy_sid(DWORD destlen,PSID dest,PSID src)1100 copy_sid (DWORD destlen, PSID dest, PSID src)
1101 {
1102   static CopySid_Proc s_pfn_Copy_Sid = NULL;
1103   HMODULE hm_advapi32 = NULL;
1104   if (is_windows_9x () == TRUE)
1105     {
1106       return FALSE;
1107     }
1108   if (g_b_init_copy_sid == 0)
1109     {
1110       g_b_init_copy_sid = 1;
1111       hm_advapi32 = LoadLibrary ("Advapi32.dll");
1112       s_pfn_Copy_Sid = (CopySid_Proc)
1113         get_proc_addr (hm_advapi32, "CopySid");
1114     }
1115   if (s_pfn_Copy_Sid == NULL)
1116     {
1117       return FALSE;
1118     }
1119   return (s_pfn_Copy_Sid (destlen, dest, src));
1120 }
1121 
1122 /*
1123   END: Wrapper functions around OpenProcessToken
1124   and other functions in advapi32.dll that are only
1125   supported in Windows NT / 2k / XP
1126 */
1127 
1128 static void WINAPI
get_native_system_info(LPSYSTEM_INFO lpSystemInfo)1129 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1130 {
1131   static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1132   if (is_windows_9x () != TRUE)
1133     {
1134       if (g_b_init_get_native_system_info == 0)
1135 	{
1136 	  g_b_init_get_native_system_info = 1;
1137 	  s_pfn_Get_Native_System_Info = (GetNativeSystemInfo_Proc)
1138             get_proc_addr (GetModuleHandle ("kernel32.dll"),
1139                                   "GetNativeSystemInfo");
1140 	}
1141       if (s_pfn_Get_Native_System_Info != NULL)
1142 	s_pfn_Get_Native_System_Info (lpSystemInfo);
1143     }
1144   else
1145     lpSystemInfo->dwNumberOfProcessors = -1;
1146 }
1147 
1148 static BOOL WINAPI
get_system_times(LPFILETIME lpIdleTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime)1149 get_system_times (LPFILETIME lpIdleTime,
1150 		  LPFILETIME lpKernelTime,
1151 		  LPFILETIME lpUserTime)
1152 {
1153   static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1154   if (is_windows_9x () == TRUE)
1155     {
1156       return FALSE;
1157     }
1158   if (g_b_init_get_system_times == 0)
1159     {
1160       g_b_init_get_system_times = 1;
1161       s_pfn_Get_System_times = (GetSystemTimes_Proc)
1162         get_proc_addr (GetModuleHandle ("kernel32.dll"),
1163                               "GetSystemTimes");
1164     }
1165   if (s_pfn_Get_System_times == NULL)
1166     return FALSE;
1167   return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1168 }
1169 
1170 static BOOLEAN WINAPI
create_symbolic_link(LPCSTR lpSymlinkFilename,LPCSTR lpTargetFileName,DWORD dwFlags)1171 create_symbolic_link (LPCSTR lpSymlinkFilename,
1172 		      LPCSTR lpTargetFileName,
1173 		      DWORD dwFlags)
1174 {
1175   static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1176   static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1177   BOOLEAN retval;
1178 
1179   if (is_windows_9x () == TRUE)
1180     {
1181       errno = ENOSYS;
1182       return 0;
1183     }
1184   if (w32_unicode_filenames)
1185     {
1186       wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1187 
1188       if (g_b_init_create_symbolic_link_w == 0)
1189 	{
1190 	  g_b_init_create_symbolic_link_w = 1;
1191 	  s_pfn_Create_Symbolic_LinkW = (CreateSymbolicLinkW_Proc)
1192             get_proc_addr (GetModuleHandle ("kernel32.dll"),
1193                                   "CreateSymbolicLinkW");
1194 	}
1195       if (s_pfn_Create_Symbolic_LinkW == NULL)
1196 	{
1197 	  errno = ENOSYS;
1198 	  return 0;
1199 	}
1200 
1201       filename_to_utf16 (lpSymlinkFilename, symfn_w);
1202       filename_to_utf16 (lpTargetFileName, tgtfn_w);
1203       retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1204       /* If we were denied creation of the symlink, try again after
1205 	 enabling the SeCreateSymbolicLinkPrivilege for our process.  */
1206       if (!retval)
1207 	{
1208 	  TOKEN_PRIVILEGES priv_current;
1209 
1210 	  if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1211 				&priv_current))
1212 	    {
1213 	      retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1214 	      restore_privilege (&priv_current);
1215 	      revert_to_self ();
1216 	    }
1217 	}
1218     }
1219   else
1220     {
1221       char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1222 
1223       if (g_b_init_create_symbolic_link_a == 0)
1224 	{
1225 	  g_b_init_create_symbolic_link_a = 1;
1226 	  s_pfn_Create_Symbolic_LinkA = (CreateSymbolicLinkA_Proc)
1227             get_proc_addr (GetModuleHandle ("kernel32.dll"),
1228                                   "CreateSymbolicLinkA");
1229 	}
1230       if (s_pfn_Create_Symbolic_LinkA == NULL)
1231 	{
1232 	  errno = ENOSYS;
1233 	  return 0;
1234 	}
1235 
1236       filename_to_ansi (lpSymlinkFilename, symfn_a);
1237       filename_to_ansi (lpTargetFileName, tgtfn_a);
1238       retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1239       /* If we were denied creation of the symlink, try again after
1240 	 enabling the SeCreateSymbolicLinkPrivilege for our process.  */
1241       if (!retval)
1242 	{
1243 	  TOKEN_PRIVILEGES priv_current;
1244 
1245 	  if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1246 				&priv_current))
1247 	    {
1248 	      retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1249 	      restore_privilege (&priv_current);
1250 	      revert_to_self ();
1251 	    }
1252 	}
1253     }
1254   return retval;
1255 }
1256 
1257 static BOOL WINAPI
is_valid_security_descriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor)1258 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1259 {
1260   static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1261 
1262   if (is_windows_9x () == TRUE)
1263     {
1264       errno = ENOTSUP;
1265       return FALSE;
1266     }
1267 
1268   if (g_b_init_is_valid_security_descriptor == 0)
1269     {
1270       g_b_init_is_valid_security_descriptor = 1;
1271       s_pfn_Is_Valid_Security_Descriptor_Proc = (IsValidSecurityDescriptor_Proc)
1272         get_proc_addr (GetModuleHandle ("Advapi32.dll"),
1273                               "IsValidSecurityDescriptor");
1274     }
1275   if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1276     {
1277       errno = ENOTSUP;
1278       return FALSE;
1279     }
1280 
1281   return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1282 }
1283 
1284 static BOOL WINAPI
convert_sd_to_sddl(PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD RequestedStringSDRevision,SECURITY_INFORMATION SecurityInformation,LPTSTR * StringSecurityDescriptor,PULONG StringSecurityDescriptorLen)1285 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1286 		    DWORD RequestedStringSDRevision,
1287 		    SECURITY_INFORMATION SecurityInformation,
1288 		    LPTSTR  *StringSecurityDescriptor,
1289 		    PULONG StringSecurityDescriptorLen)
1290 {
1291   static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1292   BOOL retval;
1293 
1294   if (is_windows_9x () == TRUE)
1295     {
1296       errno = ENOTSUP;
1297       return FALSE;
1298     }
1299 
1300   if (g_b_init_convert_sd_to_sddl == 0)
1301     {
1302       g_b_init_convert_sd_to_sddl = 1;
1303 #ifdef _UNICODE
1304       s_pfn_Convert_SD_To_SDDL =
1305 	(ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)
1306         get_proc_addr (GetModuleHandle ("Advapi32.dll"),
1307                               "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1308 #else
1309       s_pfn_Convert_SD_To_SDDL =
1310 	(ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)
1311         get_proc_addr (GetModuleHandle ("Advapi32.dll"),
1312                               "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1313 #endif
1314     }
1315   if (s_pfn_Convert_SD_To_SDDL == NULL)
1316     {
1317       errno = ENOTSUP;
1318       return FALSE;
1319     }
1320 
1321   retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1322 				     RequestedStringSDRevision,
1323 				     SecurityInformation,
1324 				     StringSecurityDescriptor,
1325 				     StringSecurityDescriptorLen);
1326 
1327   return retval;
1328 }
1329 
1330 static BOOL WINAPI
convert_sddl_to_sd(LPCTSTR StringSecurityDescriptor,DWORD StringSDRevision,PSECURITY_DESCRIPTOR * SecurityDescriptor,PULONG SecurityDescriptorSize)1331 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1332 		    DWORD StringSDRevision,
1333 		    PSECURITY_DESCRIPTOR  *SecurityDescriptor,
1334 		    PULONG  SecurityDescriptorSize)
1335 {
1336   static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1337   BOOL retval;
1338 
1339   if (is_windows_9x () == TRUE)
1340     {
1341       errno = ENOTSUP;
1342       return FALSE;
1343     }
1344 
1345   if (g_b_init_convert_sddl_to_sd == 0)
1346     {
1347       g_b_init_convert_sddl_to_sd = 1;
1348 #ifdef _UNICODE
1349       s_pfn_Convert_SDDL_To_SD =
1350 	(ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)
1351         get_proc_addr (GetModuleHandle ("Advapi32.dll"),
1352                               "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1353 #else
1354       s_pfn_Convert_SDDL_To_SD =
1355 	(ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)
1356         get_proc_addr (GetModuleHandle ("Advapi32.dll"),
1357                               "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1358 #endif
1359     }
1360   if (s_pfn_Convert_SDDL_To_SD == NULL)
1361     {
1362       errno = ENOTSUP;
1363       return FALSE;
1364     }
1365 
1366   retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1367 				     StringSDRevision,
1368 				     SecurityDescriptor,
1369 				     SecurityDescriptorSize);
1370 
1371   return retval;
1372 }
1373 
1374 static DWORD WINAPI
get_adapters_info(PIP_ADAPTER_INFO pAdapterInfo,PULONG pOutBufLen)1375 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1376 {
1377   static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1378   HMODULE hm_iphlpapi = NULL;
1379 
1380   if (is_windows_9x () == TRUE)
1381     return ERROR_NOT_SUPPORTED;
1382 
1383   if (g_b_init_get_adapters_info == 0)
1384     {
1385       g_b_init_get_adapters_info = 1;
1386       hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1387       if (hm_iphlpapi)
1388 	s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1389 	  get_proc_addr (hm_iphlpapi, "GetAdaptersInfo");
1390     }
1391   if (s_pfn_Get_Adapters_Info == NULL)
1392     return ERROR_NOT_SUPPORTED;
1393   return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1394 }
1395 
1396 static DWORD WINAPI
get_adapters_addresses(ULONG family,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)1397 get_adapters_addresses (ULONG family, PIP_ADAPTER_ADDRESSES pAdapterAddresses, PULONG pOutBufLen)
1398 {
1399   static GetAdaptersAddresses_Proc s_pfn_Get_Adapters_Addresses = NULL;
1400   HMODULE hm_iphlpapi = NULL;
1401 
1402   if (is_windows_9x () == TRUE)
1403     return ERROR_NOT_SUPPORTED;
1404 
1405   if (g_b_init_get_adapters_addresses == 0)
1406     {
1407       g_b_init_get_adapters_addresses = 1;
1408       hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1409       if (hm_iphlpapi)
1410 	s_pfn_Get_Adapters_Addresses = (GetAdaptersAddresses_Proc)
1411 	  get_proc_addr (hm_iphlpapi, "GetAdaptersAddresses");
1412     }
1413   if (s_pfn_Get_Adapters_Addresses == NULL)
1414     return ERROR_NOT_SUPPORTED;
1415   ULONG flags = GAA_FLAG_SKIP_ANYCAST
1416     | GAA_FLAG_SKIP_MULTICAST
1417     | GAA_FLAG_SKIP_DNS_SERVER;
1418   return s_pfn_Get_Adapters_Addresses (family, flags, NULL, pAdapterAddresses, pOutBufLen);
1419 }
1420 
1421 static LONG WINAPI
reg_open_key_ex_w(HKEY hkey,LPCWSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult)1422 reg_open_key_ex_w (HKEY hkey, LPCWSTR lpSubKey, DWORD ulOptions,
1423 		   REGSAM samDesired, PHKEY phkResult)
1424 {
1425   static RegOpenKeyExW_Proc s_pfn_Reg_Open_Key_Ex_w = NULL;
1426   HMODULE hm_advapi32 = NULL;
1427 
1428   if (is_windows_9x () == TRUE)
1429     return ERROR_NOT_SUPPORTED;
1430 
1431   if (g_b_init_reg_open_key_ex_w == 0)
1432     {
1433       g_b_init_reg_open_key_ex_w = 1;
1434       hm_advapi32 = LoadLibrary ("Advapi32.dll");
1435       if (hm_advapi32)
1436 	s_pfn_Reg_Open_Key_Ex_w = (RegOpenKeyExW_Proc)
1437 	  get_proc_addr (hm_advapi32, "RegOpenKeyExW");
1438     }
1439   if (s_pfn_Reg_Open_Key_Ex_w == NULL)
1440     return ERROR_NOT_SUPPORTED;
1441   return s_pfn_Reg_Open_Key_Ex_w (hkey, lpSubKey, ulOptions,
1442 				  samDesired, phkResult);
1443 }
1444 
1445 static LONG WINAPI
reg_query_value_ex_w(HKEY hkey,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData)1446 reg_query_value_ex_w (HKEY hkey, LPCWSTR lpValueName, LPDWORD lpReserved,
1447 		      LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
1448 {
1449   static RegQueryValueExW_Proc s_pfn_Reg_Query_Value_Ex_w = NULL;
1450   HMODULE hm_advapi32 = NULL;
1451 
1452   if (is_windows_9x () == TRUE)
1453     return ERROR_NOT_SUPPORTED;
1454 
1455   if (g_b_init_reg_query_value_ex_w == 0)
1456     {
1457       g_b_init_reg_query_value_ex_w = 1;
1458       hm_advapi32 = LoadLibrary ("Advapi32.dll");
1459       if (hm_advapi32)
1460 	s_pfn_Reg_Query_Value_Ex_w = (RegQueryValueExW_Proc)
1461 	  get_proc_addr (hm_advapi32, "RegQueryValueExW");
1462     }
1463   if (s_pfn_Reg_Query_Value_Ex_w == NULL)
1464     return ERROR_NOT_SUPPORTED;
1465   return s_pfn_Reg_Query_Value_Ex_w (hkey, lpValueName, lpReserved,
1466 				     lpType, lpData, lpcbData);
1467 }
1468 
1469 static DWORD WINAPI
expand_environment_strings_w(LPCWSTR lpSrc,LPWSTR lpDst,DWORD nSize)1470 expand_environment_strings_w (LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize)
1471 {
1472   static ExpandEnvironmentStringsW_Proc s_pfn_Expand_Environment_Strings_w = NULL;
1473   HMODULE hm_kernel32 = NULL;
1474 
1475   if (is_windows_9x () == TRUE)
1476     return ERROR_NOT_SUPPORTED;
1477 
1478   if (g_b_init_expand_environment_strings_w == 0)
1479     {
1480       g_b_init_expand_environment_strings_w = 1;
1481       hm_kernel32 = LoadLibrary ("Kernel32.dll");
1482       if (hm_kernel32)
1483 	s_pfn_Expand_Environment_Strings_w = (ExpandEnvironmentStringsW_Proc)
1484 	  get_proc_addr (hm_kernel32, "ExpandEnvironmentStringsW");
1485     }
1486   if (s_pfn_Expand_Environment_Strings_w == NULL)
1487     {
1488       errno = ENOSYS;
1489       return FALSE;
1490     }
1491   return s_pfn_Expand_Environment_Strings_w (lpSrc, lpDst, nSize);
1492 }
1493 
1494 static LANGID WINAPI
get_user_default_ui_language(void)1495 get_user_default_ui_language (void)
1496 {
1497   static GetUserDefaultUILanguage_Proc s_pfn_GetUserDefaultUILanguage = NULL;
1498   HMODULE hm_kernel32 = NULL;
1499 
1500   if (is_windows_9x () == TRUE)
1501     return 0;
1502 
1503   if (g_b_init_get_user_default_ui_language == 0)
1504     {
1505       g_b_init_get_user_default_ui_language = 1;
1506       hm_kernel32 = LoadLibrary ("Kernel32.dll");
1507       if (hm_kernel32)
1508 	s_pfn_GetUserDefaultUILanguage = (GetUserDefaultUILanguage_Proc)
1509 	  get_proc_addr (hm_kernel32, "GetUserDefaultUILanguage");
1510     }
1511   if (s_pfn_GetUserDefaultUILanguage == NULL)
1512     return 0;
1513   return s_pfn_GetUserDefaultUILanguage ();
1514 }
1515 
1516 
1517 
1518 /* Return 1 if P is a valid pointer to an object of size SIZE.  Return
1519    0 if P is NOT a valid pointer.  Return -1 if we cannot validate P.
1520 
1521    This is called from alloc.c:valid_pointer_p.  */
1522 int
w32_valid_pointer_p(void * p,int size)1523 w32_valid_pointer_p (void *p, int size)
1524 {
1525   SIZE_T done;
1526   HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1527 
1528   if (h)
1529     {
1530       unsigned char *buf = alloca (size);
1531       int retval = ReadProcessMemory (h, p, buf, size, &done);
1532 
1533       CloseHandle (h);
1534       return retval;
1535     }
1536   else
1537     return -1;
1538 }
1539 
1540 
1541 
1542 /* Here's an overview of how the Windows build supports file names
1543    that cannot be encoded by the current system codepage.
1544 
1545    From the POV of Lisp and layers of C code above the functions here,
1546    Emacs on Windows pretends that its file names are encoded in UTF-8;
1547    see encode_file and decode_file on coding.c.  Any file name that is
1548    passed as a unibyte string to C functions defined here is assumed
1549    to be in UTF-8 encoding.  Any file name returned by functions
1550    defined here must be in UTF-8 encoding, with only a few exceptions
1551    reserved for a couple of special cases.  (Be sure to use
1552    MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1553    as they can be much longer than MAX_PATH!)
1554 
1555    The UTF-8 encoded file names cannot be passed to system APIs, as
1556    Windows does not support that.  Therefore, they are converted
1557    either to UTF-16 or to the ANSI codepage, depending on the value of
1558    w32-unicode-filenames, before calling any system APIs or CRT library
1559    functions.  The default value of that variable is determined by the
1560    OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1561    user can change that default (although I don't see why would she
1562    want to).
1563 
1564    The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1565    filename_from_utf16, and filename_from_ansi, are the workhorses of
1566    these conversions.  They rely on Windows native APIs
1567    MultiByteToWideChar and WideCharToMultiByte; we cannot use
1568    functions from coding.c here, because they allocate memory, which
1569    is a bad idea on the level of libc, which is what the functions
1570    here emulate.  (If you worry about performance due to constant
1571    conversion back and forth from UTF-8 to UTF-16, then don't: first,
1572    it was measured to take only a few microseconds on a not-so-fast
1573    machine, and second, that's exactly what the ANSI APIs we used
1574    before did anyway, because they are just thin wrappers around the
1575    Unicode APIs.)
1576 
1577    The variables file-name-coding-system and default-file-name-coding-system
1578    still exist, but are actually used only when a file name needs to
1579    be converted to the ANSI codepage.  This happens all the time when
1580    w32-unicode-filenames is nil, but can also happen from time to time
1581    when it is t.  Otherwise, these variables have no effect on file-name
1582    encoding when w32-unicode-filenames is t; this is similar to
1583    selection-coding-system.
1584 
1585    This arrangement works very well, but it has a few gotchas and
1586    limitations:
1587 
1588    . Lisp code that encodes or decodes file names manually should
1589      normally use 'utf-8' as the coding-system on Windows,
1590      disregarding file-name-coding-system.  This is a somewhat
1591      unpleasant consequence, but it cannot be avoided.  Fortunately,
1592      very few Lisp packages need to do that.
1593 
1594      More generally, passing to library functions (e.g., fopen or
1595      opendir) file names already encoded in the ANSI codepage is
1596      explicitly *verboten*, as all those functions, as shadowed and
1597      emulated here, assume they will receive UTF-8 encoded file names.
1598 
1599      For the same reasons, no CRT function or Win32 API can be called
1600      directly in Emacs sources, without either converting the file
1601      names from UTF-8 to UTF-16 or ANSI codepage, or going through
1602      some shadowing function defined here.
1603 
1604    . Environment variables stored in Vprocess_environment are encoded
1605      in the ANSI codepage, so if getenv/egetenv is used for a variable
1606      whose value is a file name or a list of directories, it needs to
1607      be converted to UTF-8, before it is used as argument to functions
1608      or decoded into a Lisp string.
1609 
1610    . File names passed to external libraries, like the image libraries
1611      and GnuTLS, need special handling.  These libraries generally
1612      don't support UTF-16 or UTF-8 file names, so they must get file
1613      names encoded in the ANSI codepage.  To facilitate using these
1614      libraries with file names that are not encodable in the ANSI
1615      codepage, use the function ansi_encode_filename, which will try
1616      to use the short 8+3 alias of a file name if that file name is
1617      not encodable in the ANSI codepage.  See image.c and gnutls.c for
1618      examples of how this should be done.
1619 
1620    . Running subprocesses in non-ASCII directories and with non-ASCII
1621      file arguments is limited to the current codepage (even though
1622      Emacs is perfectly capable of finding an executable program file
1623      in a directory whose name cannot be encoded in the current
1624      codepage).  This is because the command-line arguments are
1625      encoded _before_ they get to the w32-specific level, and the
1626      encoding is not known in advance (it doesn't have to be the
1627      current ANSI codepage), so w32proc.c functions cannot re-encode
1628      them in UTF-16.  This should be fixed, but will also require
1629      changes in cmdproxy.  The current limitation is not terribly bad
1630      anyway, since very few, if any, Windows console programs that are
1631      likely to be invoked by Emacs support UTF-16 encoded command
1632      lines.
1633 
1634    . For similar reasons, server.el and emacsclient are also limited
1635      to the current ANSI codepage for now.
1636 
1637    . Emacs itself can only handle command-line arguments encoded in
1638      the current codepage.
1639 
1640    . Turning on w32-unicode-filename on Windows 9X (if it at all
1641      works) requires UNICOWS.DLL, which is thus a requirement even in
1642      non-GUI sessions, something that we previously avoided.  */
1643 
1644 
1645 
1646 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1647    codepage defined by file-name-coding-system.  */
1648 
1649 /* Current codepage for encoding file names.  */
1650 static int file_name_codepage;
1651 
1652 /* Initialize the codepage used for decoding file names.  This is
1653    needed to undo the value recorded during dumping, which might not
1654    be correct when we run the dumped Emacs.  */
1655 void
w32_init_file_name_codepage(void)1656 w32_init_file_name_codepage (void)
1657 {
1658   file_name_codepage = CP_ACP;
1659   w32_ansi_code_page = CP_ACP;
1660 }
1661 
1662 /* Produce a Windows ANSI codepage suitable for encoding file names.
1663    Return the information about that codepage in CP_INFO.  */
1664 int
codepage_for_filenames(CPINFO * cp_info)1665 codepage_for_filenames (CPINFO *cp_info)
1666 {
1667   /* A simple cache to avoid calling GetCPInfo every time we need to
1668      encode/decode a file name.  The file-name encoding is not
1669      supposed to be changed too frequently, if ever.  */
1670   static Lisp_Object last_file_name_encoding;
1671   static CPINFO cp;
1672   Lisp_Object current_encoding;
1673 
1674   current_encoding = Vfile_name_coding_system;
1675   if (NILP (current_encoding))
1676     current_encoding = Vdefault_file_name_coding_system;
1677 
1678   if (!EQ (last_file_name_encoding, current_encoding)
1679       || NILP (last_file_name_encoding))
1680     {
1681       /* Default to the current ANSI codepage.  */
1682       file_name_codepage = w32_ansi_code_page;
1683 
1684       if (!NILP (current_encoding))
1685 	{
1686 	  char *cpname = SSDATA (SYMBOL_NAME (current_encoding));
1687 	  char *cp = NULL, *end;
1688 	  int cpnum;
1689 
1690 	  if (strncmp (cpname, "cp", 2) == 0)
1691 	    cp = cpname + 2;
1692 	  else if (strncmp (cpname, "windows-", 8) == 0)
1693 	    cp = cpname + 8;
1694 
1695 	  if (cp)
1696 	    {
1697 	      end = cp;
1698 	      cpnum = strtol (cp, &end, 10);
1699 	      if (cpnum && *end == '\0' && end - cp >= 2)
1700 		file_name_codepage = cpnum;
1701 	    }
1702 	}
1703 
1704       if (!file_name_codepage)
1705 	file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1706 
1707       if (!GetCPInfo (file_name_codepage, &cp))
1708 	{
1709 	  file_name_codepage = CP_ACP;
1710 	  if (!GetCPInfo (file_name_codepage, &cp))
1711 	    emacs_abort ();
1712 	}
1713 
1714       /* Cache the new value.  */
1715       last_file_name_encoding = current_encoding;
1716     }
1717   if (cp_info)
1718     *cp_info = cp;
1719 
1720   return file_name_codepage;
1721 }
1722 
1723 int
filename_to_utf16(const char * fn_in,wchar_t * fn_out)1724 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1725 {
1726   int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
1727 				     -1, fn_out, MAX_PATH);
1728 
1729   if (!result)
1730     {
1731       DWORD err = GetLastError ();
1732 
1733       switch (err)
1734 	{
1735 	case ERROR_INVALID_FLAGS:
1736 	case ERROR_INVALID_PARAMETER:
1737 	  errno = EINVAL;
1738 	  break;
1739 	case ERROR_INSUFFICIENT_BUFFER:
1740 	case ERROR_NO_UNICODE_TRANSLATION:
1741 	default:
1742 	  errno = ENOENT;
1743 	  break;
1744 	}
1745       return -1;
1746     }
1747   return 0;
1748 }
1749 
1750 int
filename_from_utf16(const wchar_t * fn_in,char * fn_out)1751 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1752 {
1753   int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1754 				     fn_out, MAX_UTF8_PATH, NULL, NULL);
1755 
1756   if (!result)
1757     {
1758       DWORD err = GetLastError ();
1759 
1760       switch (err)
1761 	{
1762 	case ERROR_INVALID_FLAGS:
1763 	case ERROR_INVALID_PARAMETER:
1764 	  errno = EINVAL;
1765 	  break;
1766 	case ERROR_INSUFFICIENT_BUFFER:
1767 	case ERROR_NO_UNICODE_TRANSLATION:
1768 	default:
1769 	  errno = ENOENT;
1770 	  break;
1771 	}
1772       return -1;
1773     }
1774   return 0;
1775 }
1776 
1777 int
filename_to_ansi(const char * fn_in,char * fn_out)1778 filename_to_ansi (const char *fn_in, char *fn_out)
1779 {
1780   wchar_t fn_utf16[MAX_PATH];
1781 
1782   if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1783     {
1784       int result;
1785       int codepage = codepage_for_filenames (NULL);
1786 
1787       result  = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
1788 				      fn_out, MAX_PATH, NULL, NULL);
1789       if (!result)
1790 	{
1791 	  DWORD err = GetLastError ();
1792 
1793 	  switch (err)
1794 	    {
1795 	    case ERROR_INVALID_FLAGS:
1796 	    case ERROR_INVALID_PARAMETER:
1797 	      errno = EINVAL;
1798 	      break;
1799 	    case ERROR_INSUFFICIENT_BUFFER:
1800 	    case ERROR_NO_UNICODE_TRANSLATION:
1801 	    default:
1802 	      errno = ENOENT;
1803 	      break;
1804 	    }
1805 	  return -1;
1806 	}
1807       return 0;
1808     }
1809   return -1;
1810 }
1811 
1812 int
filename_from_ansi(const char * fn_in,char * fn_out)1813 filename_from_ansi (const char *fn_in, char *fn_out)
1814 {
1815   wchar_t fn_utf16[MAX_PATH];
1816   int codepage = codepage_for_filenames (NULL);
1817   int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
1818 				     -1, fn_utf16, MAX_PATH);
1819 
1820   if (!result)
1821     {
1822       DWORD err = GetLastError ();
1823 
1824       switch (err)
1825 	{
1826 	case ERROR_INVALID_FLAGS:
1827 	case ERROR_INVALID_PARAMETER:
1828 	  errno = EINVAL;
1829 	  break;
1830 	case ERROR_INSUFFICIENT_BUFFER:
1831 	case ERROR_NO_UNICODE_TRANSLATION:
1832 	default:
1833 	  errno = ENOENT;
1834 	  break;
1835 	}
1836       return -1;
1837     }
1838   return filename_from_utf16 (fn_utf16, fn_out);
1839 }
1840 
1841 
1842 
1843 /* The directory where we started, in UTF-8. */
1844 static char startup_dir[MAX_UTF8_PATH];
1845 
1846 /* Get the current working directory.  The caller must arrange for CWD
1847    to be allocated with enough space to hold a 260-char directory name
1848    in UTF-8.  IOW, the space should be at least MAX_UTF8_PATH bytes.  */
1849 static void
w32_get_current_directory(char * cwd)1850 w32_get_current_directory (char *cwd)
1851 {
1852   /* FIXME: Do we need to resolve possible symlinks in startup_dir?
1853      Does it matter anywhere in Emacs?  */
1854   if (w32_unicode_filenames)
1855     {
1856       wchar_t wstartup_dir[MAX_PATH];
1857 
1858       if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
1859 	emacs_abort ();
1860       filename_from_utf16 (wstartup_dir, cwd);
1861     }
1862   else
1863     {
1864       char astartup_dir[MAX_PATH];
1865 
1866       if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
1867 	emacs_abort ();
1868       filename_from_ansi (astartup_dir, cwd);
1869     }
1870 }
1871 
1872 /* For external callers.  Used by 'main' in emacs.c.  */
1873 void
w32_init_current_directory(void)1874 w32_init_current_directory (void)
1875 {
1876   w32_get_current_directory (startup_dir);
1877 }
1878 
1879 /* Return the original directory where Emacs started.  */
1880 char *
getcwd(char * dir,int dirsize)1881 getcwd (char *dir, int dirsize)
1882 {
1883   if (!dirsize)
1884     {
1885       errno = EINVAL;
1886       return NULL;
1887     }
1888   if (dirsize <= strlen (startup_dir))
1889     {
1890       errno = ERANGE;
1891       return NULL;
1892     }
1893 #if 0
1894   if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1895     return dir;
1896   return NULL;
1897 #else
1898   /* Emacs doesn't actually change directory itself, it stays in the
1899      same directory where it was started.  */
1900   strcpy (dir, startup_dir);
1901   return dir;
1902 #endif
1903 }
1904 
1905 /* Emulate getloadavg.  */
1906 
1907 struct load_sample {
1908   time_t sample_time;
1909   ULONGLONG idle;
1910   ULONGLONG kernel;
1911   ULONGLONG user;
1912 };
1913 
1914 /* Number of processors on this machine.  */
1915 static unsigned num_of_processors;
1916 
1917 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer.  */
1918 static struct load_sample samples[16*60];
1919 static int first_idx = -1, last_idx = -1;
1920 static int max_idx = ARRAYELTS (samples);
1921 
1922 static int
buf_next(int from)1923 buf_next (int from)
1924 {
1925   int next_idx = from + 1;
1926 
1927   if (next_idx >= max_idx)
1928     next_idx = 0;
1929 
1930   return next_idx;
1931 }
1932 
1933 static int
buf_prev(int from)1934 buf_prev (int from)
1935 {
1936   int prev_idx = from - 1;
1937 
1938   if (prev_idx < 0)
1939     prev_idx = max_idx - 1;
1940 
1941   return prev_idx;
1942 }
1943 
1944 static void
sample_system_load(ULONGLONG * idle,ULONGLONG * kernel,ULONGLONG * user)1945 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1946 {
1947   SYSTEM_INFO sysinfo;
1948   FILETIME ft_idle, ft_user, ft_kernel;
1949 
1950   /* Initialize the number of processors on this machine.  */
1951   if (num_of_processors <= 0)
1952     {
1953       get_native_system_info (&sysinfo);
1954       num_of_processors = sysinfo.dwNumberOfProcessors;
1955       if (num_of_processors <= 0)
1956 	{
1957 	  GetSystemInfo (&sysinfo);
1958 	  num_of_processors = sysinfo.dwNumberOfProcessors;
1959 	}
1960       if (num_of_processors <= 0)
1961 	num_of_processors = 1;
1962     }
1963 
1964   /* TODO: Take into account threads that are ready to run, by
1965      sampling the "\System\Processor Queue Length" performance
1966      counter.  The code below accounts only for threads that are
1967      actually running.  */
1968 
1969   if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1970     {
1971       ULARGE_INTEGER uidle, ukernel, uuser;
1972 
1973       memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1974       memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1975       memcpy (&uuser, &ft_user, sizeof (ft_user));
1976       *idle = uidle.QuadPart;
1977       *kernel = ukernel.QuadPart;
1978       *user = uuser.QuadPart;
1979     }
1980   else
1981     {
1982       *idle = 0;
1983       *kernel = 0;
1984       *user = 0;
1985     }
1986 }
1987 
1988 /* Produce the load average for a given time interval, using the
1989    samples in the samples[] array.  WHICH can be 0, 1, or 2, meaning
1990    1-minute, 5-minute, or 15-minute average, respectively. */
1991 static double
getavg(int which)1992 getavg (int which)
1993 {
1994   double retval = -1.0;
1995   double tdiff;
1996   int idx;
1997   double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1998   time_t now = samples[last_idx].sample_time;
1999 
2000   if (first_idx != last_idx)
2001     {
2002       for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
2003 	{
2004 	  tdiff = difftime (now, samples[idx].sample_time);
2005 	  if (tdiff >= span - 2*DBL_EPSILON*now)
2006 	    {
2007 	      long double sys =
2008 		samples[last_idx].kernel + samples[last_idx].user
2009 		- (samples[idx].kernel + samples[idx].user);
2010 	      long double idl = samples[last_idx].idle - samples[idx].idle;
2011 
2012 	      retval = (1.0 - idl / sys) * num_of_processors;
2013 	      break;
2014 	    }
2015 	  if (idx == first_idx)
2016 	    break;
2017 	}
2018     }
2019 
2020   return retval;
2021 }
2022 
2023 int
getloadavg(double loadavg[],int nelem)2024 getloadavg (double loadavg[], int nelem)
2025 {
2026   int elem;
2027   ULONGLONG idle, kernel, user;
2028   time_t now = time (NULL);
2029 
2030   /* If system time jumped back for some reason, delete all samples
2031      whose time is later than the current wall-clock time.  This
2032      prevents load average figures from becoming frozen for prolonged
2033      periods of time, when system time is reset backwards.  */
2034   if (last_idx >= 0)
2035     {
2036       while (difftime (now, samples[last_idx].sample_time) < -1.0)
2037 	{
2038 	  if (last_idx == first_idx)
2039 	    {
2040 	      first_idx = last_idx = -1;
2041 	      break;
2042 	    }
2043 	  last_idx = buf_prev (last_idx);
2044 	}
2045     }
2046 
2047   /* Store another sample.  We ignore samples that are less than 1 sec
2048      apart.  */
2049   if (last_idx < 0
2050       || (difftime (now, samples[last_idx].sample_time)
2051 	  >= 1.0 - 2*DBL_EPSILON*now))
2052     {
2053       sample_system_load (&idle, &kernel, &user);
2054       last_idx = buf_next (last_idx);
2055       samples[last_idx].sample_time = now;
2056       samples[last_idx].idle = idle;
2057       samples[last_idx].kernel = kernel;
2058       samples[last_idx].user = user;
2059       /* If the buffer has more that 15 min worth of samples, discard
2060 	 the old ones.  */
2061       if (first_idx == -1)
2062 	first_idx = last_idx;
2063       while (first_idx != last_idx
2064 	     && (difftime (now, samples[first_idx].sample_time)
2065 	         >= 15.0*60 + 2*DBL_EPSILON*now))
2066 	first_idx = buf_next (first_idx);
2067     }
2068 
2069   for (elem = 0; elem < nelem; elem++)
2070     {
2071       double avg = getavg (elem);
2072 
2073       if (avg < 0)
2074 	break;
2075       loadavg[elem] = avg;
2076     }
2077 
2078   /* Always return at least one element, otherwise load-average
2079      returns nil, and Lisp programs might decide we cannot measure
2080      system load.  For example, jit-lock-stealth-load's defcustom
2081      might decide that feature is "unsupported".  */
2082   if (elem == 0)
2083     loadavg[elem++] = 0.09;	/* < display-time-load-average-threshold */
2084 
2085   return elem;
2086 }
2087 
2088 /* Emulate getpwuid, getpwnam and others.  */
2089 
2090 #define PASSWD_FIELD_SIZE 256
2091 
2092 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
2093 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
2094 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
2095 static char dflt_passwd_dir[MAX_UTF8_PATH];
2096 static char dflt_passwd_shell[MAX_UTF8_PATH];
2097 
2098 static struct passwd dflt_passwd =
2099 {
2100   dflt_passwd_name,
2101   dflt_passwd_passwd,
2102   0,
2103   0,
2104   0,
2105   dflt_passwd_gecos,
2106   dflt_passwd_dir,
2107   dflt_passwd_shell,
2108 };
2109 
2110 static char dflt_group_name[GNLEN+1];
2111 
2112 static struct group dflt_group =
2113 {
2114   /* When group information is not available, we return this as the
2115      group for all files.  */
2116   dflt_group_name,
2117   0,
2118 };
2119 
2120 unsigned
getuid(void)2121 getuid (void)
2122 {
2123   return dflt_passwd.pw_uid;
2124 }
2125 
2126 unsigned
geteuid(void)2127 geteuid (void)
2128 {
2129   /* I could imagine arguing for checking to see whether the user is
2130      in the Administrators group and returning a UID of 0 for that
2131      case, but I don't know how wise that would be in the long run.  */
2132   return getuid ();
2133 }
2134 
2135 unsigned
getgid(void)2136 getgid (void)
2137 {
2138   return dflt_passwd.pw_gid;
2139 }
2140 
2141 unsigned
getegid(void)2142 getegid (void)
2143 {
2144   return getgid ();
2145 }
2146 
2147 struct passwd *
getpwuid(unsigned uid)2148 getpwuid (unsigned uid)
2149 {
2150   if (uid == dflt_passwd.pw_uid)
2151     return &dflt_passwd;
2152   return NULL;
2153 }
2154 
2155 struct group *
getgrgid(gid_t gid)2156 getgrgid (gid_t gid)
2157 {
2158   if (gid == dflt_passwd.pw_gid)
2159     return &dflt_group;
2160   return NULL;
2161 }
2162 
2163 struct passwd *
getpwnam(char * name)2164 getpwnam (char *name)
2165 {
2166   struct passwd *pw;
2167 
2168   pw = getpwuid (getuid ());
2169   if (!pw)
2170     return pw;
2171 
2172   if (xstrcasecmp (name, pw->pw_name))
2173     {
2174       /* Mimic what init_editfns does with these environment
2175 	 variables, so that the likes of ~USER is recognized by
2176 	 expand-file-name even if $LOGNAME gives a name different from
2177 	 the real username produced by the process token.  */
2178       char *logname = getenv ("LOGNAME");
2179       char *username = getenv ("USERNAME");
2180       if ((logname || username)
2181 	  && xstrcasecmp (name, logname ? logname : username) == 0)
2182 	{
2183 	  static struct passwd alias_user;
2184 	  static char alias_name[PASSWD_FIELD_SIZE];
2185 
2186 	  memcpy (&alias_user, &dflt_passwd, sizeof dflt_passwd);
2187 	  alias_name[0] = '\0';
2188 	  strncat (alias_name, logname ? logname : username,
2189 		   PASSWD_FIELD_SIZE - 1);
2190 	  alias_user.pw_name = alias_name;
2191 	  pw = &alias_user;
2192 	}
2193       else
2194 	return NULL;
2195     }
2196 
2197   return pw;
2198 }
2199 
2200 static void
init_user_info(void)2201 init_user_info (void)
2202 {
2203   /* Find the user's real name by opening the process token and
2204      looking up the name associated with the user-sid in that token.
2205 
2206      Use the relative portion of the identifier authority value from
2207      the user-sid as the user id value (same for group id using the
2208      primary group sid from the process token). */
2209 
2210   char         uname[UNLEN+1], gname[GNLEN+1], domain[1025];
2211   DWORD        ulength = sizeof (uname), dlength = sizeof (domain), needed;
2212   DWORD	       glength = sizeof (gname);
2213   HANDLE       token = NULL;
2214   SID_NAME_USE user_type;
2215   unsigned char *buf = NULL;
2216   DWORD        blen = 0;
2217   TOKEN_USER   user_token;
2218   TOKEN_PRIMARY_GROUP group_token;
2219   BOOL         result;
2220 
2221   result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
2222   if (result)
2223     {
2224       result = get_token_information (token, TokenUser, NULL, 0, &blen);
2225       if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2226 	{
2227 	  buf = xmalloc (blen);
2228 	  result = get_token_information (token, TokenUser,
2229 					  (LPVOID)buf, blen, &needed);
2230 	  if (result)
2231 	    {
2232 	      memcpy (&user_token, buf, sizeof (user_token));
2233 	      result = lookup_account_sid (NULL, user_token.User.Sid,
2234 					   uname, &ulength,
2235 					   domain, &dlength, &user_type);
2236 	    }
2237 	}
2238       else
2239 	result = FALSE;
2240     }
2241   if (result)
2242     {
2243       strcpy (dflt_passwd.pw_name, uname);
2244       /* Determine a reasonable uid value.  */
2245       if (xstrcasecmp ("administrator", uname) == 0)
2246 	{
2247 	  dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
2248 	  dflt_passwd.pw_gid = 513; /* well-known None gid */
2249 	}
2250       else
2251 	{
2252 	  /* Use the last sub-authority value of the RID, the relative
2253 	     portion of the SID, as user/group ID. */
2254 	  dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
2255 
2256 	  /* Get group id and name.  */
2257 	  result = get_token_information (token, TokenPrimaryGroup,
2258 					  (LPVOID)buf, blen, &needed);
2259 	  if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2260 	    {
2261 	      buf = xrealloc (buf, blen = needed);
2262 	      result = get_token_information (token, TokenPrimaryGroup,
2263 					      (LPVOID)buf, blen, &needed);
2264 	    }
2265 	  if (result)
2266 	    {
2267 	      memcpy (&group_token, buf, sizeof (group_token));
2268 	      dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
2269 	      dlength = sizeof (domain);
2270 	      /* If we can get at the real Primary Group name, use that.
2271 		 Otherwise, the default group name was already set to
2272 		 "None" in globals_of_w32.  */
2273 	      if (lookup_account_sid (NULL, group_token.PrimaryGroup,
2274 				      gname, &glength, NULL, &dlength,
2275 				      &user_type))
2276 		strcpy (dflt_group_name, gname);
2277 	    }
2278 	  else
2279 	    dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2280 	}
2281     }
2282   /* If security calls are not supported (presumably because we
2283      are running under Windows 9X), fallback to this: */
2284   else if (GetUserName (uname, &ulength))
2285     {
2286       strcpy (dflt_passwd.pw_name, uname);
2287       if (xstrcasecmp ("administrator", uname) == 0)
2288 	dflt_passwd.pw_uid = 0;
2289       else
2290 	dflt_passwd.pw_uid = 123;
2291       dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2292     }
2293   else
2294     {
2295       strcpy (dflt_passwd.pw_name, "unknown");
2296       dflt_passwd.pw_uid = 123;
2297       dflt_passwd.pw_gid = 123;
2298     }
2299   dflt_group.gr_gid = dflt_passwd.pw_gid;
2300 
2301   /* Set dir and shell from environment variables. */
2302   if (w32_unicode_filenames)
2303     {
2304       wchar_t *home = _wgetenv (L"HOME");
2305       wchar_t *shell = _wgetenv (L"SHELL");
2306 
2307       /* Ensure HOME and SHELL are defined. */
2308       if (home == NULL)
2309 	emacs_abort ();
2310       if (shell == NULL)
2311 	emacs_abort ();
2312       filename_from_utf16 (home, dflt_passwd.pw_dir);
2313       filename_from_utf16 (shell, dflt_passwd.pw_shell);
2314     }
2315   else
2316     {
2317       char *home = getenv ("HOME");
2318       char *shell = getenv ("SHELL");
2319 
2320       if (home == NULL)
2321 	emacs_abort ();
2322       if (shell == NULL)
2323 	emacs_abort ();
2324       filename_from_ansi (home, dflt_passwd.pw_dir);
2325       filename_from_ansi (shell, dflt_passwd.pw_shell);
2326     }
2327 
2328   xfree (buf);
2329   if (token)
2330     CloseHandle (token);
2331 }
2332 
2333 static HCRYPTPROV w32_crypto_hprov;
2334 static int
w32_init_crypt_random(void)2335 w32_init_crypt_random (void)
2336 {
2337   if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL,
2338 			    CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2339     {
2340       DebPrint (("CryptAcquireContext failed with error %x\n",
2341 		 GetLastError ()));
2342       w32_crypto_hprov = 0;
2343       return -1;
2344     }
2345   return 0;
2346 }
2347 
2348 int
w32_init_random(void * buf,ptrdiff_t buflen)2349 w32_init_random (void *buf, ptrdiff_t buflen)
2350 {
2351   if (!w32_crypto_hprov)
2352     w32_init_crypt_random ();
2353   if (w32_crypto_hprov)
2354     {
2355       if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf))
2356 	return 0;
2357     }
2358   return -1;
2359 }
2360 
2361 /* MS-Windows 'rand' produces separate identical series for each
2362    thread, so we replace it with our version.  */
2363 
2364 /* Algorithm AS183: An Efficient and Portable Pseudo-random Number
2365    Generator, by B.A. Wichmann, I.D. Hill.  AS, v31, No. 2 (1982).  */
2366 static int ix = 3172, iy = 9814, iz = 20125;
2367 #define RAND_MAX_X  30269
2368 #define RAND_MAX_Y  30307
2369 #define RAND_MAX_Z  30323
2370 
2371 static int
rand_as183(void)2372 rand_as183 (void)
2373 {
2374   ix = (171 * ix) % RAND_MAX_X;
2375   iy = (172 * iy) % RAND_MAX_Y;
2376   iz = (170 * iz) % RAND_MAX_Z;
2377 
2378   return (ix + iy + iz) & 0x7fff;
2379 }
2380 
2381 int
random(void)2382 random (void)
2383 {
2384   /* rand_as183 () gives us 15 random bits...hack together 30 bits.  */
2385   return ((rand_as183 () << 15) | rand_as183 ());
2386 }
2387 
2388 void
srandom(int seed)2389 srandom (int seed)
2390 {
2391   srand (seed);
2392   ix = rand () % RAND_MAX_X;
2393   iy = rand () % RAND_MAX_Y;
2394   iz = rand () % RAND_MAX_Z;
2395 }
2396 
2397 /* Return the maximum length in bytes of a multibyte character
2398    sequence encoded in the current ANSI codepage.  This is required to
2399    correctly walk the encoded file names one character at a time.  */
2400 static int
max_filename_mbslen(void)2401 max_filename_mbslen (void)
2402 {
2403   CPINFO cp_info;
2404 
2405   codepage_for_filenames (&cp_info);
2406   return cp_info.MaxCharSize;
2407 }
2408 
2409 /* Normalize filename by converting in-place all of its path
2410    separators to the separator specified by PATH_SEP.  */
2411 
2412 static void
normalize_filename(register char * fp,char path_sep)2413 normalize_filename (register char *fp, char path_sep)
2414 {
2415   char *p2;
2416 
2417   /* Always lower-case drive letters a-z, even if the filesystem
2418      preserves case in filenames.
2419      This is so filenames can be compared by string comparison
2420      functions that are case-sensitive.  Even case-preserving filesystems
2421      do not distinguish case in drive letters.  */
2422   p2 = fp + 1;
2423 
2424   if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2425     {
2426       *fp += 'a' - 'A';
2427       fp += 2;
2428     }
2429 
2430   while (*fp)
2431     {
2432       if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2433 	*fp = path_sep;
2434       fp++;
2435     }
2436 }
2437 
2438 /* Destructively turn backslashes into slashes.  */
2439 void
dostounix_filename(register char * p)2440 dostounix_filename (register char *p)
2441 {
2442   normalize_filename (p, '/');
2443 }
2444 
2445 /* Destructively turn slashes into backslashes.  */
2446 void
unixtodos_filename(register char * p)2447 unixtodos_filename (register char *p)
2448 {
2449   normalize_filename (p, '\\');
2450 }
2451 
2452 /* Remove all CR's that are followed by a LF.
2453    (From msdos.c...probably should figure out a way to share it,
2454    although this code isn't going to ever change.)  */
2455 static int
crlf_to_lf(register int n,register char * buf)2456 crlf_to_lf (register int n, register char *buf)
2457 {
2458   unsigned char *np = (unsigned char *)buf;
2459   unsigned char *startp = np;
2460   char *endp = buf + n;
2461 
2462   if (n == 0)
2463     return n;
2464   while (buf < endp - 1)
2465     {
2466       if (*buf == 0x0d)
2467 	{
2468 	  if (*(++buf) != 0x0a)
2469 	    *np++ = 0x0d;
2470 	}
2471       else
2472 	*np++ = *buf++;
2473     }
2474   if (buf < endp)
2475     *np++ = *buf++;
2476   return np - startp;
2477 }
2478 
2479 /* Parse the root part of file name, if present.  Return length and
2480     optionally store pointer to char after root.  */
2481 static int
parse_root(const char * name,const char ** pPath)2482 parse_root (const char * name, const char ** pPath)
2483 {
2484   const char * start = name;
2485 
2486   if (name == NULL)
2487     return 0;
2488 
2489   /* find the root name of the volume if given */
2490   if (isalpha (name[0]) && name[1] == ':')
2491     {
2492       /* skip past drive specifier */
2493       name += 2;
2494       if (IS_DIRECTORY_SEP (name[0]))
2495 	name++;
2496     }
2497   else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2498     {
2499       int slashes = 2;
2500 
2501       name += 2;
2502       do
2503         {
2504 	  if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2505 	    break;
2506 	  name++;
2507 	}
2508       while ( *name );
2509       if (IS_DIRECTORY_SEP (name[0]))
2510 	name++;
2511     }
2512 
2513   if (pPath)
2514     *pPath = name;
2515 
2516   return name - start;
2517 }
2518 
2519 /* Get long base name for name; name is assumed to be absolute.  */
2520 static int
get_long_basename(char * name,char * buf,int size)2521 get_long_basename (char * name, char * buf, int size)
2522 {
2523   HANDLE dir_handle = INVALID_HANDLE_VALUE;
2524   char fname_utf8[MAX_UTF8_PATH];
2525   int len = 0;
2526   int cstatus = -1;
2527 
2528   /* Must be valid filename, no wild cards or other invalid characters.  */
2529   if (strpbrk (name, "*?|<>\""))
2530     return 0;
2531 
2532   if (w32_unicode_filenames)
2533     {
2534       wchar_t fname_utf16[MAX_PATH];
2535       WIN32_FIND_DATAW find_data_wide;
2536 
2537       filename_to_utf16 (name, fname_utf16);
2538       dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2539       if (dir_handle != INVALID_HANDLE_VALUE)
2540 	cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2541     }
2542   else
2543     {
2544       char fname_ansi[MAX_PATH];
2545       WIN32_FIND_DATAA find_data_ansi;
2546 
2547       filename_to_ansi (name, fname_ansi);
2548       /* If the ANSI name includes ? characters, it is not encodable
2549 	 in the ANSI codepage.  In that case, we deliver the question
2550 	 marks to the caller; calling FindFirstFileA in this case
2551 	 could return some unrelated file name in the same
2552 	 directory.  */
2553       if (_mbspbrk (fname_ansi, "?"))
2554 	{
2555 	  /* Find the basename of fname_ansi.  */
2556 	  char *p = strrchr (fname_ansi, '\\');
2557 
2558 	  if (!p)
2559 	    p = fname_ansi;
2560 	  else
2561 	    p++;
2562 	  cstatus = filename_from_ansi (p, fname_utf8);
2563 	}
2564       else
2565 	{
2566 	  dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2567 	  if (dir_handle != INVALID_HANDLE_VALUE)
2568 	    cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2569 	}
2570     }
2571 
2572   if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2573     memcpy (buf, fname_utf8, len + 1);
2574   else
2575     len = 0;
2576 
2577   if (dir_handle != INVALID_HANDLE_VALUE)
2578     FindClose (dir_handle);
2579 
2580   return len;
2581 }
2582 
2583 /* Get long name for file, if possible (assumed to be absolute).  */
2584 BOOL
w32_get_long_filename(const char * name,char * buf,int size)2585 w32_get_long_filename (const char * name, char * buf, int size)
2586 {
2587   char * o = buf;
2588   char * p;
2589   const char * q;
2590   char full[ MAX_UTF8_PATH ];
2591   int len;
2592 
2593   len = strlen (name);
2594   if (len >= MAX_UTF8_PATH)
2595     return FALSE;
2596 
2597   /* Use local copy for destructive modification.  */
2598   memcpy (full, name, len+1);
2599   unixtodos_filename (full);
2600 
2601   /* Copy root part verbatim.  */
2602   len = parse_root (full, (const char **)&p);
2603   memcpy (o, full, len);
2604   o += len;
2605   *o = '\0';
2606   size -= len;
2607 
2608   while (p != NULL && *p)
2609     {
2610       q = p;
2611       p = strchr (q, '\\');
2612       if (p) *p = '\0';
2613       len = get_long_basename (full, o, size);
2614       if (len > 0)
2615 	{
2616 	  o += len;
2617 	  size -= len;
2618 	  if (p != NULL)
2619 	    {
2620 	      *p++ = '\\';
2621 	      if (size < 2)
2622 		return FALSE;
2623 	      *o++ = '\\';
2624 	      size--;
2625 	      *o = '\0';
2626 	    }
2627 	}
2628       else
2629 	return FALSE;
2630     }
2631 
2632   return TRUE;
2633 }
2634 
2635 unsigned int
w32_get_short_filename(const char * name,char * buf,int size)2636 w32_get_short_filename (const char * name, char * buf, int size)
2637 {
2638   if (w32_unicode_filenames)
2639     {
2640       wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2641       unsigned int retval;
2642 
2643       filename_to_utf16 (name, name_utf16);
2644       retval = GetShortPathNameW (name_utf16, short_name, size);
2645       if (retval && retval < size)
2646 	filename_from_utf16 (short_name, buf);
2647       return retval;
2648     }
2649   else
2650     {
2651       char name_ansi[MAX_PATH];
2652 
2653       filename_to_ansi (name, name_ansi);
2654       return GetShortPathNameA (name_ansi, buf, size);
2655     }
2656 }
2657 
2658 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2659    MS-Windows ANSI codepage.  If FILENAME includes characters not
2660    supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2661    if it exists.  This is needed because the w32 build wants to
2662    support file names outside of the system locale, but image
2663    libraries typically don't support wide (a.k.a. "Unicode") APIs
2664    required for that.  */
2665 
2666 Lisp_Object
ansi_encode_filename(Lisp_Object filename)2667 ansi_encode_filename (Lisp_Object filename)
2668 {
2669   Lisp_Object encoded_filename;
2670   char fname[MAX_PATH];
2671 
2672   filename_to_ansi (SSDATA (filename), fname);
2673   if (_mbspbrk (fname, "?"))
2674     {
2675       char shortname[MAX_PATH];
2676 
2677       if (w32_get_short_filename (SSDATA (filename), shortname, MAX_PATH))
2678 	{
2679 	  dostounix_filename (shortname);
2680 	  encoded_filename = build_string (shortname);
2681 	}
2682       else
2683 	encoded_filename = build_unibyte_string (fname);
2684     }
2685   else
2686     encoded_filename = build_unibyte_string (fname);
2687   return encoded_filename;
2688 }
2689 
2690 static int
is_unc_volume(const char * filename)2691 is_unc_volume (const char *filename)
2692 {
2693   const char *ptr = filename;
2694 
2695   if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2696     return 0;
2697 
2698   if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2699     return 0;
2700 
2701   return 1;
2702 }
2703 
2704 /* Emulate the Posix unsetenv.  */
2705 int
unsetenv(const char * name)2706 unsetenv (const char *name)
2707 {
2708   char *var;
2709   size_t name_len;
2710 
2711   if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2712     {
2713       errno = EINVAL;
2714       return -1;
2715     }
2716   name_len = strlen (name);
2717   /* MS docs says an environment variable cannot be longer than 32K.  */
2718   if (name_len > 32767)
2719     {
2720       errno = ENOMEM;
2721       return 0;
2722     }
2723   /* It is safe to use 'alloca' with 32K size, since the stack is at
2724      least 2MB, and we set it to 8MB in the link command line.  */
2725   var = alloca (name_len + 2);
2726   memcpy (var, name, name_len);
2727   var[name_len++] = '=';
2728   var[name_len] = '\0';
2729   return _putenv (var);
2730 }
2731 
2732 /* MS _putenv doesn't support removing a variable when the argument
2733    does not include the '=' character, so we fix that here.  */
2734 int
sys_putenv(char * str)2735 sys_putenv (char *str)
2736 {
2737   const char *const name_end = strchr (str, '=');
2738 
2739   if (name_end == NULL)
2740     {
2741       /* Remove the variable from the environment.  */
2742       return unsetenv (str);
2743     }
2744 
2745   if (strncmp (str, "TZ=<", 4) == 0)
2746     {
2747       /* MS-Windows does not support POSIX.1-2001 angle-bracket TZ
2748 	 abbreviation syntax.  Convert to POSIX.1-1988 syntax if possible,
2749 	 and to the undocumented placeholder "ZZZ" otherwise.  */
2750       bool supported_abbr = true;
2751       for (char *p = str + 4; *p; p++)
2752 	{
2753 	  if (('0' <= *p && *p <= '9') || *p == '-' || *p == '+')
2754 	    supported_abbr = false;
2755 	  else if (*p == '>')
2756 	    {
2757 	      ptrdiff_t abbrlen;
2758 	      if (supported_abbr)
2759 		{
2760 		  abbrlen = p - (str + 4);
2761 		  memmove (str + 3, str + 4, abbrlen);
2762 		}
2763 	      else
2764 		{
2765 		  abbrlen = 3;
2766 		  memset (str + 3, 'Z', abbrlen);
2767 		}
2768 	      memmove (str + 3 + abbrlen, p + 1, strlen (p));
2769 	      break;
2770 	    }
2771 	}
2772     }
2773 
2774   return _putenv (str);
2775 }
2776 
2777 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2778 
2779 LPBYTE
w32_get_resource(const char * key,LPDWORD lpdwtype)2780 w32_get_resource (const char *key, LPDWORD lpdwtype)
2781 {
2782   LPBYTE lpvalue;
2783   HKEY hrootkey = NULL;
2784   DWORD cbData;
2785 
2786   /* Check both the current user and the local machine to see if
2787      we have any resources.  */
2788 
2789   if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2790     {
2791       lpvalue = NULL;
2792 
2793       if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2794 	  && (lpvalue = xmalloc (cbData)) != NULL
2795 	  && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2796 	{
2797           RegCloseKey (hrootkey);
2798 	  return (lpvalue);
2799 	}
2800 
2801       xfree (lpvalue);
2802 
2803       RegCloseKey (hrootkey);
2804     }
2805 
2806   if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2807     {
2808       lpvalue = NULL;
2809 
2810       if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2811 	  && (lpvalue = xmalloc (cbData)) != NULL
2812 	  && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2813 	{
2814           RegCloseKey (hrootkey);
2815 	  return (lpvalue);
2816 	}
2817 
2818       xfree (lpvalue);
2819 
2820       RegCloseKey (hrootkey);
2821     }
2822 
2823   return (NULL);
2824 }
2825 
2826 /* The argv[] array holds ANSI-encoded strings, and so this function
2827    works with ANS_encoded strings.  */
2828 void
init_environment(char ** argv)2829 init_environment (char ** argv)
2830 {
2831   static const char * const tempdirs[] = {
2832     "$TMPDIR", "$TEMP", "$TMP", "c:/"
2833   };
2834 
2835   int i;
2836 
2837   const int imax = ARRAYELTS (tempdirs);
2838 
2839   /* Implementation note: This function explicitly works with ANSI
2840      file names, not with UTF-8 encoded file names.  This is because
2841      this function pushes variables into the Emacs's environment, and
2842      the environment variables are always assumed to be in the
2843      locale-specific encoding.  Do NOT call any functions that accept
2844      UTF-8 file names from this function!  */
2845 
2846   /* Make sure they have a usable $TMPDIR.  Many Emacs functions use
2847      temporary files and assume "/tmp" if $TMPDIR is unset, which
2848      will break on DOS/Windows.  Refuse to work if we cannot find
2849      a directory, not even "c:/", usable for that purpose.  */
2850   for (i = 0; i < imax ; i++)
2851     {
2852       const char *tmp = tempdirs[i];
2853 
2854       if (*tmp == '$')
2855 	tmp = getenv (tmp + 1);
2856       /* Note that `access' can lie to us if the directory resides on a
2857 	 read-only filesystem, like CD-ROM or a write-protected floppy.
2858 	 The only way to be really sure is to actually create a file and
2859 	 see if it succeeds.  But I think that's too much to ask.  */
2860 
2861       /* MSVCRT's _access crashes with D_OK, so we use our replacement.  */
2862       if (tmp && sys_access (tmp, D_OK) == 0)
2863 	{
2864 	  char * var = alloca (strlen (tmp) + 8);
2865 	  sprintf (var, "TMPDIR=%s", tmp);
2866 	  _putenv (strdup (var));
2867 	  break;
2868 	}
2869     }
2870   if (i >= imax)
2871     cmd_error_internal
2872       (Fcons (Qerror,
2873 	      Fcons (build_string ("no usable temporary directories found!!"),
2874 		     Qnil)),
2875        "While setting TMPDIR: ");
2876 
2877   /* Check for environment variables and use registry settings if they
2878      don't exist.  Fallback on default values where applicable.  */
2879   {
2880     int i;
2881     LPBYTE lpval;
2882     DWORD dwType;
2883     char locale_name[32];
2884     char default_home[MAX_PATH];
2885     int appdata = 0;
2886 
2887     static const struct env_entry
2888     {
2889       const char * name;
2890       const char * def_value;
2891     } dflt_envvars[] =
2892     {
2893       /* If the default value is NULL, we will use the value from the
2894 	 outside environment or the Registry, but will not push the
2895 	 variable into the Emacs environment if it is defined neither
2896 	 in the Registry nor in the outside environment.  */
2897       {"HOME", "C:/"},
2898       {"PRELOAD_WINSOCK", NULL},
2899       {"emacs_dir", "C:/emacs"},
2900       {"EMACSLOADPATH", NULL},
2901       {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2902       {"EMACSDATA", NULL},
2903       {"EMACSPATH", NULL},
2904       {"INFOPATH", NULL},
2905       {"EMACSDOC", NULL},
2906       {"TERM", "cmd"},
2907       {"LANG", NULL},
2908     };
2909 
2910 #define N_ENV_VARS ARRAYELTS (dflt_envvars)
2911 
2912     /* We need to copy dflt_envvars[] and work on the copy because we
2913        don't want the dumped Emacs to inherit the values of
2914        environment variables we saw during dumping (which could be on
2915        a different system).  The defaults above must be left intact.  */
2916     struct env_entry env_vars[N_ENV_VARS];
2917 
2918     for (i = 0; i < N_ENV_VARS; i++)
2919       env_vars[i] = dflt_envvars[i];
2920 
2921     /* For backwards compatibility, check if a .emacs file exists in C:/
2922        If not, then we can try to default to the appdata directory under the
2923        user's profile, which is more likely to be writable.   */
2924     if (sys_access ("C:/.emacs", F_OK) != 0)
2925       {
2926 	HRESULT profile_result;
2927 	/* Dynamically load ShGetFolderPath, as it won't exist on versions
2928 	   of Windows 95 and NT4 that have not been updated to include
2929 	   MSIE 5.  */
2930 	ShGetFolderPath_fn get_folder_path;
2931 	get_folder_path = (ShGetFolderPath_fn)
2932 	  get_proc_addr (GetModuleHandle ("shell32.dll"),
2933                                 "SHGetFolderPathA");
2934 
2935 	if (get_folder_path != NULL)
2936 	  {
2937 	    profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2938 					      0, default_home);
2939 
2940 	    /* If we can't get the appdata dir, revert to old behavior.	 */
2941 	    if (profile_result == S_OK)
2942 	      {
2943 		env_vars[0].def_value = default_home;
2944 		appdata = 1;
2945 	      }
2946 	  }
2947       }
2948 
2949   /* Get default locale info and use it for LANG.  */
2950   if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2951                      LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2952                      locale_name, sizeof (locale_name)))
2953     {
2954       /* Microsoft are migrating away of locale IDs, replacing them
2955 	 with locale names, such as "en-US", and are therefore
2956 	 deprecating the APIs which use LCID etc.  As part of that
2957 	 deprecation, they don't bother inventing LCID and LANGID
2958 	 codes for new locales and language/culture combinations;
2959 	 instead, those get LCID of 0xC000 and LANGID of 0x2000, for
2960 	 which the LCID/LANGID oriented APIs return "ZZZ" as the
2961 	 "language name".  Such "language name" is useless for our
2962 	 purposes.  So we instead use the default UI language, in the
2963 	 hope of getting something usable.  */
2964       if (strcmp (locale_name, "ZZZ") == 0)
2965 	{
2966 	  LANGID lang_id = get_user_default_ui_language ();
2967 
2968 	  if (lang_id != 0)
2969 	    {
2970 	      /* Disregard the sorting order differences between cultures.  */
2971 	      LCID def_lcid = MAKELCID (lang_id, SORT_DEFAULT);
2972 	      char locale_name_def[32];
2973 
2974 	      if (GetLocaleInfo (def_lcid,
2975 				 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2976 				 locale_name_def, sizeof (locale_name_def)))
2977 		strcpy (locale_name, locale_name_def);
2978 	    }
2979 	}
2980       for (i = 0; i < N_ENV_VARS; i++)
2981         {
2982           if (strcmp (env_vars[i].name, "LANG") == 0)
2983             {
2984               env_vars[i].def_value = locale_name;
2985               break;
2986             }
2987         }
2988     }
2989 
2990 #define SET_ENV_BUF_SIZE (4 * MAX_PATH)	/* to cover EMACSLOADPATH */
2991 
2992     /* Treat emacs_dir specially: set it unconditionally based on our
2993        location.  */
2994     {
2995       char *p;
2996       char modname[MAX_PATH];
2997 
2998       if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2999 	emacs_abort ();
3000       if ((p = _mbsrchr (modname, '\\')) == NULL)
3001 	emacs_abort ();
3002       *p = 0;
3003 
3004       if ((p = _mbsrchr (modname, '\\'))
3005 	  /* From bin means installed Emacs, from src means uninstalled.  */
3006 	  && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
3007 	{
3008 	  char buf[SET_ENV_BUF_SIZE];
3009 	  int within_build_tree = xstrcasecmp (p, "\\src") == 0;
3010 
3011 	  *p = 0;
3012 	  for (p = modname; *p; p = CharNext (p))
3013 	    if (*p == '\\') *p = '/';
3014 
3015 	  _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
3016 	  _putenv (strdup (buf));
3017 	  /* If we are running from the Posix-like build tree, define
3018 	     SHELL to point to our own cmdproxy.  The loop below will
3019 	     then disregard PATH_EXEC and the default value.  */
3020 	  if (within_build_tree)
3021 	    {
3022 	      _snprintf (buf, sizeof (buf) - 1,
3023 			 "SHELL=%s/nt/cmdproxy.exe", modname);
3024 	      _putenv (strdup (buf));
3025 	    }
3026 	}
3027     }
3028 
3029     for (i = 0; i < N_ENV_VARS; i++)
3030       {
3031 	if (!getenv (env_vars[i].name))
3032 	  {
3033 	    int dont_free = 0;
3034 	    char bufc[SET_ENV_BUF_SIZE];
3035 
3036 	    if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
3037 		/* Also ignore empty environment variables.  */
3038 		|| *lpval == 0)
3039 	      {
3040 		xfree (lpval);
3041 		dont_free = 1;
3042 		if (strcmp (env_vars[i].name, "SHELL") == 0)
3043 		  {
3044 		    /* Look for cmdproxy.exe in every directory in
3045 		       PATH_EXEC.  FIXME: This does not find cmdproxy
3046 		       in nt/ when we run uninstalled.  */
3047 		    char fname[MAX_PATH];
3048 		    const char *pstart = PATH_EXEC, *pend;
3049 
3050 		    do {
3051 		      pend = _mbschr (pstart, ';');
3052 		      if (!pend)
3053 			pend = pstart + strlen (pstart);
3054 		      /* Be defensive against series of ;;; characters.  */
3055 		      if (pend > pstart)
3056 			{
3057 			  strncpy (fname, pstart, pend - pstart);
3058 			  fname[pend - pstart] = '/';
3059 			  strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
3060 			  ExpandEnvironmentStrings ((LPSTR) fname, bufc,
3061 						    sizeof (bufc));
3062 			  if (sys_access (bufc, F_OK) == 0)
3063 			    {
3064 			      lpval = bufc;
3065 			      dwType = REG_SZ;
3066 			      break;
3067 			    }
3068 			}
3069 		      if (*pend)
3070 			pstart = pend + 1;
3071 		      else
3072 			pstart = pend;
3073 		      if (!*pstart)
3074 			{
3075 			  /* If not found in any directory, use the
3076 			     default as the last resort.  */
3077 			  lpval = (char *)env_vars[i].def_value;
3078 			  dwType = REG_EXPAND_SZ;
3079 			}
3080 		    } while (*pstart);
3081 		  }
3082 		else
3083 		  {
3084 		    lpval = (char *)env_vars[i].def_value;
3085 		    dwType = REG_EXPAND_SZ;
3086 		  }
3087 		if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
3088 		  Vdelayed_warnings_list
3089                     = Fcons
3090 		    (list2 (intern ("initialization"), build_string
3091                             ("Use of `C:\\.emacs' without defining `HOME'\n"
3092                              "in the environment is deprecated, "
3093                              "see `Windows HOME' in the Emacs manual.")),
3094                      Vdelayed_warnings_list);
3095 	      }
3096 
3097 	    if (lpval)
3098 	      {
3099 		char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
3100 
3101 		if (dwType == REG_EXPAND_SZ)
3102 		  ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
3103 		else if (dwType == REG_SZ)
3104 		  strcpy (buf1, (char *)lpval);
3105 		if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
3106 		  {
3107 		    _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
3108 			       buf1);
3109 		    _putenv (strdup (buf2));
3110 		  }
3111 
3112 		if (!dont_free)
3113 		  xfree (lpval);
3114 	      }
3115 	  }
3116       }
3117   }
3118 
3119   /* Rebuild system configuration to reflect invoking system.  */
3120   Vsystem_configuration = build_string (EMACS_CONFIGURATION);
3121 
3122   /* Another special case: on NT, the PATH variable is actually named
3123      "Path" although cmd.exe (perhaps NT itself) arranges for
3124      environment variable lookup and setting to be case insensitive.
3125      However, Emacs assumes a fully case sensitive environment, so we
3126      need to change "Path" to "PATH" to match the expectations of
3127      various elisp packages.  We do this by the sneaky method of
3128      modifying the string in the C runtime environ entry.
3129 
3130      The same applies to COMSPEC.  */
3131   {
3132     char ** envp;
3133     const char *path = "PATH=";
3134     int path_len = strlen (path);
3135     const char *comspec = "COMSPEC=";
3136     int comspec_len = strlen (comspec);
3137 
3138     for (envp = environ; *envp; envp++)
3139       if (_strnicmp (*envp, path, path_len) == 0)
3140         memcpy (*envp, path, path_len);
3141       else if (_strnicmp (*envp, comspec, comspec_len) == 0)
3142         memcpy (*envp, comspec, comspec_len);
3143 
3144     /* Make the same modification to `process-environment' which has
3145        already been initialized in set_initial_environment.  */
3146     for (Lisp_Object env = Vprocess_environment; CONSP (env); env = XCDR (env))
3147     {
3148       Lisp_Object entry = XCAR (env);
3149       if (_strnicmp (SDATA (entry), path, path_len) == 0)
3150         for (int i = 0; i < path_len; i++)
3151           SSET (entry, i, path[i]);
3152       else if (_strnicmp (SDATA (entry), comspec, comspec_len) == 0)
3153         for (int i = 0; i < comspec_len; i++)
3154           SSET (entry, i, comspec[i]);
3155     }
3156   }
3157 
3158   /* Remember the initial working directory for getcwd.  */
3159   w32_get_current_directory (startup_dir);
3160 
3161   {
3162     static char modname[MAX_PATH];
3163 
3164     if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
3165       emacs_abort ();
3166     argv[0] = modname;
3167   }
3168 
3169   /* Determine if there is a middle mouse button, to allow parse_button
3170      to decide whether right mouse events should be mouse-2 or
3171      mouse-3. */
3172   w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
3173 
3174   init_user_info ();
3175 }
3176 
3177 /* Called from expand-file-name when default-directory is not a string.  */
3178 
3179 char *
emacs_root_dir(void)3180 emacs_root_dir (void)
3181 {
3182   static char root_dir[MAX_UTF8_PATH];
3183   const char *p;
3184 
3185   p = getenv ("emacs_dir");
3186   if (p == NULL)
3187     emacs_abort ();
3188   filename_from_ansi (p, root_dir);
3189   root_dir[parse_root (root_dir, NULL)] = '\0';
3190   dostounix_filename (root_dir);
3191   return root_dir;
3192 }
3193 
3194 /* Emulate fdutimens.  */
3195 
3196 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
3197    TIMESPEC[0] and TIMESPEC[1], respectively.
3198    FD must be either negative -- in which case it is ignored --
3199    or a file descriptor that is open on FILE.
3200    If FD is nonnegative, then FILE can be NULL, which means
3201    use just futimes instead of utimes.
3202    If TIMESPEC is null, FAIL.
3203    Return 0 on success, -1 (setting errno) on failure.  */
3204 
3205 int
fdutimens(int fd,char const * file,struct timespec const timespec[2])3206 fdutimens (int fd, char const *file, struct timespec const timespec[2])
3207 {
3208   if (!timespec)
3209     {
3210       errno = ENOSYS;
3211       return -1;
3212     }
3213   if (fd < 0 && !file)
3214     {
3215       errno = EBADF;
3216       return -1;
3217     }
3218   /* _futime's prototype defines 2nd arg as having the type 'struct
3219      _utimbuf', while utime needs to accept 'struct utimbuf' for
3220      compatibility with Posix.  So we need to use 2 different (but
3221      equivalent) types to avoid compiler warnings, sigh.  */
3222   if (fd >= 0)
3223     {
3224       struct _utimbuf _ut;
3225 
3226       _ut.actime = timespec[0].tv_sec;
3227       _ut.modtime = timespec[1].tv_sec;
3228       return _futime (fd, &_ut);
3229     }
3230   else
3231     {
3232       struct utimbuf ut;
3233 
3234       ut.actime = timespec[0].tv_sec;
3235       ut.modtime = timespec[1].tv_sec;
3236       /* Call 'utime', which is implemented below, not the MS library
3237 	 function, which fails on directories.  */
3238       return utime (file, &ut);
3239     }
3240 }
3241 
3242 
3243 /* ------------------------------------------------------------------------- */
3244 /* IO support and wrapper functions for the Windows API. */
3245 /* ------------------------------------------------------------------------- */
3246 
3247 /* Place a wrapper around the MSVC version of ctime.  It returns NULL
3248    on network directories, so we handle that case here.
3249    (Ulrich Leodolter, 1/11/95).  */
3250 char *
sys_ctime(const time_t * t)3251 sys_ctime (const time_t *t)
3252 {
3253   char *str = (char *) ctime (t);
3254   return (str ? str : (char *)"Sun Jan 01 00:00:00 1970");
3255 }
3256 
3257 /* Emulate sleep...we could have done this with a define, but that
3258    would necessitate including windows.h in the files that used it.
3259    This is much easier.  */
3260 void
sys_sleep(int seconds)3261 sys_sleep (int seconds)
3262 {
3263   Sleep (seconds * 1000);
3264 }
3265 
3266 /* Internal MSVC functions for low-level descriptor munging */
3267 extern int __cdecl _set_osfhnd (int fd, long h);
3268 extern int __cdecl _free_osfhnd (int fd);
3269 
3270 /* parallel array of private info on file handles */
3271 filedesc fd_info [ MAXDESC ];
3272 
3273 typedef struct volume_info_data {
3274   struct volume_info_data * next;
3275 
3276   /* time when info was obtained */
3277   DWORD     timestamp;
3278 
3279   /* actual volume info */
3280   char *    root_dir;
3281   DWORD     serialnum;
3282   DWORD     maxcomp;
3283   DWORD     flags;
3284   char *    name;
3285   char *    type;
3286 } volume_info_data;
3287 
3288 /* Global referenced by various functions.  */
3289 static volume_info_data volume_info;
3290 
3291 /* Vector to indicate which drives are local and fixed (for which cached
3292    data never expires).  */
3293 static BOOL fixed_drives[26];
3294 
3295 /* Consider cached volume information to be stale if older than 10s,
3296    at least for non-local drives.  Info for fixed drives is never stale.  */
3297 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
3298 #define VOLINFO_STILL_VALID( root_dir, info )		\
3299   ( ( isalpha (root_dir[0]) &&				\
3300       fixed_drives[ DRIVE_INDEX (root_dir[0]) ] )	\
3301     || GetTickCount () - info->timestamp < 10000 )
3302 
3303 /* Cache support functions.  */
3304 
3305 /* Simple linked list with linear search is sufficient.  */
3306 static volume_info_data *volume_cache = NULL;
3307 
3308 static volume_info_data *
lookup_volume_info(char * root_dir)3309 lookup_volume_info (char * root_dir)
3310 {
3311   volume_info_data * info;
3312 
3313   for (info = volume_cache; info; info = info->next)
3314     if (xstrcasecmp (info->root_dir, root_dir) == 0)
3315       break;
3316   return info;
3317 }
3318 
3319 static void
add_volume_info(char * root_dir,volume_info_data * info)3320 add_volume_info (char * root_dir, volume_info_data * info)
3321 {
3322   info->root_dir = xstrdup (root_dir);
3323   unixtodos_filename (info->root_dir);
3324   info->next = volume_cache;
3325   volume_cache = info;
3326 }
3327 
3328 
3329 /* Wrapper for GetVolumeInformation, which uses caching to avoid
3330    performance penalty (~2ms on 486 for local drives, 7.5ms for local
3331    cdrom drive, ~5-10ms or more for remote drives on LAN).  */
3332 static volume_info_data *
GetCachedVolumeInformation(char * root_dir)3333 GetCachedVolumeInformation (char * root_dir)
3334 {
3335   volume_info_data * info;
3336   char default_root[ MAX_UTF8_PATH ];
3337   char  name[MAX_PATH+1];
3338   char  type[MAX_PATH+1];
3339 
3340   /* NULL for root_dir means use root from current directory.  */
3341   if (root_dir == NULL)
3342     {
3343       w32_get_current_directory (default_root);
3344       parse_root (default_root, (const char **)&root_dir);
3345       *root_dir = 0;
3346       root_dir = default_root;
3347     }
3348 
3349   /* Local fixed drives can be cached permanently.  Removable drives
3350      cannot be cached permanently, since the volume name and serial
3351      number (if nothing else) can change.  Remote drives should be
3352      treated as if they are removable, since there is no sure way to
3353      tell whether they are or not.  Also, the UNC association of drive
3354      letters mapped to remote volumes can be changed at any time (even
3355      by other processes) without notice.
3356 
3357      As a compromise, so we can benefit from caching info for remote
3358      volumes, we use a simple expiry mechanism to invalidate cache
3359      entries that are more than ten seconds old.  */
3360 
3361 #if 0
3362   /* No point doing this, because WNetGetConnection is even slower than
3363      GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
3364      GetDriveType is about the only call of this type which does not
3365      involve network access, and so is extremely quick).  */
3366 
3367   /* Map drive letter to UNC if remote. */
3368   if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
3369     {
3370       char remote_name[ 256 ];
3371       char drive[3] = { root_dir[0], ':' };
3372 
3373       if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
3374 	  == NO_ERROR)
3375 	/* do something */ ;
3376     }
3377 #endif
3378 
3379   info = lookup_volume_info (root_dir);
3380 
3381   if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
3382     {
3383       DWORD serialnum;
3384       DWORD maxcomp;
3385       DWORD flags;
3386 
3387       /* Info is not cached, or is stale. */
3388       if (w32_unicode_filenames)
3389 	{
3390 	  wchar_t root_w[MAX_PATH];
3391 	  wchar_t  name_w[MAX_PATH+1];
3392 	  wchar_t  type_w[MAX_PATH+1];
3393 
3394 	  filename_to_utf16 (root_dir, root_w);
3395 	  if (!GetVolumeInformationW (root_w,
3396 				     name_w, sizeof (name_w),
3397 				     &serialnum,
3398 				     &maxcomp,
3399 				     &flags,
3400 				     type_w, sizeof (type_w)))
3401 	    return NULL;
3402 	  /* Hmm... not really 100% correct, as these 2 are not file
3403 	     names...  */
3404 	  filename_from_utf16 (name_w, name);
3405 	  filename_from_utf16 (type_w, type);
3406 	}
3407       else
3408 	{
3409 	  char root_a[MAX_PATH];
3410 	  char  name_a[MAX_PATH+1];
3411 	  char  type_a[MAX_PATH+1];
3412 
3413 	  filename_to_ansi (root_dir, root_a);
3414 	  if (!GetVolumeInformationA (root_a,
3415 				     name_a, sizeof (name_a),
3416 				     &serialnum,
3417 				     &maxcomp,
3418 				     &flags,
3419 				     type_a, sizeof (type_a)))
3420 	    return NULL;
3421 	  filename_from_ansi (name_a, name);
3422 	  filename_from_ansi (type_a, type);
3423 	}
3424 
3425       /* Cache the volume information for future use, overwriting existing
3426 	 entry if present.  */
3427       if (info == NULL)
3428 	{
3429 	  info = xmalloc (sizeof (volume_info_data));
3430 	  add_volume_info (root_dir, info);
3431 	}
3432       else
3433 	{
3434 	  xfree (info->name);
3435 	  xfree (info->type);
3436 	}
3437 
3438       info->name = xstrdup (name);
3439       unixtodos_filename (info->name);
3440       info->serialnum = serialnum;
3441       info->maxcomp = maxcomp;
3442       info->flags = flags;
3443       info->type = xstrdup (type);
3444       info->timestamp = GetTickCount ();
3445     }
3446 
3447   return info;
3448 }
3449 
3450 /* Get information on the volume where NAME is held; set path pointer to
3451    start of pathname in NAME (past UNC header\volume header if present),
3452    if pPath is non-NULL.
3453 
3454    Note: if NAME includes symlinks, the information is for the volume
3455    of the symlink, not of its target.  That's because, even though
3456    GetVolumeInformation returns information about the symlink target
3457    of its argument, we only pass the root directory to
3458    GetVolumeInformation, not the full NAME.  */
3459 static int
get_volume_info(const char * name,const char ** pPath)3460 get_volume_info (const char * name, const char ** pPath)
3461 {
3462   char temp[MAX_UTF8_PATH];
3463   char *rootname = NULL;  /* default to current volume */
3464   volume_info_data * info;
3465   int root_len = parse_root (name, pPath);
3466 
3467   if (name == NULL)
3468     return FALSE;
3469 
3470   /* Copy the root name of the volume, if given.  */
3471   if (root_len)
3472     {
3473       strncpy (temp, name, root_len);
3474       temp[root_len] = '\0';
3475       unixtodos_filename (temp);
3476       rootname = temp;
3477     }
3478 
3479   info = GetCachedVolumeInformation (rootname);
3480   if (info != NULL)
3481     {
3482       /* Set global referenced by other functions.  */
3483       volume_info = *info;
3484       return TRUE;
3485     }
3486   return FALSE;
3487 }
3488 
3489 /* Determine if volume is FAT format (ie. only supports short 8.3
3490    names); also set path pointer to start of pathname in name, if
3491    pPath is non-NULL.  */
3492 static int
is_fat_volume(const char * name,const char ** pPath)3493 is_fat_volume (const char * name, const char ** pPath)
3494 {
3495   if (get_volume_info (name, pPath))
3496     return (volume_info.maxcomp == 12);
3497   return FALSE;
3498 }
3499 
3500 /* Convert all slashes in a filename to backslashes, and map filename
3501    to a valid 8.3 name if necessary.  The result is a pointer to a
3502    static buffer, so CAVEAT EMPTOR!  */
3503 const char *map_w32_filename (const char *, const char **);
3504 
3505 const char *
map_w32_filename(const char * name,const char ** pPath)3506 map_w32_filename (const char * name, const char ** pPath)
3507 {
3508   static char shortname[MAX_UTF8_PATH];
3509   char * str = shortname;
3510   char c;
3511   char * path;
3512   const char * save_name = name;
3513 
3514   if (strlen (name) >= sizeof (shortname))
3515     {
3516       /* Return a filename which will cause callers to fail.  */
3517       strcpy (shortname, "?");
3518       return shortname;
3519     }
3520 
3521   if (!fatal_error_in_progress	/* disable fancy processing during crash */
3522       && is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3523     {
3524       register int left = 8;	/* maximum number of chars in part */
3525       register int extn = 0;	/* extension added? */
3526       register int dots = 2;	/* maximum number of dots allowed */
3527 
3528       while (name < path)
3529 	*str++ = *name++;	/* skip past UNC header */
3530 
3531       while ((c = *name++))
3532         {
3533 	  switch ( c )
3534 	    {
3535 	    case ':':
3536 	    case '\\':
3537 	    case '/':
3538 	      *str++ = (c == ':' ? ':' : '\\');
3539 	      extn = 0;		/* reset extension flags */
3540 	      dots = 2;		/* max 2 dots */
3541 	      left = 8;		/* max length 8 for main part */
3542 	      break;
3543 	    case '.':
3544 	      if ( dots )
3545 	        {
3546 		  /* Convert path components of the form .xxx to _xxx,
3547 		     but leave . and .. as they are.  This allows .emacs
3548 		     to be read as _emacs, for example.  */
3549 
3550 		  if (! *name ||
3551 		      *name == '.' ||
3552 		      IS_DIRECTORY_SEP (*name))
3553 		    {
3554 		      *str++ = '.';
3555 		      dots--;
3556 		    }
3557 		  else
3558 		    {
3559 		      *str++ = '_';
3560 		      left--;
3561 		      dots = 0;
3562 		    }
3563 		}
3564 	      else if ( !extn )
3565 	        {
3566 		  *str++ = '.';
3567 		  extn = 1;		/* we've got an extension */
3568 		  left = 3;		/* 3 chars in extension */
3569 		}
3570 	      else
3571 	        {
3572 		  /* any embedded dots after the first are converted to _ */
3573 		  *str++ = '_';
3574 		}
3575 	      break;
3576 	    case '~':
3577 	    case '#':			/* don't lose these, they're important */
3578 	      if ( ! left )
3579 		str[-1] = c;		/* replace last character of part */
3580 	      /* FALLTHRU */
3581 	      FALLTHROUGH;
3582 	    default:
3583 	      if ( left && 'A' <= c && c <= 'Z' )
3584 	        {
3585 		  *str++ = tolower (c);	/* map to lower case (looks nicer) */
3586 		  left--;
3587 		  dots = 0;		/* started a path component */
3588 		}
3589 	      break;
3590 	    }
3591 	}
3592       *str = '\0';
3593     }
3594   else
3595     {
3596       strcpy (shortname, name);
3597       unixtodos_filename (shortname);
3598     }
3599 
3600   if (pPath)
3601     *pPath = shortname + (path - save_name);
3602 
3603   return shortname;
3604 }
3605 
3606 static int
is_exec(const char * name)3607 is_exec (const char * name)
3608 {
3609   char * p = strrchr (name, '.');
3610   return
3611     (p != NULL
3612      && (xstrcasecmp (p, ".exe") == 0 ||
3613 	 xstrcasecmp (p, ".com") == 0 ||
3614 	 xstrcasecmp (p, ".bat") == 0 ||
3615 	 xstrcasecmp (p, ".cmd") == 0));
3616 }
3617 
3618 /* Emulate the Unix directory procedures opendir, closedir, and
3619    readdir.  We rename them to sys_* names because some versions of
3620    MinGW startup code call opendir and readdir to glob wildcards, and
3621    the code that calls them doesn't grok UTF-8 encoded file names we
3622    produce in dirent->d_name[].  */
3623 
3624 struct dirent dir_static;       /* simulated directory contents */
3625 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3626 static int    dir_is_fat;
3627 static char   dir_pathname[MAX_UTF8_PATH];
3628 static WIN32_FIND_DATAW dir_find_data_w;
3629 static WIN32_FIND_DATAA dir_find_data_a;
3630 #define DIR_FIND_DATA_W 1
3631 #define DIR_FIND_DATA_A 2
3632 static int    last_dir_find_data = -1;
3633 
3634 /* Support shares on a network resource as subdirectories of a read-only
3635    root directory. */
3636 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3637 static HANDLE open_unc_volume (const char *);
3638 static void  *read_unc_volume (HANDLE, wchar_t *, char *, int);
3639 static void   close_unc_volume (HANDLE);
3640 
3641 DIR *
sys_opendir(const char * filename)3642 sys_opendir (const char *filename)
3643 {
3644   DIR *dirp;
3645 
3646   /* Opening is done by FindFirstFile.  However, a read is inherent to
3647      this operation, so we defer the open until read time.  */
3648 
3649   if (dir_find_handle != INVALID_HANDLE_VALUE)
3650     return NULL;
3651   if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3652     return NULL;
3653 
3654   /* Note: We don't support traversal of UNC volumes via symlinks.
3655      Doing so would mean punishing 99.99% of use cases by resolving
3656      all the possible symlinks in FILENAME, recursively. */
3657   if (is_unc_volume (filename))
3658     {
3659       wnet_enum_handle = open_unc_volume (filename);
3660       if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3661 	return NULL;
3662     }
3663 
3664   if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3665     return NULL;
3666 
3667   dirp->dd_fd = 0;
3668   dirp->dd_loc = 0;
3669   dirp->dd_size = 0;
3670 
3671   strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3672   dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3673   /* Note: We don't support symlinks to file names on FAT volumes.
3674      Doing so would mean punishing 99.99% of use cases by resolving
3675      all the possible symlinks in FILENAME, recursively.  */
3676   dir_is_fat = is_fat_volume (filename, NULL);
3677 
3678   return dirp;
3679 }
3680 
3681 void
sys_closedir(DIR * dirp)3682 sys_closedir (DIR *dirp)
3683 {
3684   /* If we have a find-handle open, close it.  */
3685   if (dir_find_handle != INVALID_HANDLE_VALUE)
3686     {
3687       FindClose (dir_find_handle);
3688       dir_find_handle = INVALID_HANDLE_VALUE;
3689     }
3690   else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3691     {
3692       close_unc_volume (wnet_enum_handle);
3693       wnet_enum_handle = INVALID_HANDLE_VALUE;
3694     }
3695   xfree ((char *) dirp);
3696 }
3697 
3698 struct dirent *
sys_readdir(DIR * dirp)3699 sys_readdir (DIR *dirp)
3700 {
3701   int downcase = !NILP (Vw32_downcase_file_names);
3702 
3703   if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3704     {
3705       if (!read_unc_volume (wnet_enum_handle,
3706                             dir_find_data_w.cFileName,
3707                             dir_find_data_a.cFileName,
3708                             MAX_PATH))
3709 	return NULL;
3710     }
3711   /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3712   else if (dir_find_handle == INVALID_HANDLE_VALUE)
3713     {
3714       char filename[MAX_UTF8_PATH];
3715       int ln;
3716       bool last_slash = true;
3717 
3718       /* Note: We don't need to worry about dir_pathname being longer
3719 	 than MAX_UTF8_PATH, as sys_opendir already took care of that
3720 	 when it called map_w32_filename: that function will put a "?"
3721 	 in its return value in that case, thus failing all the calls
3722 	 below.  */
3723       strcpy (filename, dir_pathname);
3724       ln = strlen (filename);
3725       if (!IS_DIRECTORY_SEP (filename[ln - 1]))
3726 	last_slash = false;
3727 
3728       /* Note: No need to resolve symlinks in FILENAME, because
3729 	 FindFirst opens the directory that is the target of a
3730 	 symlink.  */
3731       if (w32_unicode_filenames)
3732 	{
3733 	  wchar_t fnw[MAX_PATH + 2];
3734 
3735 	  filename_to_utf16 (filename, fnw);
3736 	  if (!last_slash)
3737 	    wcscat (fnw, L"\\");
3738 	  wcscat (fnw, L"*");
3739 	  dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3740 	}
3741       else
3742 	{
3743 	  char fna[MAX_PATH + 2];
3744 
3745 	  filename_to_ansi (filename, fna);
3746 	  if (!last_slash)
3747 	    strcat (fna, "\\");
3748 	  strcat (fna, "*");
3749 	  /* If FILENAME is not representable by the current ANSI
3750 	     codepage, we don't want FindFirstFileA to interpret the
3751 	     '?' characters as a wildcard.  */
3752 	  if (_mbspbrk (fna, "?"))
3753 	    dir_find_handle = INVALID_HANDLE_VALUE;
3754 	  else
3755 	    dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3756 	}
3757 
3758       if (dir_find_handle == INVALID_HANDLE_VALUE)
3759 	{
3760 	  /* Any changes in the value of errno here should be in sync
3761 	     with what directory_files_internal does when it calls
3762 	     readdir.  */
3763 	  switch (GetLastError ())
3764 	    {
3765 	      /* Windows uses this value when FindFirstFile finds no
3766 		 files that match the wildcard.  This is not supposed
3767 		 to happen, since our wildcard is "*", but just in
3768 		 case, if there's some weird empty directory with not
3769 		 even "." and ".." entries...  */
3770 	    case ERROR_FILE_NOT_FOUND:
3771 	      errno = 0;
3772 	      /* FALLTHRU */
3773 	    default:
3774 	      break;
3775 	    case ERROR_ACCESS_DENIED:
3776 	    case ERROR_NETWORK_ACCESS_DENIED:
3777 	      errno = EACCES;
3778 	      break;
3779 	    case ERROR_PATH_NOT_FOUND:
3780 	    case ERROR_INVALID_DRIVE:
3781 	    case ERROR_NOT_READY:
3782 	    case ERROR_BAD_NETPATH:
3783 	    case ERROR_BAD_NET_NAME:
3784 	      errno = ENOENT;
3785 	      break;
3786 	    }
3787 	  return NULL;
3788 	}
3789     }
3790   else if (w32_unicode_filenames)
3791     {
3792       if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3793 	{
3794 	  errno = 0;
3795 	  return NULL;
3796 	}
3797     }
3798   else
3799     {
3800       if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3801 	{
3802 	  errno = 0;
3803 	  return NULL;
3804 	}
3805     }
3806 
3807   /* Emacs never uses this value, so don't bother making it match
3808      value returned by stat().  */
3809   dir_static.d_ino = 1;
3810 
3811   if (w32_unicode_filenames)
3812     {
3813       if (downcase || dir_is_fat)
3814 	{
3815 	  wchar_t tem[MAX_PATH];
3816 
3817 	  wcscpy (tem, dir_find_data_w.cFileName);
3818 	  CharLowerW (tem);
3819 	  filename_from_utf16 (tem, dir_static.d_name);
3820 	}
3821       else
3822 	filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3823       last_dir_find_data = DIR_FIND_DATA_W;
3824     }
3825   else
3826     {
3827       char tem[MAX_PATH];
3828 
3829       /* If the file name in cFileName[] includes `?' characters, it
3830 	 means the original file name used characters that cannot be
3831 	 represented by the current ANSI codepage.  To avoid total
3832 	 lossage, retrieve the short 8+3 alias of the long file
3833 	 name.  */
3834       if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3835 	{
3836 	  strcpy (tem, dir_find_data_a.cAlternateFileName);
3837 	  /* 8+3 aliases are returned in all caps, which could break
3838 	     various alists that look at filenames' extensions.  */
3839 	  downcase = 1;
3840 	}
3841       else if (downcase || dir_is_fat)
3842 	strcpy (tem, dir_find_data_a.cFileName);
3843       else
3844 	filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3845       if (downcase || dir_is_fat)
3846 	{
3847 	  _mbslwr (tem);
3848 	  filename_from_ansi (tem, dir_static.d_name);
3849 	}
3850       last_dir_find_data = DIR_FIND_DATA_A;
3851     }
3852 
3853   dir_static.d_namlen = strlen (dir_static.d_name);
3854   dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3855     dir_static.d_namlen - dir_static.d_namlen % 4;
3856 
3857   return &dir_static;
3858 }
3859 
3860 static HANDLE
open_unc_volume(const char * path)3861 open_unc_volume (const char *path)
3862 {
3863   const char *fn = map_w32_filename (path, NULL);
3864   DWORD result;
3865   HANDLE henum;
3866 
3867   if (w32_unicode_filenames)
3868     {
3869       NETRESOURCEW nrw;
3870       wchar_t fnw[MAX_PATH];
3871 
3872       nrw.dwScope = RESOURCE_GLOBALNET;
3873       nrw.dwType = RESOURCETYPE_DISK;
3874       nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3875       nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3876       nrw.lpLocalName = NULL;
3877       filename_to_utf16 (fn, fnw);
3878       nrw.lpRemoteName = fnw;
3879       nrw.lpComment = NULL;
3880       nrw.lpProvider = NULL;
3881 
3882       result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3883 			      RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3884     }
3885   else
3886     {
3887       NETRESOURCEA nra;
3888       char fna[MAX_PATH];
3889 
3890       nra.dwScope = RESOURCE_GLOBALNET;
3891       nra.dwType = RESOURCETYPE_DISK;
3892       nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3893       nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3894       nra.lpLocalName = NULL;
3895       filename_to_ansi (fn, fna);
3896       nra.lpRemoteName = fna;
3897       nra.lpComment = NULL;
3898       nra.lpProvider = NULL;
3899 
3900       result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3901 			      RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3902     }
3903   if (result == NO_ERROR)
3904     return henum;
3905   else
3906     {
3907       /* Make sure directory_files_internal reports a sensible error.  */
3908       errno = ENOENT;
3909       return INVALID_HANDLE_VALUE;
3910     }
3911 }
3912 
3913 static void *
read_unc_volume(HANDLE henum,wchar_t * fname_w,char * fname_a,int size)3914 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3915 {
3916   DWORD count;
3917   int result;
3918   char *buffer;
3919   DWORD bufsize = 512;
3920   void *retval;
3921 
3922   count = 1;
3923   if (w32_unicode_filenames)
3924     {
3925       wchar_t *ptrw;
3926 
3927       bufsize *= 2;
3928       buffer = alloca (bufsize);
3929       result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3930       if (result != NO_ERROR)
3931 	return NULL;
3932       /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3933       ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3934       ptrw += 2;
3935       while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3936       ptrw++;
3937       wcsncpy (fname_w, ptrw, size);
3938       retval = fname_w;
3939     }
3940   else
3941     {
3942       int dbcs_p = max_filename_mbslen () > 1;
3943       char *ptra;
3944 
3945       buffer = alloca (bufsize);
3946       result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3947       if (result != NO_ERROR)
3948 	return NULL;
3949       ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3950       ptra += 2;
3951       if (!dbcs_p)
3952 	while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3953       else
3954 	{
3955 	  while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3956 	    ptra = CharNextExA (file_name_codepage, ptra, 0);
3957 	}
3958       ptra++;
3959       strncpy (fname_a, ptra, size);
3960       retval = fname_a;
3961     }
3962 
3963   return retval;
3964 }
3965 
3966 static void
close_unc_volume(HANDLE henum)3967 close_unc_volume (HANDLE henum)
3968 {
3969   if (henum != INVALID_HANDLE_VALUE)
3970     WNetCloseEnum (henum);
3971 }
3972 
3973 static DWORD
unc_volume_file_attributes(const char * path)3974 unc_volume_file_attributes (const char *path)
3975 {
3976   HANDLE henum;
3977   DWORD attrs;
3978 
3979   henum = open_unc_volume (path);
3980   if (henum == INVALID_HANDLE_VALUE)
3981     return -1;
3982 
3983   attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3984 
3985   close_unc_volume (henum);
3986 
3987   return attrs;
3988 }
3989 
3990 /* Ensure a network connection is authenticated.  */
3991 static void
logon_network_drive(const char * path)3992 logon_network_drive (const char *path)
3993 {
3994   char share[MAX_UTF8_PATH];
3995   int n_slashes;
3996   char drive[4];
3997   UINT drvtype;
3998   char *p;
3999   DWORD val;
4000 
4001   if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
4002     drvtype = DRIVE_REMOTE;
4003   else if (path[0] == '\0' || path[1] != ':')
4004     drvtype = GetDriveType (NULL);
4005   else
4006     {
4007       drive[0] = path[0];
4008       drive[1] = ':';
4009       drive[2] = '\\';
4010       drive[3] = '\0';
4011       drvtype = GetDriveType (drive);
4012     }
4013 
4014   /* Only logon to networked drives.  */
4015   if (drvtype != DRIVE_REMOTE)
4016     return;
4017 
4018   n_slashes = 2;
4019   strncpy (share, path, MAX_UTF8_PATH - 1);
4020   /* Truncate to just server and share name.  */
4021   for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
4022     {
4023       if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
4024         {
4025           *p = '\0';
4026           break;
4027         }
4028     }
4029 
4030   if (w32_unicode_filenames)
4031     {
4032       NETRESOURCEW resourcew;
4033       wchar_t share_w[MAX_PATH];
4034 
4035       resourcew.dwScope = RESOURCE_GLOBALNET;
4036       resourcew.dwType = RESOURCETYPE_DISK;
4037       resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
4038       resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
4039       resourcew.lpLocalName = NULL;
4040       filename_to_utf16 (share, share_w);
4041       resourcew.lpRemoteName = share_w;
4042       resourcew.lpProvider = NULL;
4043 
4044       val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
4045     }
4046   else
4047     {
4048       NETRESOURCEA resourcea;
4049       char share_a[MAX_PATH];
4050 
4051       resourcea.dwScope = RESOURCE_GLOBALNET;
4052       resourcea.dwType = RESOURCETYPE_DISK;
4053       resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
4054       resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
4055       resourcea.lpLocalName = NULL;
4056       filename_to_ansi (share, share_a);
4057       resourcea.lpRemoteName = share_a;
4058       resourcea.lpProvider = NULL;
4059 
4060       val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
4061     }
4062 
4063   switch (val)
4064     {
4065     case NO_ERROR:
4066     case ERROR_ALREADY_ASSIGNED:
4067       break;
4068     case ERROR_ACCESS_DENIED:
4069     case ERROR_LOGON_FAILURE:
4070       errno = EACCES;
4071       break;
4072     case ERROR_BUSY:
4073       errno = EAGAIN;
4074       break;
4075     case ERROR_BAD_NET_NAME:
4076     case ERROR_NO_NET_OR_BAD_PATH:
4077     case ERROR_NO_NETWORK:
4078     case ERROR_CANCELLED:
4079     default:
4080       errno = ENOENT;
4081       break;
4082     }
4083 }
4084 
4085 /* Emulate faccessat(2).  */
4086 int
faccessat(int dirfd,const char * path,int mode,int flags)4087 faccessat (int dirfd, const char * path, int mode, int flags)
4088 {
4089   DWORD attributes;
4090   char fullname[MAX_UTF8_PATH];
4091 
4092   /* Rely on a hack: an open directory is modeled as file descriptor 0,
4093      and its actual file name is stored in dir_pathname by opendir.
4094      This is good enough for the current usage in Emacs, but is fragile.  */
4095   if (dirfd != AT_FDCWD
4096       && !(IS_DIRECTORY_SEP (path[0])
4097 	   || IS_DEVICE_SEP (path[1])))
4098     {
4099       char lastc = dir_pathname[strlen (dir_pathname) - 1];
4100 
4101       if (_snprintf (fullname, sizeof fullname, "%s%s%s",
4102 		     dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", path)
4103 	  < 0)
4104 	{
4105 	  errno = ENAMETOOLONG;
4106 	  return -1;
4107 	}
4108       path = fullname;
4109     }
4110 
4111   /* When dired.c calls us with F_OK and a trailing slash, it actually
4112      wants to know whether PATH is a directory.  */
4113   if (IS_DIRECTORY_SEP (path[strlen (path) - 1]) && mode == F_OK)
4114     mode |= D_OK;
4115 
4116   /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
4117      newer versions blow up when passed D_OK.  */
4118   path = map_w32_filename (path, NULL);
4119   /* If the last element of PATH is a symlink, we need to resolve it
4120      to get the attributes of its target file.  Note: any symlinks in
4121      PATH elements other than the last one are transparently resolved
4122      by GetFileAttributes below.  */
4123   if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
4124       && (flags & AT_SYMLINK_NOFOLLOW) == 0)
4125     path = chase_symlinks (path);
4126 
4127   if (w32_unicode_filenames)
4128     {
4129       wchar_t path_w[MAX_PATH];
4130 
4131       filename_to_utf16 (path, path_w);
4132       attributes = GetFileAttributesW (path_w);
4133     }
4134   else
4135     {
4136       char path_a[MAX_PATH];
4137 
4138       filename_to_ansi (path, path_a);
4139       attributes = GetFileAttributesA (path_a);
4140     }
4141 
4142   if (attributes == -1)
4143     {
4144       DWORD w32err = GetLastError ();
4145 
4146       switch (w32err)
4147 	{
4148 	case ERROR_INVALID_NAME:
4149 	case ERROR_BAD_PATHNAME:
4150 	  if (is_unc_volume (path))
4151 	    {
4152 	      attributes = unc_volume_file_attributes (path);
4153 	      if (attributes == -1)
4154 		{
4155 		  errno = EACCES;
4156 		  return -1;
4157 		}
4158 	      goto check_attrs;
4159 	    }
4160 	  /* FALLTHROUGH */
4161 	  FALLTHROUGH;
4162 	case ERROR_FILE_NOT_FOUND:
4163 	case ERROR_PATH_NOT_FOUND:
4164 	case ERROR_INVALID_DRIVE:
4165 	case ERROR_NOT_READY:
4166 	case ERROR_BAD_NETPATH:
4167 	case ERROR_BAD_NET_NAME:
4168 	  errno = ENOENT;
4169 	  break;
4170 	default:
4171 	  errno = EACCES;
4172 	  break;
4173 	}
4174       return -1;
4175     }
4176 
4177  check_attrs:
4178   if ((mode & X_OK) != 0
4179       && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
4180     {
4181       errno = EACCES;
4182       return -1;
4183     }
4184   if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
4185     {
4186       errno = EACCES;
4187       return -1;
4188     }
4189   if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
4190     {
4191       errno = EACCES;
4192       return -1;
4193     }
4194   return 0;
4195 }
4196 
4197 /* A special test for DIRNAME being a directory accessible by the
4198    current user.  This is needed because the security permissions in
4199    directory's ACLs are not visible in the Posix-style mode bits
4200    returned by 'stat' and in attributes returned by GetFileAttributes.
4201    So a directory would seem like it's readable by the current user,
4202    but will in fact error out with EACCES when they actually try.  */
4203 int
w32_accessible_directory_p(const char * dirname,ptrdiff_t dirlen)4204 w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
4205 {
4206   char pattern[MAX_UTF8_PATH];
4207   bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
4208   HANDLE dh;
4209 
4210   /* Network volumes need a different reading method.  */
4211   if (is_unc_volume (dirname))
4212     {
4213       void *read_result = NULL;
4214       wchar_t fnw[MAX_PATH];
4215       char fna[MAX_PATH];
4216 
4217       dh = open_unc_volume (dirname);
4218       if (dh != INVALID_HANDLE_VALUE)
4219 	{
4220 	  read_result = read_unc_volume (dh, fnw, fna, MAX_PATH);
4221 	  close_unc_volume (dh);
4222 	}
4223       /* Treat empty volumes as accessible.  */
4224       return read_result != NULL || GetLastError () == ERROR_NO_MORE_ITEMS;
4225     }
4226 
4227   /* Note: map_w32_filename makes sure DIRNAME is not longer than
4228      MAX_UTF8_PATH.  */
4229   strcpy (pattern, map_w32_filename (dirname, NULL));
4230 
4231   /* Note: No need to resolve symlinks in FILENAME, because FindFirst
4232      opens the directory that is the target of a symlink.  */
4233   if (w32_unicode_filenames)
4234     {
4235       wchar_t pat_w[MAX_PATH + 2];
4236       WIN32_FIND_DATAW dfd_w;
4237 
4238       filename_to_utf16 (pattern, pat_w);
4239       if (!last_slash)
4240 	wcscat (pat_w, L"\\");
4241       wcscat (pat_w, L"*");
4242       dh = FindFirstFileW (pat_w, &dfd_w);
4243     }
4244   else
4245     {
4246       char pat_a[MAX_PATH + 2];
4247       WIN32_FIND_DATAA dfd_a;
4248 
4249       filename_to_ansi (pattern, pat_a);
4250       if (!last_slash)
4251 	strcpy (pat_a, "\\");
4252       strcat (pat_a, "*");
4253       /* In case DIRNAME cannot be expressed in characters from the
4254 	 current ANSI codepage.  */
4255       if (_mbspbrk (pat_a, "?"))
4256 	{
4257 	  errno = ENOENT;
4258 	  return 0;
4259 	}
4260       dh = FindFirstFileA (pat_a, &dfd_a);
4261     }
4262 
4263   if (dh == INVALID_HANDLE_VALUE)
4264     {
4265       DWORD w32err = GetLastError ();
4266 
4267       switch (w32err)
4268 	{
4269 	case ERROR_INVALID_NAME:
4270 	case ERROR_BAD_PATHNAME:
4271 	case ERROR_FILE_NOT_FOUND:
4272 	case ERROR_PATH_NOT_FOUND:
4273 	case ERROR_NO_MORE_FILES:
4274 	case ERROR_BAD_NETPATH:
4275 	  errno = ENOENT;
4276 	  break;
4277 	case ERROR_NOT_READY:
4278 	  errno = ENODEV;
4279 	  break;
4280 	default:
4281 	  errno = EACCES;
4282 	  break;
4283 	}
4284     return 0;
4285     }
4286   FindClose (dh);
4287   return 1;
4288 }
4289 
4290 /* A version of 'access' to be used locally with file names in
4291    locale-specific encoding.  Does not resolve symlinks and does not
4292    support file names on FAT12 and FAT16 volumes, but that's OK, since
4293    we only invoke this function for files inside the Emacs source or
4294    installation tree, on directories (so any symlinks should have the
4295    directory bit set), and on short file names such as "C:/.emacs".  */
4296 static int
sys_access(const char * fname,int mode)4297 sys_access (const char *fname, int mode)
4298 {
4299   char fname_copy[MAX_PATH], *p;
4300   DWORD attributes;
4301 
4302   strcpy (fname_copy, fname);
4303   /* Do the equivalent of unixtodos_filename.  */
4304   for (p = fname_copy; *p; p = CharNext (p))
4305     if (*p == '/')
4306       *p = '\\';
4307 
4308   if ((attributes = GetFileAttributesA (fname_copy)) == -1)
4309     {
4310       DWORD w32err = GetLastError ();
4311 
4312       switch (w32err)
4313 	{
4314 	case ERROR_INVALID_NAME:
4315 	case ERROR_BAD_PATHNAME:
4316 	case ERROR_FILE_NOT_FOUND:
4317 	case ERROR_BAD_NETPATH:
4318 	  errno = ENOENT;
4319 	  break;
4320 	default:
4321 	  errno = EACCES;
4322 	  break;
4323 	}
4324       return -1;
4325     }
4326   if ((mode & X_OK) != 0
4327       && !(is_exec (fname_copy)
4328 	   || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
4329     {
4330       errno = EACCES;
4331       return -1;
4332     }
4333   if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
4334     {
4335       errno = EACCES;
4336       return -1;
4337     }
4338   if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
4339     {
4340       errno = EACCES;
4341       return -1;
4342     }
4343   return 0;
4344 }
4345 
4346 /* Shadow some MSVC runtime functions to map requests for long filenames
4347    to reasonable short names if necessary.  This was originally added to
4348    permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
4349    long file names.  */
4350 
4351 int
sys_chdir(const char * path)4352 sys_chdir (const char * path)
4353 {
4354   path = map_w32_filename (path, NULL);
4355   if (w32_unicode_filenames)
4356     {
4357       wchar_t newdir_w[MAX_PATH];
4358 
4359       if (filename_to_utf16 (path, newdir_w) == 0)
4360 	return _wchdir (newdir_w);
4361       return -1;
4362     }
4363   else
4364     {
4365       char newdir_a[MAX_PATH];
4366 
4367       if (filename_to_ansi (path, newdir_a) == 0)
4368 	return _chdir (newdir_a);
4369       return -1;
4370     }
4371 }
4372 
4373 int
sys_chmod(const char * path,int mode)4374 sys_chmod (const char * path, int mode)
4375 {
4376   path = chase_symlinks (map_w32_filename (path, NULL));
4377   if (w32_unicode_filenames)
4378     {
4379       wchar_t path_w[MAX_PATH];
4380 
4381       filename_to_utf16 (path, path_w);
4382       return _wchmod (path_w, mode);
4383     }
4384   else
4385     {
4386       char path_a[MAX_PATH];
4387 
4388       filename_to_ansi (path, path_a);
4389       return _chmod (path_a, mode);
4390     }
4391 }
4392 
4393 int
sys_creat(const char * path,int mode)4394 sys_creat (const char * path, int mode)
4395 {
4396   path = map_w32_filename (path, NULL);
4397   if (w32_unicode_filenames)
4398     {
4399       wchar_t path_w[MAX_PATH];
4400 
4401       filename_to_utf16 (path, path_w);
4402       return _wcreat (path_w, mode);
4403     }
4404   else
4405     {
4406       char path_a[MAX_PATH];
4407 
4408       filename_to_ansi (path, path_a);
4409       return _creat (path_a, mode);
4410     }
4411 }
4412 
4413 FILE *
sys_fopen(const char * path,const char * mode)4414 sys_fopen (const char * path, const char * mode)
4415 {
4416   int fd;
4417   int oflag;
4418   const char * mode_save = mode;
4419 
4420   /* Force all file handles to be non-inheritable.  This is necessary to
4421      ensure child processes don't unwittingly inherit handles that might
4422      prevent future file access. */
4423 
4424   if (mode[0] == 'r')
4425     oflag = O_RDONLY;
4426   else if (mode[0] == 'w' || mode[0] == 'a')
4427     oflag = O_WRONLY | O_CREAT | O_TRUNC;
4428   else
4429     return NULL;
4430 
4431   /* Only do simplistic option parsing. */
4432   while (*++mode)
4433     if (mode[0] == '+')
4434       {
4435 	oflag &= ~(O_RDONLY | O_WRONLY);
4436 	oflag |= O_RDWR;
4437       }
4438     else if (mode[0] == 'b')
4439       {
4440 	oflag &= ~O_TEXT;
4441 	oflag |= O_BINARY;
4442       }
4443     else if (mode[0] == 't')
4444       {
4445 	oflag &= ~O_BINARY;
4446 	oflag |= O_TEXT;
4447       }
4448     else break;
4449 
4450   path = map_w32_filename (path, NULL);
4451   if (w32_unicode_filenames)
4452     {
4453       wchar_t path_w[MAX_PATH];
4454 
4455       filename_to_utf16 (path, path_w);
4456       fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
4457     }
4458   else
4459     {
4460       char path_a[MAX_PATH];
4461 
4462       filename_to_ansi (path, path_a);
4463       fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
4464     }
4465   if (fd < 0)
4466     return NULL;
4467 
4468   return _fdopen (fd, mode_save);
4469 }
4470 
4471 /* This only works on NTFS volumes, but is useful to have.  */
4472 int
sys_link(const char * old,const char * new)4473 sys_link (const char * old, const char * new)
4474 {
4475   HANDLE fileh;
4476   int   result = -1;
4477   char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
4478   wchar_t oldname_w[MAX_PATH];
4479   char oldname_a[MAX_PATH];
4480 
4481   if (old == NULL || new == NULL)
4482     {
4483       errno = ENOENT;
4484       return -1;
4485     }
4486 
4487   strcpy (oldname, map_w32_filename (old, NULL));
4488   strcpy (newname, map_w32_filename (new, NULL));
4489 
4490   if (w32_unicode_filenames)
4491     {
4492       filename_to_utf16 (oldname, oldname_w);
4493       fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
4494 			   FILE_FLAG_BACKUP_SEMANTICS, NULL);
4495     }
4496   else
4497     {
4498       filename_to_ansi (oldname, oldname_a);
4499       fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
4500 			   FILE_FLAG_BACKUP_SEMANTICS, NULL);
4501     }
4502   if (fileh != INVALID_HANDLE_VALUE)
4503     {
4504       int wlen;
4505 
4506       /* Confusingly, the "alternate" stream name field does not apply
4507          when restoring a hard link, and instead contains the actual
4508          stream data for the link (ie. the name of the link to create).
4509          The WIN32_STREAM_ID structure before the cStreamName field is
4510          the stream header, which is then immediately followed by the
4511          stream data.  */
4512 
4513       struct {
4514 	WIN32_STREAM_ID wid;
4515 	WCHAR wbuffer[MAX_PATH];	/* extra space for link name */
4516       } data;
4517 
4518       /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
4519 	 indicates that flag is unsupported for CP_UTF8, and OTOH says
4520 	 it is the default anyway.  */
4521       wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
4522 				   data.wid.cStreamName, MAX_PATH);
4523       if (wlen > 0)
4524 	{
4525 	  LPVOID context = NULL;
4526 	  DWORD wbytes = 0;
4527 
4528 	  data.wid.dwStreamId = BACKUP_LINK;
4529 	  data.wid.dwStreamAttributes = 0;
4530 	  data.wid.Size.LowPart = wlen * sizeof (WCHAR);
4531 	  data.wid.Size.HighPart = 0;
4532 	  data.wid.dwStreamNameSize = 0;
4533 
4534 	  if (BackupWrite (fileh, (LPBYTE)&data,
4535 			   offsetof (WIN32_STREAM_ID, cStreamName)
4536 			   + data.wid.Size.LowPart,
4537 			   &wbytes, FALSE, FALSE, &context)
4538 	      && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
4539 	    {
4540 	      /* succeeded */
4541 	      result = 0;
4542 	    }
4543 	  else
4544 	    {
4545 	      DWORD err = GetLastError ();
4546 	      DWORD attributes;
4547 
4548 	      switch (err)
4549 		{
4550 		case ERROR_ACCESS_DENIED:
4551 		  /* This is what happens when OLDNAME is a directory,
4552 		     since Windows doesn't support hard links to
4553 		     directories.  Posix says to set errno to EPERM in
4554 		     that case.  */
4555 		  if (w32_unicode_filenames)
4556 		    attributes = GetFileAttributesW (oldname_w);
4557 		  else
4558 		    attributes = GetFileAttributesA (oldname_a);
4559 		  if (attributes != -1
4560 		      && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
4561 		    errno = EPERM;
4562 		  else if (attributes == -1
4563 			   && is_unc_volume (oldname)
4564 			   && unc_volume_file_attributes (oldname) != -1)
4565 		    errno = EPERM;
4566 		  else
4567 		    errno = EACCES;
4568 		  break;
4569 		case ERROR_TOO_MANY_LINKS:
4570 		  errno = EMLINK;
4571 		  break;
4572 		case ERROR_NOT_SAME_DEVICE:
4573 		  errno = EXDEV;
4574 		  break;
4575 		default:
4576 		  errno = EINVAL;
4577 		  break;
4578 		}
4579 	    }
4580 	}
4581 
4582       CloseHandle (fileh);
4583     }
4584   else
4585     errno = ENOENT;
4586 
4587   return result;
4588 }
4589 
4590 int
sys_mkdir(const char * path,mode_t mode)4591 sys_mkdir (const char * path, mode_t mode)
4592 {
4593   path = map_w32_filename (path, NULL);
4594 
4595   if (w32_unicode_filenames)
4596     {
4597       wchar_t path_w[MAX_PATH];
4598 
4599       filename_to_utf16 (path, path_w);
4600       return _wmkdir (path_w);
4601     }
4602   else
4603     {
4604       char path_a[MAX_PATH];
4605 
4606       filename_to_ansi (path, path_a);
4607       return _mkdir (path_a);
4608     }
4609 }
4610 
4611 int
sys_open(const char * path,int oflag,int mode)4612 sys_open (const char * path, int oflag, int mode)
4613 {
4614   const char* mpath = map_w32_filename (path, NULL);
4615   int res = -1;
4616 
4617   if (w32_unicode_filenames)
4618     {
4619       wchar_t mpath_w[MAX_PATH];
4620 
4621       filename_to_utf16 (mpath, mpath_w);
4622       /* If possible, try to open file without _O_CREAT, to be able to
4623 	 write to existing hidden and system files.  Force all file
4624 	 handles to be non-inheritable. */
4625       if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4626 	res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4627       if (res < 0)
4628 	res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4629     }
4630   else
4631     {
4632       char mpath_a[MAX_PATH];
4633 
4634       filename_to_ansi (mpath, mpath_a);
4635       if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4636 	res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4637       if (res < 0)
4638 	res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4639     }
4640 
4641   return res;
4642 }
4643 
4644 int
fchmod(int fd,mode_t mode)4645 fchmod (int fd, mode_t mode)
4646 {
4647   return 0;
4648 }
4649 
4650 int
sys_rename_replace(const char * oldname,const char * newname,BOOL force)4651 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4652 {
4653   BOOL result;
4654   char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4655   int newname_dev;
4656   int oldname_dev;
4657   bool have_temp_a = false;
4658 
4659   /* MoveFile on Windows 95 doesn't correctly change the short file name
4660      alias in a number of circumstances (it is not easy to predict when
4661      just by looking at oldname and newname, unfortunately).  In these
4662      cases, renaming through a temporary name avoids the problem.
4663 
4664      A second problem on Windows 95 is that renaming through a temp name when
4665      newname is uppercase fails (the final long name ends up in
4666      lowercase, although the short alias might be uppercase) UNLESS the
4667      long temp name is not 8.3.
4668 
4669      So, on Windows 95 we always rename through a temp name, and we make sure
4670      the temp name has a long extension to ensure correct renaming.  */
4671 
4672   strcpy (temp, map_w32_filename (oldname, NULL));
4673 
4674   /* volume_info is set indirectly by map_w32_filename.  */
4675   oldname_dev = volume_info.serialnum;
4676 
4677   if (os_subtype == OS_9X)
4678     {
4679       char * o;
4680       char * p;
4681       int    i = 0;
4682       char oldname_a[MAX_PATH];
4683 
4684       oldname = map_w32_filename (oldname, NULL);
4685       filename_to_ansi (oldname, oldname_a);
4686       filename_to_ansi (temp, temp_a);
4687       if ((o = strrchr (oldname_a, '\\')))
4688 	o++;
4689       else
4690 	o = (char *) oldname_a;
4691 
4692       if ((p = strrchr (temp_a, '\\')))
4693 	p++;
4694       else
4695 	p = temp_a;
4696 
4697       do
4698 	{
4699 	  /* Force temp name to require a manufactured 8.3 alias - this
4700 	     seems to make the second rename work properly.  */
4701 	  sprintf (p, "_.%s.%d", o, i);
4702 	  i++;
4703 	  result = rename (oldname_a, temp_a);
4704 	}
4705       /* This loop must surely terminate!  */
4706       while (result < 0 && errno == EEXIST);
4707       if (result < 0)
4708 	return -1;
4709       have_temp_a = true;
4710     }
4711 
4712   /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4713      (at least if it is a file; don't do this for directories).
4714 
4715      Since we mustn't do this if we are just changing the case of the
4716      file name (we would end up deleting the file we are trying to
4717      rename!), we let rename detect if the destination file already
4718      exists - that way we avoid the possible pitfalls of trying to
4719      determine ourselves whether two names really refer to the same
4720      file, which is not always possible in the general case.  (Consider
4721      all the permutations of shared or subst'd drives, etc.)  */
4722 
4723   newname = map_w32_filename (newname, NULL);
4724 
4725   /* volume_info is set indirectly by map_w32_filename.  */
4726   newname_dev = volume_info.serialnum;
4727 
4728   if (w32_unicode_filenames)
4729     {
4730       wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4731 
4732       filename_to_utf16 (temp, temp_w);
4733       filename_to_utf16 (newname, newname_w);
4734       result = _wrename (temp_w, newname_w);
4735       if (result < 0)
4736 	{
4737 	  DWORD w32err = GetLastError ();
4738 
4739 	  if (errno == EACCES
4740 	      && newname_dev != oldname_dev)
4741 	    {
4742 	      DWORD attributes;
4743 	      /* The implementation of `rename' on Windows does not return
4744 		 errno = EXDEV when you are moving a directory to a
4745 		 different storage device (ex. logical disk).  It returns
4746 		 EACCES instead.  So here we handle such situations and
4747 		 return EXDEV.  */
4748 	      if ((attributes = GetFileAttributesW (temp_w)) != -1
4749 		  && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4750 		errno = EXDEV;
4751 	    }
4752 	  else if (errno == EEXIST && force)
4753 	    {
4754 	      DWORD attributes_old;
4755 	      DWORD attributes_new;
4756 
4757 	      if (_wchmod (newname_w, 0666) != 0)
4758 		return result;
4759 	      attributes_old = GetFileAttributesW (temp_w);
4760 	      attributes_new = GetFileAttributesW (newname_w);
4761 	      if (attributes_old != -1 && attributes_new != -1
4762 		  && ((attributes_old & FILE_ATTRIBUTE_DIRECTORY)
4763 		      != (attributes_new & FILE_ATTRIBUTE_DIRECTORY)))
4764 		{
4765 		  if ((attributes_old & FILE_ATTRIBUTE_DIRECTORY) != 0)
4766 		    errno = ENOTDIR;
4767 		  else
4768 		    errno = EISDIR;
4769 		  return -1;
4770 		}
4771 	      if ((attributes_new & FILE_ATTRIBUTE_DIRECTORY) != 0)
4772 		{
4773 		  if (_wrmdir (newname_w) != 0)
4774 		    return result;
4775 		}
4776 	      else if (_wunlink (newname_w) != 0)
4777 		return result;
4778 	      result = _wrename (temp_w, newname_w);
4779 	    }
4780 	  else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4781 		   && is_symlink (temp))
4782 	    {
4783 	      /* This is Windows prohibiting the user from creating a
4784 		 symlink in another place, since that requires
4785 		 privileges.  */
4786 	      errno = EPERM;
4787 	    }
4788 	}
4789     }
4790   else
4791     {
4792       char newname_a[MAX_PATH];
4793 
4794       if (!have_temp_a)
4795 	filename_to_ansi (temp, temp_a);
4796       filename_to_ansi (newname, newname_a);
4797       result = rename (temp_a, newname_a);
4798       if (result < 0)
4799 	{
4800 	  DWORD w32err = GetLastError ();
4801 
4802 	  if (errno == EACCES
4803 	      && newname_dev != oldname_dev)
4804 	    {
4805 	      DWORD attributes;
4806 	      if ((attributes = GetFileAttributesA (temp_a)) != -1
4807 		  && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4808 		errno = EXDEV;
4809 	    }
4810 	  else if (errno == EEXIST && force)
4811 	    {
4812 	      DWORD attributes_old;
4813 	      DWORD attributes_new;
4814 
4815 	      if (_chmod (newname_a, 0666) != 0)
4816 		return result;
4817 	      attributes_old = GetFileAttributesA (temp_a);
4818 	      attributes_new = GetFileAttributesA (newname_a);
4819 	      if (attributes_old != -1 && attributes_new != -1
4820 		  && ((attributes_old & FILE_ATTRIBUTE_DIRECTORY)
4821 		      != (attributes_new & FILE_ATTRIBUTE_DIRECTORY)))
4822 		{
4823 		  if ((attributes_old & FILE_ATTRIBUTE_DIRECTORY) != 0)
4824 		    errno = ENOTDIR;
4825 		  else
4826 		    errno = EISDIR;
4827 		  return -1;
4828 		}
4829 	      if ((attributes_new & FILE_ATTRIBUTE_DIRECTORY) != 0)
4830 		{
4831 		  if (_rmdir (newname_a) != 0)
4832 		    return result;
4833 		}
4834 	      else if (_unlink (newname_a) != 0)
4835 		return result;
4836 	      result = rename (temp_a, newname_a);
4837 	    }
4838 	  else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4839 		   && is_symlink (temp))
4840 	    errno = EPERM;
4841 	}
4842     }
4843 
4844   return result;
4845 }
4846 
4847 int
sys_rename(char const * old,char const * new)4848 sys_rename (char const *old, char const *new)
4849 {
4850   return sys_rename_replace (old, new, TRUE);
4851 }
4852 
4853 int
sys_rmdir(const char * path)4854 sys_rmdir (const char * path)
4855 {
4856   path = map_w32_filename (path, NULL);
4857 
4858   if (w32_unicode_filenames)
4859     {
4860       wchar_t path_w[MAX_PATH];
4861 
4862       filename_to_utf16 (path, path_w);
4863       return _wrmdir (path_w);
4864     }
4865   else
4866     {
4867       char path_a[MAX_PATH];
4868 
4869       filename_to_ansi (path, path_a);
4870       return _rmdir (path_a);
4871     }
4872 }
4873 
4874 int
sys_unlink(const char * path)4875 sys_unlink (const char * path)
4876 {
4877   int rmstatus, e;
4878 
4879   path = map_w32_filename (path, NULL);
4880 
4881   if (w32_unicode_filenames)
4882     {
4883       wchar_t path_w[MAX_PATH];
4884 
4885       filename_to_utf16 (path, path_w);
4886       /* On Unix, unlink works without write permission.  */
4887       _wchmod (path_w, 0666);
4888       rmstatus = _wunlink (path_w);
4889       e = errno;
4890       /* Symlinks to directories can only be deleted by _rmdir;
4891 	 _unlink returns EACCES.  */
4892       if (rmstatus != 0
4893 	  && errno == EACCES
4894 	  && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4895 	rmstatus = _wrmdir (path_w);
4896       else
4897 	errno = e;
4898     }
4899   else
4900     {
4901       char path_a[MAX_PATH];
4902 
4903       filename_to_ansi (path, path_a);
4904       _chmod (path_a, 0666);
4905       rmstatus = _unlink (path_a);
4906       e = errno;
4907       if (rmstatus != 0
4908 	  && errno == EACCES
4909 	  && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4910 	rmstatus = _rmdir (path_a);
4911       else
4912 	errno = e;
4913     }
4914 
4915   return rmstatus;
4916 }
4917 
4918 static FILETIME utc_base_ft;
4919 static ULONGLONG utc_base;  /* In 100ns units */
4920 static int init = 0;
4921 
4922 #define FILETIME_TO_U64(result, ft)        \
4923   do {                                     \
4924     ULARGE_INTEGER uiTemp;                 \
4925     uiTemp.LowPart = (ft).dwLowDateTime;   \
4926     uiTemp.HighPart = (ft).dwHighDateTime; \
4927     result = uiTemp.QuadPart;              \
4928   } while (0)
4929 
4930 static void
initialize_utc_base(void)4931 initialize_utc_base (void)
4932 {
4933   /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4934   SYSTEMTIME st;
4935 
4936   st.wYear = 1970;
4937   st.wMonth = 1;
4938   st.wDay = 1;
4939   st.wHour = 0;
4940   st.wMinute = 0;
4941   st.wSecond = 0;
4942   st.wMilliseconds = 0;
4943 
4944   SystemTimeToFileTime (&st, &utc_base_ft);
4945   FILETIME_TO_U64 (utc_base, utc_base_ft);
4946 }
4947 
4948 static time_t
convert_time(FILETIME ft)4949 convert_time (FILETIME ft)
4950 {
4951   ULONGLONG tmp;
4952 
4953   if (!init)
4954     {
4955       initialize_utc_base ();
4956       init = 1;
4957     }
4958 
4959   if (CompareFileTime (&ft, &utc_base_ft) < 0)
4960     return 0;
4961 
4962   FILETIME_TO_U64 (tmp, ft);
4963   return (time_t) ((tmp - utc_base) / 10000000L);
4964 }
4965 
4966 static void
convert_from_time_t(time_t time,FILETIME * pft)4967 convert_from_time_t (time_t time, FILETIME * pft)
4968 {
4969   ULARGE_INTEGER tmp;
4970 
4971   if (!init)
4972     {
4973       initialize_utc_base ();
4974       init = 1;
4975     }
4976 
4977   /* time in 100ns units since 1-Jan-1601 */
4978   tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4979   pft->dwHighDateTime = tmp.HighPart;
4980   pft->dwLowDateTime = tmp.LowPart;
4981 }
4982 
4983 static PSECURITY_DESCRIPTOR
get_file_security_desc_by_handle(HANDLE h)4984 get_file_security_desc_by_handle (HANDLE h)
4985 {
4986   PSECURITY_DESCRIPTOR psd = NULL;
4987   DWORD err;
4988   SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4989     | GROUP_SECURITY_INFORMATION  /* | DACL_SECURITY_INFORMATION */ ;
4990 
4991   err = get_security_info (h, SE_FILE_OBJECT, si,
4992 			   NULL, NULL, NULL, NULL, &psd);
4993   if (err != ERROR_SUCCESS)
4994     return NULL;
4995 
4996   return psd;
4997 }
4998 
4999 static PSECURITY_DESCRIPTOR
get_file_security_desc_by_name(const char * fname)5000 get_file_security_desc_by_name (const char *fname)
5001 {
5002   PSECURITY_DESCRIPTOR psd = NULL;
5003   DWORD sd_len, err;
5004   SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
5005     | GROUP_SECURITY_INFORMATION  /* | DACL_SECURITY_INFORMATION */ ;
5006 
5007   if (!get_file_security (fname, si, psd, 0, &sd_len))
5008     {
5009       err = GetLastError ();
5010       if (err != ERROR_INSUFFICIENT_BUFFER)
5011 	return NULL;
5012     }
5013 
5014   psd = xmalloc (sd_len);
5015   if (!get_file_security (fname, si, psd, sd_len, &sd_len))
5016     {
5017       xfree (psd);
5018       return NULL;
5019     }
5020 
5021   return psd;
5022 }
5023 
5024 static DWORD
get_rid(PSID sid)5025 get_rid (PSID sid)
5026 {
5027   unsigned n_subauthorities;
5028 
5029   /* Use the last sub-authority value of the RID, the relative
5030      portion of the SID, as user/group ID. */
5031   n_subauthorities = *get_sid_sub_authority_count (sid);
5032   if (n_subauthorities < 1)
5033     return 0;	/* the "World" RID */
5034   return *get_sid_sub_authority (sid, n_subauthorities - 1);
5035 }
5036 
5037 /* Caching SID and account values for faster lokup.  */
5038 
5039 struct w32_id {
5040   unsigned rid;
5041   struct w32_id *next;
5042   char name[GNLEN+1];
5043   unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
5044 };
5045 
5046 static struct w32_id *w32_idlist;
5047 
5048 static int
w32_cached_id(PSID sid,unsigned * id,char * name)5049 w32_cached_id (PSID sid, unsigned *id, char *name)
5050 {
5051   struct w32_id *tail, *found;
5052 
5053   for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
5054     {
5055       if (equal_sid ((PSID)tail->sid, sid))
5056 	{
5057 	  found = tail;
5058 	  break;
5059 	}
5060     }
5061   if (found)
5062     {
5063       *id = found->rid;
5064       strcpy (name, found->name);
5065       return 1;
5066     }
5067   else
5068     return 0;
5069 }
5070 
5071 static void
w32_add_to_cache(PSID sid,unsigned id,char * name)5072 w32_add_to_cache (PSID sid, unsigned id, char *name)
5073 {
5074   DWORD sid_len;
5075   struct w32_id *new_entry;
5076 
5077   /* We don't want to leave behind stale cache from when Emacs was
5078      dumped.  */
5079   if (initialized)
5080     {
5081       sid_len = get_length_sid (sid);
5082       new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
5083       if (new_entry)
5084 	{
5085 	  new_entry->rid = id;
5086 	  strcpy (new_entry->name, name);
5087 	  copy_sid (sid_len, (PSID)new_entry->sid, sid);
5088 	  new_entry->next = w32_idlist;
5089 	  w32_idlist = new_entry;
5090 	}
5091     }
5092 }
5093 
5094 #define UID 1
5095 #define GID 2
5096 
5097 static int
get_name_and_id(PSECURITY_DESCRIPTOR psd,unsigned * id,char * nm,int what)5098 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
5099 {
5100   PSID sid = NULL;
5101   BOOL dflt;
5102   SID_NAME_USE ignore;
5103   char name[UNLEN+1];
5104   DWORD name_len = sizeof (name);
5105   char domain[1024];
5106   DWORD domain_len = sizeof (domain);
5107   int use_dflt = 0;
5108   int result;
5109 
5110   if (what == UID)
5111     result = get_security_descriptor_owner (psd, &sid, &dflt);
5112   else if (what == GID)
5113     result = get_security_descriptor_group (psd, &sid, &dflt);
5114   else
5115     result = 0;
5116 
5117   if (!result || !is_valid_sid (sid))
5118     use_dflt = 1;
5119   else if (!w32_cached_id (sid, id, nm))
5120     {
5121       if (!lookup_account_sid (NULL, sid, name, &name_len,
5122 			       domain, &domain_len, &ignore)
5123 	  || name_len > UNLEN+1)
5124 	use_dflt = 1;
5125       else
5126 	{
5127 	  *id = get_rid (sid);
5128 	  strcpy (nm, name);
5129 	  w32_add_to_cache (sid, *id, name);
5130 	}
5131     }
5132   return use_dflt;
5133 }
5134 
5135 static void
get_file_owner_and_group(PSECURITY_DESCRIPTOR psd,struct stat * st)5136 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
5137 {
5138   int dflt_usr = 0, dflt_grp = 0;
5139 
5140   if (!psd)
5141     {
5142       dflt_usr = 1;
5143       dflt_grp = 1;
5144     }
5145   else
5146     {
5147       if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
5148 	dflt_usr = 1;
5149       if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
5150 	dflt_grp = 1;
5151     }
5152   /* Consider files to belong to current user/group, if we cannot get
5153      more accurate information.  */
5154   if (dflt_usr)
5155     {
5156       st->st_uid = dflt_passwd.pw_uid;
5157       strcpy (st->st_uname, dflt_passwd.pw_name);
5158     }
5159   if (dflt_grp)
5160     {
5161       st->st_gid = dflt_passwd.pw_gid;
5162       strcpy (st->st_gname, dflt_group.gr_name);
5163     }
5164 }
5165 
5166 /* Return non-zero if NAME is a potentially slow filesystem.  */
5167 int is_slow_fs (const char *);
5168 
5169 int
is_slow_fs(const char * name)5170 is_slow_fs (const char *name)
5171 {
5172   char drive_root[4];
5173   UINT devtype;
5174 
5175   if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
5176     devtype = DRIVE_REMOTE;	   /* assume UNC name is remote */
5177   else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
5178     devtype = GetDriveType (NULL); /* use root of current drive */
5179   else
5180     {
5181       /* GetDriveType needs the root directory of the drive.  */
5182       strncpy (drive_root, name, 2);
5183       drive_root[2] = '\\';
5184       drive_root[3] = '\0';
5185       devtype = GetDriveType (drive_root);
5186     }
5187   return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
5188 }
5189 
5190 /* If this is non-zero, the caller wants accurate information about
5191    file's owner and group, which could be expensive to get.  dired.c
5192    uses this flag when needed for the job at hand.  */
5193 int w32_stat_get_owner_group;
5194 
5195 /* MSVC stat function can't cope with UNC names and has other bugs, so
5196    replace it with our own.  This also allows us to calculate consistent
5197    inode values and owner/group without hacks in the main Emacs code,
5198    and support file names encoded in UTF-8. */
5199 
5200 static int
stat_worker(const char * path,struct stat * buf,int follow_symlinks)5201 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
5202 {
5203   char *name, *save_name, *r;
5204   WIN32_FIND_DATAW wfd_w;
5205   WIN32_FIND_DATAA wfd_a;
5206   HANDLE fh;
5207   unsigned __int64 fake_inode = 0;
5208   int permission;
5209   int len;
5210   int rootdir = FALSE;
5211   PSECURITY_DESCRIPTOR psd = NULL;
5212   int is_a_symlink = 0;
5213   DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
5214   DWORD access_rights = 0;
5215   DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
5216   FILETIME ctime, atime, wtime;
5217   wchar_t name_w[MAX_PATH];
5218   char name_a[MAX_PATH];
5219 
5220   if (path == NULL || buf == NULL)
5221     {
5222       errno = EFAULT;
5223       return -1;
5224     }
5225 
5226   save_name = name = (char *) map_w32_filename (path, &path);
5227   /* Must be valid filename, no wild cards or other invalid
5228      characters.  */
5229   if (strpbrk (name, "*?|<>\""))
5230     {
5231       errno = ENOENT;
5232       return -1;
5233     }
5234 
5235   len = strlen (name);
5236   /* Allocate 1 extra byte so that we could append a slash to a root
5237      directory, down below.  */
5238   name = strcpy (alloca (len + 2), name);
5239 
5240   /* Avoid a somewhat costly call to is_symlink if the filesystem
5241      doesn't support symlinks.  */
5242   if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5243     is_a_symlink = is_symlink (name);
5244 
5245   /* Plan A: Open the file and get all the necessary information via
5246      the resulting handle.  This solves several issues in one blow:
5247 
5248       . retrieves attributes for the target of a symlink, if needed
5249       . gets attributes of root directories and symlinks pointing to
5250         root directories, thus avoiding the need for special-casing
5251         these and detecting them by examining the file-name format
5252       . retrieves more accurate attributes (e.g., non-zero size for
5253         some directories, esp. directories that are junction points)
5254       . correctly resolves "c:/..", "/.." and similar file names
5255       . avoids run-time penalties for 99% of use cases
5256 
5257      Plan A is always tried first, unless the user asked not to (but
5258      if the file is a symlink and we need to follow links, we try Plan
5259      A even if the user asked not to).
5260 
5261      If Plan A fails, we go to Plan B (below), where various
5262      potentially expensive techniques must be used to handle "special"
5263      files such as UNC volumes etc.  */
5264   if (!(NILP (Vw32_get_true_file_attributes)
5265 	|| (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
5266       /* Following symlinks requires getting the info by handle.  */
5267       || (is_a_symlink && follow_symlinks))
5268     {
5269       BY_HANDLE_FILE_INFORMATION info;
5270 
5271       if (is_a_symlink && !follow_symlinks)
5272 	file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
5273       /* READ_CONTROL access rights are required to get security info
5274 	 by handle.  But if the OS doesn't support security in the
5275 	 first place, we don't need to try.  */
5276       if (is_windows_9x () != TRUE)
5277 	access_rights |= READ_CONTROL;
5278 
5279       if (w32_unicode_filenames)
5280 	{
5281 	  filename_to_utf16 (name, name_w);
5282 	  fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
5283 			   file_flags, NULL);
5284 	  /* If CreateFile fails with READ_CONTROL, try again with
5285 	     zero as access rights.  */
5286 	  if (fh == INVALID_HANDLE_VALUE && access_rights)
5287 	    fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
5288 			     file_flags, NULL);
5289 	}
5290       else
5291 	{
5292 	  filename_to_ansi (name, name_a);
5293 	  fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
5294 			   file_flags, NULL);
5295 	  if (fh == INVALID_HANDLE_VALUE && access_rights)
5296 	    fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
5297 			     file_flags, NULL);
5298 	}
5299       if (fh == INVALID_HANDLE_VALUE)
5300 	goto no_true_file_attributes;
5301 
5302       /* This is more accurate in terms of getting the correct number
5303 	 of links, but is quite slow (it is noticeable when Emacs is
5304 	 making a list of file name completions). */
5305       if (GetFileInformationByHandle (fh, &info))
5306 	{
5307 	  nlinks = info.nNumberOfLinks;
5308 	  /* Might as well use file index to fake inode values, but this
5309 	     is not guaranteed to be unique unless we keep a handle open
5310 	     all the time (even then there are situations where it is
5311 	     not unique).  Reputedly, there are at most 48 bits of info
5312 	     (on NTFS, presumably less on FAT). */
5313 	  fake_inode = info.nFileIndexHigh;
5314 	  fake_inode <<= 32;
5315 	  fake_inode += info.nFileIndexLow;
5316 	  serialnum = info.dwVolumeSerialNumber;
5317 	  fs_high = info.nFileSizeHigh;
5318 	  fs_low  = info.nFileSizeLow;
5319 	  ctime = info.ftCreationTime;
5320 	  atime = info.ftLastAccessTime;
5321 	  wtime = info.ftLastWriteTime;
5322 	  fattrs = info.dwFileAttributes;
5323 	}
5324       else
5325 	{
5326 	  /* We don't go to Plan B here, because it's not clear that
5327 	     it's a good idea.  The only known use case where
5328 	     CreateFile succeeds, but GetFileInformationByHandle fails
5329 	     (with ERROR_INVALID_FUNCTION) is for character devices
5330 	     such as NUL, PRN, etc.  For these, switching to Plan B is
5331 	     a net loss, because we lose the character device
5332 	     attribute returned by GetFileType below (FindFirstFile
5333 	     doesn't set that bit in the attributes), and the other
5334 	     fields don't make sense for character devices anyway.
5335 	     Emacs doesn't really care for non-file entities in the
5336 	     context of l?stat, so neither do we.  */
5337 
5338 	  /* w32err is assigned so one could put a breakpoint here and
5339 	     examine its value, when GetFileInformationByHandle
5340 	     fails. */
5341 	  DWORD w32err = GetLastError ();
5342 
5343 	  switch (w32err)
5344 	    {
5345 	    case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
5346 	      errno = ENOENT;
5347 	      return -1;
5348 	    }
5349 	}
5350 
5351       /* Test for a symlink before testing for a directory, since
5352 	 symlinks to directories have the directory bit set, but we
5353 	 don't want them to appear as directories.  */
5354       if (is_a_symlink && !follow_symlinks)
5355 	buf->st_mode = S_IFLNK;
5356       else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5357 	buf->st_mode = S_IFDIR;
5358       else
5359 	{
5360 	  DWORD ftype = GetFileType (fh);
5361 
5362 	  switch (ftype)
5363 	    {
5364 	    case FILE_TYPE_DISK:
5365 	      buf->st_mode = S_IFREG;
5366 	      break;
5367 	    case FILE_TYPE_PIPE:
5368 	      buf->st_mode = S_IFIFO;
5369 	      break;
5370 	    case FILE_TYPE_CHAR:
5371 	    case FILE_TYPE_UNKNOWN:
5372 	    default:
5373 	      buf->st_mode = S_IFCHR;
5374 	    }
5375 	}
5376       /* We produce the fallback owner and group data, based on the
5377 	 current user that runs Emacs, in the following cases:
5378 
5379 	  . caller didn't request owner and group info
5380 	  . this is Windows 9X
5381 	  . getting security by handle failed, and we need to produce
5382 	    information for the target of a symlink (this is better
5383 	    than producing a potentially misleading info about the
5384 	    symlink itself)
5385 
5386 	 If getting security by handle fails, and we don't need to
5387 	 resolve symlinks, we try getting security by name.  */
5388       if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5389 	get_file_owner_and_group (NULL, buf);
5390       else
5391 	{
5392 	  psd = get_file_security_desc_by_handle (fh);
5393 	  if (psd)
5394 	    {
5395 	      get_file_owner_and_group (psd, buf);
5396 	      LocalFree (psd);
5397 	    }
5398 	  else if (!(is_a_symlink && follow_symlinks))
5399 	    {
5400 	      psd = get_file_security_desc_by_name (name);
5401 	      get_file_owner_and_group (psd, buf);
5402 	      xfree (psd);
5403 	    }
5404 	  else
5405 	    get_file_owner_and_group (NULL, buf);
5406 	}
5407       CloseHandle (fh);
5408     }
5409   else
5410     {
5411     no_true_file_attributes:
5412       /* Plan B: Either getting a handle on the file failed, or the
5413 	 caller explicitly asked us to not bother making this
5414 	 information more accurate.
5415 
5416 	 Implementation note: In Plan B, we never bother to resolve
5417 	 symlinks, even if we got here because we tried Plan A and
5418 	 failed.  That's because, even if the caller asked for extra
5419 	 precision by setting Vw32_get_true_file_attributes to t,
5420 	 resolving symlinks requires acquiring a file handle to the
5421 	 symlink, which we already know will fail.  And if the user
5422 	 did not ask for extra precision, resolving symlinks will fly
5423 	 in the face of that request, since the user then wants the
5424 	 lightweight version of the code.  */
5425       rootdir = (path >= save_name + len - 1
5426 		 && (IS_DIRECTORY_SEP (*path) || *path == 0));
5427 
5428       /* If name is "c:/.." or "/.." then stat "c:/" or "/".  */
5429       r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
5430       if (IS_DIRECTORY_SEP (r[0])
5431 	  && r[1] == '.' && r[2] == '.' && r[3] == '\0')
5432 	r[1] = r[2] = '\0';
5433 
5434       /* Note: If NAME is a symlink to the root of a UNC volume
5435 	 (i.e. "\\SERVER"), we will not detect that here, and we will
5436 	 return data about the symlink as result of FindFirst below.
5437 	 This is unfortunate, but that marginal use case does not
5438 	 justify a call to chase_symlinks which would impose a penalty
5439 	 on all the other use cases.  (We get here for symlinks to
5440 	 roots of UNC volumes because CreateFile above fails for them,
5441 	 unlike with symlinks to root directories X:\ of drives.)  */
5442       if (is_unc_volume (name))
5443 	{
5444 	  fattrs = unc_volume_file_attributes (name);
5445 	  if (fattrs == -1)
5446 	    return -1;
5447 
5448 	  ctime = atime = wtime = utc_base_ft;
5449 	}
5450       else if (rootdir)
5451 	{
5452 	  /* Make sure root directories end in a slash.  */
5453 	  if (!IS_DIRECTORY_SEP (name[len-1]))
5454 	    strcpy (name + len, "\\");
5455 	  if (GetDriveType (name) < 2)
5456 	    {
5457 	      errno = ENOENT;
5458 	      return -1;
5459 	    }
5460 
5461 	  fattrs = FILE_ATTRIBUTE_DIRECTORY;
5462 	  ctime = atime = wtime = utc_base_ft;
5463 	}
5464       else
5465 	{
5466 	  int have_wfd = -1;
5467 
5468 	  /* Make sure non-root directories do NOT end in a slash,
5469 	     otherwise FindFirstFile might fail.  */
5470 	  if (IS_DIRECTORY_SEP (name[len-1]))
5471 	    name[len - 1] = 0;
5472 
5473 	  /* (This is hacky, but helps when doing file completions on
5474 	     network drives.)  Optimize by using information available from
5475 	     active readdir if possible.  */
5476 	  len = strlen (dir_pathname);
5477 	  if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
5478 	    len--;
5479 	  if (dir_find_handle != INVALID_HANDLE_VALUE
5480 	      && last_dir_find_data != -1
5481 	      && !(is_a_symlink && follow_symlinks)
5482 	      /* The 2 file-name comparisons below support only ASCII
5483 		 characters, and will lose (compare not equal) when
5484 		 the file names include non-ASCII characters that are
5485 		 the same but for the case.  However, doing this
5486 		 properly involves: (a) converting both file names to
5487 		 UTF-16, (b) lower-casing both names using CharLowerW,
5488 		 and (c) comparing the results; this would be quite a
5489 		 bit slower, whereas Plan B is for users who want
5490 		 lightweight albeit inaccurate version of 'stat'.  */
5491 	      && c_strncasecmp (save_name, dir_pathname, len) == 0
5492 	      && IS_DIRECTORY_SEP (name[len])
5493 	      && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
5494 	    {
5495 	      have_wfd = last_dir_find_data;
5496 	      /* This was the last entry returned by readdir.  */
5497 	      if (last_dir_find_data == DIR_FIND_DATA_W)
5498 		wfd_w = dir_find_data_w;
5499 	      else
5500 		wfd_a = dir_find_data_a;
5501 	    }
5502 	  else
5503 	    {
5504 	      logon_network_drive (name);
5505 
5506 	      if (w32_unicode_filenames)
5507 		{
5508 		  filename_to_utf16 (name, name_w);
5509 		  fh = FindFirstFileW (name_w, &wfd_w);
5510 		  have_wfd = DIR_FIND_DATA_W;
5511 		}
5512 	      else
5513 		{
5514 		  filename_to_ansi (name, name_a);
5515 		  /* If NAME includes characters not representable by
5516 		     the current ANSI codepage, filename_to_ansi
5517 		     usually replaces them with a '?'.  We don't want
5518 		     to let FindFirstFileA interpret those as wildcards,
5519 		     and "succeed", returning us data from some random
5520 		     file in the same directory.  */
5521 		  if (_mbspbrk (name_a, "?"))
5522 		    fh = INVALID_HANDLE_VALUE;
5523 		  else
5524 		    fh = FindFirstFileA (name_a, &wfd_a);
5525 		  have_wfd = DIR_FIND_DATA_A;
5526 		}
5527 	      if (fh == INVALID_HANDLE_VALUE)
5528 		{
5529 		  errno = ENOENT;
5530 		  return -1;
5531 		}
5532 	      FindClose (fh);
5533 	    }
5534 	  /* Note: if NAME is a symlink, the information we get from
5535 	     FindFirstFile is for the symlink, not its target.  */
5536 	  if (have_wfd == DIR_FIND_DATA_W)
5537 	    {
5538 	      fattrs = wfd_w.dwFileAttributes;
5539 	      ctime = wfd_w.ftCreationTime;
5540 	      atime = wfd_w.ftLastAccessTime;
5541 	      wtime = wfd_w.ftLastWriteTime;
5542 	      fs_high = wfd_w.nFileSizeHigh;
5543 	      fs_low = wfd_w.nFileSizeLow;
5544 	    }
5545 	  else
5546 	    {
5547 	      fattrs = wfd_a.dwFileAttributes;
5548 	      ctime = wfd_a.ftCreationTime;
5549 	      atime = wfd_a.ftLastAccessTime;
5550 	      wtime = wfd_a.ftLastWriteTime;
5551 	      fs_high = wfd_a.nFileSizeHigh;
5552 	      fs_low = wfd_a.nFileSizeLow;
5553 	    }
5554 	  fake_inode = 0;
5555 	  nlinks = 1;
5556 	  serialnum = volume_info.serialnum;
5557 	}
5558       if (is_a_symlink && !follow_symlinks)
5559 	buf->st_mode = S_IFLNK;
5560       else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5561 	buf->st_mode = S_IFDIR;
5562       else
5563 	buf->st_mode = S_IFREG;
5564 
5565       get_file_owner_and_group (NULL, buf);
5566     }
5567 
5568   buf->st_ino = fake_inode;
5569 
5570   buf->st_dev = serialnum;
5571   buf->st_rdev = serialnum;
5572 
5573   buf->st_size = fs_high;
5574   buf->st_size <<= 32;
5575   buf->st_size += fs_low;
5576   buf->st_nlink = nlinks;
5577 
5578   /* Convert timestamps to Unix format. */
5579   buf->st_mtime = convert_time (wtime);
5580   buf->st_atime = convert_time (atime);
5581   if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5582   buf->st_ctime = convert_time (ctime);
5583   if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5584 
5585   /* determine rwx permissions */
5586   if (is_a_symlink && !follow_symlinks)
5587     permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5588   else
5589     {
5590       if (fattrs & FILE_ATTRIBUTE_READONLY)
5591 	permission = S_IREAD;
5592       else
5593 	permission = S_IREAD | S_IWRITE;
5594 
5595       if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5596 	permission |= S_IEXEC;
5597       else if (is_exec (name))
5598 	permission |= S_IEXEC;
5599     }
5600 
5601   buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5602 
5603   return 0;
5604 }
5605 
5606 int
stat(const char * path,struct stat * buf)5607 stat (const char * path, struct stat * buf)
5608 {
5609   return stat_worker (path, buf, 1);
5610 }
5611 
5612 int
lstat(const char * path,struct stat * buf)5613 lstat (const char * path, struct stat * buf)
5614 {
5615   return stat_worker (path, buf, 0);
5616 }
5617 
5618 int
fstatat(int fd,char const * name,struct stat * st,int flags)5619 fstatat (int fd, char const *name, struct stat *st, int flags)
5620 {
5621   /* Rely on a hack: an open directory is modeled as file descriptor 0.
5622      This is good enough for the current usage in Emacs, but is fragile.
5623 
5624      FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5625      Gnulib does this and can serve as a model.  */
5626   char fullname[MAX_UTF8_PATH];
5627 
5628   if (fd != AT_FDCWD)
5629     {
5630       char lastc = dir_pathname[strlen (dir_pathname) - 1];
5631 
5632       if (_snprintf (fullname, sizeof fullname, "%s%s%s",
5633 		     dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
5634 	  < 0)
5635 	{
5636 	  errno = ENAMETOOLONG;
5637 	  return -1;
5638 	}
5639       name = fullname;
5640     }
5641 
5642   return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5643 }
5644 
5645 /* Provide fstat and utime as well as stat for consistent handling of
5646    file timestamps. */
5647 int
fstat(int desc,struct stat * buf)5648 fstat (int desc, struct stat * buf)
5649 {
5650   HANDLE fh = (HANDLE) _get_osfhandle (desc);
5651   BY_HANDLE_FILE_INFORMATION info;
5652   unsigned __int64 fake_inode;
5653   int permission;
5654 
5655   switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5656     {
5657     case FILE_TYPE_DISK:
5658       buf->st_mode = S_IFREG;
5659       if (!GetFileInformationByHandle (fh, &info))
5660 	{
5661 	  errno = EACCES;
5662 	  return -1;
5663 	}
5664       break;
5665     case FILE_TYPE_PIPE:
5666       buf->st_mode = S_IFIFO;
5667       goto non_disk;
5668     case FILE_TYPE_CHAR:
5669     case FILE_TYPE_UNKNOWN:
5670     default:
5671       buf->st_mode = S_IFCHR;
5672     non_disk:
5673       memset (&info, 0, sizeof (info));
5674       info.dwFileAttributes = 0;
5675       info.ftCreationTime = utc_base_ft;
5676       info.ftLastAccessTime = utc_base_ft;
5677       info.ftLastWriteTime = utc_base_ft;
5678     }
5679 
5680   if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5681       buf->st_mode = S_IFDIR;
5682 
5683   buf->st_nlink = info.nNumberOfLinks;
5684   /* Might as well use file index to fake inode values, but this
5685      is not guaranteed to be unique unless we keep a handle open
5686      all the time (even then there are situations where it is
5687      not unique).  Reputedly, there are at most 48 bits of info
5688      (on NTFS, presumably less on FAT). */
5689   fake_inode = info.nFileIndexHigh;
5690   fake_inode <<= 32;
5691   fake_inode += info.nFileIndexLow;
5692 
5693   /* MSVC defines _ino_t to be short; other libc's might not.  */
5694   if (sizeof (buf->st_ino) == 2)
5695     buf->st_ino = fake_inode ^ (fake_inode >> 16);
5696   else
5697     buf->st_ino = fake_inode;
5698 
5699   /* If the caller so requested, get the true file owner and group.
5700      Otherwise, consider the file to belong to the current user.  */
5701   if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5702     get_file_owner_and_group (NULL, buf);
5703   else
5704     {
5705       PSECURITY_DESCRIPTOR psd = NULL;
5706 
5707       psd = get_file_security_desc_by_handle (fh);
5708       if (psd)
5709 	{
5710 	  get_file_owner_and_group (psd, buf);
5711 	  LocalFree (psd);
5712 	}
5713       else
5714 	get_file_owner_and_group (NULL, buf);
5715     }
5716 
5717   buf->st_dev = info.dwVolumeSerialNumber;
5718   buf->st_rdev = info.dwVolumeSerialNumber;
5719 
5720   buf->st_size = info.nFileSizeHigh;
5721   buf->st_size <<= 32;
5722   buf->st_size += info.nFileSizeLow;
5723 
5724   /* Convert timestamps to Unix format. */
5725   buf->st_mtime = convert_time (info.ftLastWriteTime);
5726   buf->st_atime = convert_time (info.ftLastAccessTime);
5727   if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5728   buf->st_ctime = convert_time (info.ftCreationTime);
5729   if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5730 
5731   /* determine rwx permissions */
5732   if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5733     permission = S_IREAD;
5734   else
5735     permission = S_IREAD | S_IWRITE;
5736 
5737   if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5738     permission |= S_IEXEC;
5739   else
5740     {
5741 #if 0 /* no way of knowing the filename */
5742       char * p = strrchr (name, '.');
5743       if (p != NULL &&
5744 	  (xstrcasecmp (p, ".exe") == 0 ||
5745 	   xstrcasecmp (p, ".com") == 0 ||
5746 	   xstrcasecmp (p, ".bat") == 0 ||
5747 	   xstrcasecmp (p, ".cmd") == 0))
5748 	permission |= S_IEXEC;
5749 #endif
5750     }
5751 
5752   buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5753 
5754   return 0;
5755 }
5756 
5757 /* A version of 'utime' which handles directories as well as
5758    files.  */
5759 
5760 int
utime(const char * name,struct utimbuf * times)5761 utime (const char *name, struct utimbuf *times)
5762 {
5763   struct utimbuf deftime;
5764   HANDLE fh;
5765   FILETIME mtime;
5766   FILETIME atime;
5767 
5768   if (times == NULL)
5769     {
5770       deftime.modtime = deftime.actime = time (NULL);
5771       times = &deftime;
5772     }
5773 
5774   if (w32_unicode_filenames)
5775     {
5776       wchar_t name_utf16[MAX_PATH];
5777 
5778       if (filename_to_utf16 (name, name_utf16) != 0)
5779 	return -1;	/* errno set by filename_to_utf16 */
5780 
5781       /* Need write access to set times.  */
5782       fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5783 			/* If NAME specifies a directory, FILE_SHARE_DELETE
5784 			   allows other processes to delete files inside it,
5785 			   while we have the directory open.  */
5786 			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5787 			0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5788     }
5789   else
5790     {
5791       char name_ansi[MAX_PATH];
5792 
5793       if (filename_to_ansi (name, name_ansi) != 0)
5794 	return -1;	/* errno set by filename_to_ansi */
5795 
5796       fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5797 			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5798 			0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5799     }
5800   if (fh != INVALID_HANDLE_VALUE)
5801     {
5802       convert_from_time_t (times->actime, &atime);
5803       convert_from_time_t (times->modtime, &mtime);
5804       if (!SetFileTime (fh, NULL, &atime, &mtime))
5805 	{
5806 	  CloseHandle (fh);
5807 	  errno = EACCES;
5808 	  return -1;
5809 	}
5810       CloseHandle (fh);
5811     }
5812   else
5813     {
5814       DWORD err = GetLastError ();
5815 
5816       switch (err)
5817 	{
5818 	case ERROR_FILE_NOT_FOUND:
5819 	case ERROR_PATH_NOT_FOUND:
5820 	case ERROR_INVALID_DRIVE:
5821 	case ERROR_BAD_NETPATH:
5822 	case ERROR_DEV_NOT_EXIST:
5823 	  /* ERROR_INVALID_NAME is the error CreateFile sets when the
5824 	     file name includes ?s, i.e. translation to ANSI failed.  */
5825 	case ERROR_INVALID_NAME:
5826 	  errno = ENOENT;
5827 	  break;
5828 	case ERROR_TOO_MANY_OPEN_FILES:
5829 	  errno = ENFILE;
5830 	  break;
5831 	case ERROR_ACCESS_DENIED:
5832 	case ERROR_SHARING_VIOLATION:
5833 	  errno = EACCES;
5834 	  break;
5835 	default:
5836 	  errno = EINVAL;
5837 	  break;
5838 	}
5839       return -1;
5840     }
5841   return 0;
5842 }
5843 
5844 int
sys_umask(int mode)5845 sys_umask (int mode)
5846 {
5847   static int current_mask;
5848   int retval, arg = 0;
5849 
5850   /* The only bit we really support is the write bit.  Files are
5851      always readable on MS-Windows, and the execute bit does not exist
5852      at all.  */
5853   /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
5854      to prevent access by other users on NTFS.  */
5855   if ((mode & S_IWRITE) != 0)
5856     arg |= S_IWRITE;
5857 
5858   retval = _umask (arg);
5859   /* Merge into the return value the bits they've set the last time,
5860      which msvcrt.dll ignores and never returns.  Emacs insists on its
5861      notion of mask being identical to what we return.  */
5862   retval |= (current_mask & ~S_IWRITE);
5863   current_mask = mode;
5864 
5865   return retval;
5866 }
5867 
5868 
5869 /* Symlink-related functions.  */
5870 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5871 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5872 #endif
5873 
5874 int
symlink(char const * filename,char const * linkname)5875 symlink (char const *filename, char const *linkname)
5876 {
5877   char linkfn[MAX_UTF8_PATH], *tgtfn;
5878   DWORD flags = 0;
5879   int dir_access, filename_ends_in_slash;
5880 
5881   /* Diagnostics follows Posix as much as possible.  */
5882   if (filename == NULL || linkname == NULL)
5883     {
5884       errno = EFAULT;
5885       return -1;
5886     }
5887   if (!*filename)
5888     {
5889       errno = ENOENT;
5890       return -1;
5891     }
5892   if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5893     {
5894       errno = ENAMETOOLONG;
5895       return -1;
5896     }
5897 
5898   strcpy (linkfn, map_w32_filename (linkname, NULL));
5899   if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5900     {
5901       errno = EPERM;
5902       return -1;
5903     }
5904 
5905   /* Note: since empty FILENAME was already rejected, we can safely
5906      refer to FILENAME[1].  */
5907   if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5908     {
5909       /* Non-absolute FILENAME is understood as being relative to
5910 	 LINKNAME's directory.  We need to prepend that directory to
5911 	 FILENAME to get correct results from faccessat below, since
5912 	 otherwise it will interpret FILENAME relative to the
5913 	 directory where the Emacs process runs.  Note that
5914 	 make-symbolic-link always makes sure LINKNAME is a fully
5915 	 expanded file name.  */
5916       char tem[MAX_UTF8_PATH];
5917       char *p = linkfn + strlen (linkfn);
5918 
5919       while (p > linkfn && !IS_ANY_SEP (p[-1]))
5920 	p--;
5921       if (p > linkfn)
5922 	strncpy (tem, linkfn, p - linkfn);
5923       strcpy (tem + (p - linkfn), filename);
5924       dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5925     }
5926   else
5927     dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5928 
5929   /* Since Windows distinguishes between symlinks to directories and
5930      to files, we provide a kludgy feature: if FILENAME doesn't
5931      exist, but ends in a slash, we create a symlink to directory.  If
5932      FILENAME exists and is a directory, we always create a symlink to
5933      directory.  */
5934   filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5935   if (dir_access == 0 || filename_ends_in_slash)
5936     flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5937 
5938   tgtfn = (char *)map_w32_filename (filename, NULL);
5939   if (filename_ends_in_slash)
5940     tgtfn[strlen (tgtfn) - 1] = '\0';
5941 
5942   errno = 0;
5943   if (!create_symbolic_link (linkfn, tgtfn, flags))
5944     {
5945       /* ENOSYS is set by create_symbolic_link, when it detects that
5946 	 the OS doesn't support the CreateSymbolicLink API.  */
5947       if (errno != ENOSYS)
5948 	{
5949 	  DWORD w32err = GetLastError ();
5950 
5951 	  switch (w32err)
5952 	    {
5953 	      /* ERROR_SUCCESS is sometimes returned when LINKFN and
5954 		 TGTFN point to the same file name, go figure.  */
5955 	    case ERROR_SUCCESS:
5956 	    case ERROR_FILE_EXISTS:
5957 	      errno = EEXIST;
5958 	      break;
5959 	    case ERROR_ACCESS_DENIED:
5960 	      errno = EACCES;
5961 	      break;
5962 	    case ERROR_FILE_NOT_FOUND:
5963 	    case ERROR_PATH_NOT_FOUND:
5964 	    case ERROR_BAD_NETPATH:
5965 	    case ERROR_INVALID_REPARSE_DATA:
5966 	      errno = ENOENT;
5967 	      break;
5968 	    case ERROR_DIRECTORY:
5969 	      errno = EISDIR;
5970 	      break;
5971 	    case ERROR_PRIVILEGE_NOT_HELD:
5972 	    case ERROR_NOT_ALL_ASSIGNED:
5973 	      errno = EPERM;
5974 	      break;
5975 	    case ERROR_DISK_FULL:
5976 	      errno = ENOSPC;
5977 	      break;
5978 	    default:
5979 	      errno = EINVAL;
5980 	      break;
5981 	    }
5982 	}
5983       return -1;
5984     }
5985   return 0;
5986 }
5987 
5988 /* A quick inexpensive test of whether FILENAME identifies a file that
5989    is a symlink.  Returns non-zero if it is, zero otherwise.  FILENAME
5990    must already be in the normalized form returned by
5991    map_w32_filename.  If the symlink is to a directory, the
5992    FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
5993 
5994    Note: for repeated operations on many files, it is best to test
5995    whether the underlying volume actually supports symlinks, by
5996    testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5997    avoid the call to this function if it doesn't.  That's because the
5998    call to GetFileAttributes takes a non-negligible time, especially
5999    on non-local or removable filesystems.  See stat_worker for an
6000    example of how to do that.  */
6001 static int
is_symlink(const char * filename)6002 is_symlink (const char *filename)
6003 {
6004   DWORD attrs;
6005   wchar_t filename_w[MAX_PATH];
6006   char filename_a[MAX_PATH];
6007   WIN32_FIND_DATAW wfdw;
6008   WIN32_FIND_DATAA wfda;
6009   HANDLE fh;
6010   int attrs_mean_symlink;
6011 
6012   if (w32_unicode_filenames)
6013     {
6014       filename_to_utf16 (filename, filename_w);
6015       attrs = GetFileAttributesW (filename_w);
6016     }
6017   else
6018     {
6019       filename_to_ansi (filename, filename_a);
6020       attrs = GetFileAttributesA (filename_a);
6021     }
6022   if (attrs == -1)
6023     {
6024       DWORD w32err = GetLastError ();
6025 
6026       switch (w32err)
6027 	{
6028 	case ERROR_BAD_NETPATH:	/* network share, can't be a symlink */
6029 	  break;
6030 	case ERROR_ACCESS_DENIED:
6031 	  errno = EACCES;
6032 	  break;
6033 	case ERROR_FILE_NOT_FOUND:
6034 	case ERROR_PATH_NOT_FOUND:
6035 	default:
6036 	  errno = ENOENT;
6037 	  break;
6038 	}
6039       return 0;
6040     }
6041   if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
6042     return 0;
6043   logon_network_drive (filename);
6044   if (w32_unicode_filenames)
6045     {
6046       fh = FindFirstFileW (filename_w, &wfdw);
6047       attrs_mean_symlink =
6048 	(wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
6049 	&& (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
6050       if (attrs_mean_symlink)
6051 	attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
6052     }
6053   else if (_mbspbrk (filename_a, "?"))
6054     {
6055       /* filename_to_ansi failed to convert the file name.  */
6056       errno = ENOENT;
6057       return 0;
6058     }
6059   else
6060     {
6061       fh = FindFirstFileA (filename_a, &wfda);
6062       attrs_mean_symlink =
6063 	(wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
6064 	&& (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
6065       if (attrs_mean_symlink)
6066 	attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
6067     }
6068   if (fh == INVALID_HANDLE_VALUE)
6069     return 0;
6070   FindClose (fh);
6071   return attrs_mean_symlink;
6072 }
6073 
6074 /* If NAME identifies a symbolic link, copy into BUF the file name of
6075    the symlink's target.  Copy at most BUF_SIZE bytes, and do NOT
6076    NUL-terminate the target name, even if it fits.  Return the number
6077    of bytes copied, or -1 if NAME is not a symlink or any error was
6078    encountered while resolving it.  The file name copied into BUF is
6079    encoded in the current ANSI codepage.  */
6080 ssize_t
readlink(const char * name,char * buf,size_t buf_size)6081 readlink (const char *name, char *buf, size_t buf_size)
6082 {
6083   const char *path;
6084   TOKEN_PRIVILEGES privs;
6085   int restore_privs = 0;
6086   HANDLE sh;
6087   ssize_t retval;
6088   char resolved[MAX_UTF8_PATH];
6089 
6090   if (name == NULL)
6091     {
6092       errno = EFAULT;
6093       return -1;
6094     }
6095   if (!*name)
6096     {
6097       errno = ENOENT;
6098       return -1;
6099     }
6100 
6101   path = map_w32_filename (name, NULL);
6102 
6103   if (strlen (path) > MAX_UTF8_PATH)
6104     {
6105       errno = ENAMETOOLONG;
6106       return -1;
6107     }
6108 
6109   errno = 0;
6110   if (is_windows_9x () == TRUE
6111       || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
6112       || !is_symlink (path))
6113     {
6114       if (!errno)
6115 	errno = EINVAL;	/* not a symlink */
6116       return -1;
6117     }
6118 
6119   /* Done with simple tests, now we're in for some _real_ work.  */
6120   if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
6121     restore_privs = 1;
6122   /* Implementation note: From here and onward, don't return early,
6123      since that will fail to restore the original set of privileges of
6124      the calling thread.  */
6125 
6126   retval = -1;	/* not too optimistic, are we? */
6127 
6128   /* Note: In the next call to CreateFile, we use zero as the 2nd
6129      argument because, when the symlink is a hidden/system file,
6130      e.g. 'C:\Users\All Users', GENERIC_READ fails with
6131      ERROR_ACCESS_DENIED.  Zero seems to work just fine, both for file
6132      and directory symlinks.  */
6133   if (w32_unicode_filenames)
6134     {
6135       wchar_t path_w[MAX_PATH];
6136 
6137       filename_to_utf16 (path, path_w);
6138       sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
6139 			FILE_FLAG_OPEN_REPARSE_POINT
6140 			| FILE_FLAG_BACKUP_SEMANTICS,
6141 			NULL);
6142     }
6143   else
6144     {
6145       char path_a[MAX_PATH];
6146 
6147       filename_to_ansi (path, path_a);
6148       sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
6149 			FILE_FLAG_OPEN_REPARSE_POINT
6150 			| FILE_FLAG_BACKUP_SEMANTICS,
6151 			NULL);
6152     }
6153   if (sh != INVALID_HANDLE_VALUE)
6154     {
6155       BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
6156       REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
6157       DWORD retbytes;
6158 
6159       if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
6160 			    reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
6161 			    &retbytes, NULL))
6162 	errno = EIO;
6163       else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
6164 	errno = EINVAL;
6165       else
6166 	{
6167 	  /* Copy the link target name, in wide characters, from
6168 	     reparse_data, then convert it to multibyte encoding in
6169 	     the current locale's codepage.  */
6170 	  WCHAR *lwname;
6171 	  size_t lname_size;
6172 	  USHORT lwname_len =
6173 	    reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
6174 	  WCHAR *lwname_src =
6175 	    reparse_data->SymbolicLinkReparseBuffer.PathBuffer
6176 	    + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
6177 	  size_t size_to_copy = buf_size;
6178 
6179 	  /* According to MSDN, PrintNameLength does not include the
6180 	     terminating NUL character.  */
6181 	  lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
6182 	  memcpy (lwname, lwname_src, lwname_len);
6183 	  lwname[lwname_len/sizeof(WCHAR)] = 0; /* NUL-terminate */
6184 	  filename_from_utf16 (lwname, resolved);
6185 	  dostounix_filename (resolved);
6186 	  lname_size = strlen (resolved) + 1;
6187 	  if (lname_size <= buf_size)
6188 	    size_to_copy = lname_size;
6189 	  memcpy (buf, resolved, size_to_copy);
6190 	  /* Success!  */
6191 	  retval = size_to_copy;
6192 	}
6193       CloseHandle (sh);
6194     }
6195   else
6196     {
6197       /* CreateFile failed.  */
6198       DWORD w32err2 = GetLastError ();
6199 
6200       switch (w32err2)
6201 	{
6202 	case ERROR_FILE_NOT_FOUND:
6203 	case ERROR_PATH_NOT_FOUND:
6204 	  errno = ENOENT;
6205 	  break;
6206 	case ERROR_ACCESS_DENIED:
6207 	case ERROR_TOO_MANY_OPEN_FILES:
6208 	  errno = EACCES;
6209 	  break;
6210 	default:
6211 	  errno = EPERM;
6212 	  break;
6213 	}
6214     }
6215   if (restore_privs)
6216     {
6217       restore_privilege (&privs);
6218       revert_to_self ();
6219     }
6220 
6221   return retval;
6222 }
6223 
6224 ssize_t
readlinkat(int fd,char const * name,char * buffer,size_t buffer_size)6225 readlinkat (int fd, char const *name, char *buffer,
6226 	    size_t buffer_size)
6227 {
6228   /* Rely on a hack: an open directory is modeled as file descriptor 0,
6229      as in fstatat.  FIXME: Add proper support for readlinkat.  */
6230   char fullname[MAX_UTF8_PATH];
6231 
6232   if (fd != AT_FDCWD)
6233     {
6234       if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
6235 	  < 0)
6236 	{
6237 	  errno = ENAMETOOLONG;
6238 	  return -1;
6239 	}
6240       name = fullname;
6241     }
6242 
6243   return readlink (name, buffer, buffer_size);
6244 }
6245 
6246 /* If FILE is a symlink, return its target (stored in a static
6247    buffer); otherwise return FILE.
6248 
6249    This function repeatedly resolves symlinks in the last component of
6250    a chain of symlink file names, as in foo -> bar -> baz -> ...,
6251    until it arrives at a file whose last component is not a symlink,
6252    or some error occurs.  It returns the target of the last
6253    successfully resolved symlink in the chain.  If it succeeds to
6254    resolve even a single symlink, the value returned is an absolute
6255    file name with backslashes (result of GetFullPathName).  By
6256    contrast, if the original FILE is returned, it is unaltered.
6257 
6258    Note: This function can set errno even if it succeeds.
6259 
6260    Implementation note: we only resolve the last portion ("basename")
6261    of the argument FILE and of each following file in the chain,
6262    disregarding any possible symlinks in its leading directories.
6263    This is because Windows system calls and library functions
6264    transparently resolve symlinks in leading directories and return
6265    correct information, as long as the basename is not a symlink.  */
6266 static char *
chase_symlinks(const char * file)6267 chase_symlinks (const char *file)
6268 {
6269   static char target[MAX_UTF8_PATH];
6270   char link[MAX_UTF8_PATH];
6271   wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
6272   char target_a[MAX_PATH], link_a[MAX_PATH];
6273   ssize_t res, link_len;
6274   int loop_count = 0;
6275 
6276   if (is_windows_9x () == TRUE || !is_symlink (file))
6277     return (char *)file;
6278 
6279   if (w32_unicode_filenames)
6280     {
6281       wchar_t file_w[MAX_PATH];
6282 
6283       filename_to_utf16 (file, file_w);
6284       if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
6285 	return (char *)file;
6286       filename_from_utf16 (link_w, link);
6287     }
6288   else
6289     {
6290       char file_a[MAX_PATH];
6291 
6292       filename_to_ansi (file, file_a);
6293       if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
6294 	return (char *)file;
6295       filename_from_ansi (link_a, link);
6296     }
6297   link_len = strlen (link);
6298 
6299   target[0] = '\0';
6300   do {
6301 
6302     /* Remove trailing slashes, as we want to resolve the last
6303        non-trivial part of the link name.  */
6304     while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
6305       link[link_len--] = '\0';
6306 
6307     res = readlink (link, target, MAX_UTF8_PATH);
6308     if (res > 0)
6309       {
6310 	target[res] = '\0';
6311 	if (!(IS_DEVICE_SEP (target[1])
6312 	      || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
6313 	  {
6314 	    /* Target is relative.  Append it to the directory part of
6315 	       the symlink, then copy the result back to target.  */
6316 	    char *p = link + link_len;
6317 
6318 	    while (p > link && !IS_ANY_SEP (p[-1]))
6319 	      p--;
6320 	    strcpy (p, target);
6321 	    strcpy (target, link);
6322 	  }
6323 	/* Resolve any "." and ".." to get a fully-qualified file name
6324 	   in link[] again. */
6325 	if (w32_unicode_filenames)
6326 	  {
6327 	    filename_to_utf16 (target, target_w);
6328 	    link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
6329 	    if (link_len > 0)
6330 	      filename_from_utf16 (link_w, link);
6331 	  }
6332 	else
6333 	  {
6334 	    filename_to_ansi (target, target_a);
6335 	    link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
6336 	    if (link_len > 0)
6337 	      filename_from_ansi (link_a, link);
6338 	  }
6339 	link_len = strlen (link);
6340       }
6341   } while (res > 0 && link_len > 0 && ++loop_count <= 100);
6342 
6343   if (loop_count > 100)
6344     errno = ELOOP;
6345 
6346   if (target[0] == '\0') /* not a single call to readlink succeeded */
6347     return (char *)file;
6348   return target;
6349 }
6350 
6351 
6352 /* Posix ACL emulation.  */
6353 
6354 int
acl_valid(acl_t acl)6355 acl_valid (acl_t acl)
6356 {
6357   return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
6358 }
6359 
6360 char * ATTRIBUTE_MALLOC
acl_to_text(acl_t acl,ssize_t * size)6361 acl_to_text (acl_t acl, ssize_t *size)
6362 {
6363   LPTSTR str_acl;
6364   SECURITY_INFORMATION flags =
6365     OWNER_SECURITY_INFORMATION |
6366     GROUP_SECURITY_INFORMATION |
6367     DACL_SECURITY_INFORMATION;
6368   char *retval = NULL;
6369   ULONG local_size;
6370   int e = errno;
6371 
6372   errno = 0;
6373 
6374   if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
6375     {
6376       errno = e;
6377       /* We don't want to mix heaps, so we duplicate the string in our
6378 	 heap and free the one allocated by the API.  */
6379       retval = xstrdup (str_acl);
6380       if (size)
6381 	*size = local_size;
6382       LocalFree (str_acl);
6383     }
6384   else if (errno != ENOTSUP)
6385     errno = EINVAL;
6386 
6387   return retval;
6388 }
6389 
6390 acl_t
acl_from_text(const char * acl_str)6391 acl_from_text (const char *acl_str)
6392 {
6393   PSECURITY_DESCRIPTOR psd, retval = NULL;
6394   ULONG sd_size;
6395   int e = errno;
6396 
6397   errno = 0;
6398 
6399   if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
6400     {
6401       errno = e;
6402       retval = xmalloc (sd_size);
6403       memcpy (retval, psd, sd_size);
6404       LocalFree (psd);
6405     }
6406   else if (errno != ENOTSUP)
6407     errno = EINVAL;
6408 
6409   return retval;
6410 }
6411 
6412 int
acl_free(void * ptr)6413 acl_free (void *ptr)
6414 {
6415   xfree (ptr);
6416   return 0;
6417 }
6418 
6419 acl_t
acl_get_file(const char * fname,acl_type_t type)6420 acl_get_file (const char *fname, acl_type_t type)
6421 {
6422   PSECURITY_DESCRIPTOR psd = NULL;
6423   const char *filename;
6424 
6425   if (type == ACL_TYPE_ACCESS)
6426     {
6427       DWORD sd_len, err;
6428       SECURITY_INFORMATION si =
6429 	OWNER_SECURITY_INFORMATION |
6430 	GROUP_SECURITY_INFORMATION |
6431 	DACL_SECURITY_INFORMATION ;
6432       int e = errno;
6433 
6434       filename = map_w32_filename (fname, NULL);
6435       if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6436 	fname = chase_symlinks (filename);
6437       else
6438 	fname = filename;
6439 
6440       errno = 0;
6441       if (!get_file_security (fname, si, psd, 0, &sd_len)
6442 	  && errno != ENOTSUP)
6443 	{
6444 	  err = GetLastError ();
6445 	  if (err == ERROR_INSUFFICIENT_BUFFER)
6446 	    {
6447 	      psd = xmalloc (sd_len);
6448 	      if (!get_file_security (fname, si, psd, sd_len, &sd_len))
6449 		{
6450 		  xfree (psd);
6451 		  err = GetLastError ();
6452 		  if (err == ERROR_NOT_SUPPORTED
6453 		      || err == ERROR_ACCESS_DENIED)
6454 		    errno = ENOTSUP;
6455 		  else if (err == ERROR_FILE_NOT_FOUND
6456 			   || err == ERROR_PATH_NOT_FOUND
6457 			   || err == ERROR_INVALID_NAME)
6458 		    errno = ENOENT;
6459 		  else
6460 		    errno = EIO;
6461 		  psd = NULL;
6462 		}
6463 	    }
6464 	  else if (err == ERROR_FILE_NOT_FOUND
6465 		   || err == ERROR_PATH_NOT_FOUND
6466 		   /* ERROR_INVALID_NAME is what we get if
6467 		      w32-unicode-filenames is nil and the file cannot
6468 		      be encoded in the current ANSI codepage. */
6469 		   || err == ERROR_INVALID_NAME)
6470 	    errno = ENOENT;
6471 	  else if (err == ERROR_NOT_SUPPORTED
6472 		   /* ERROR_ACCESS_DENIED is what we get for a volume
6473 		      mounted by WebDAV, which evidently doesn't
6474 		      support ACLs.  */
6475 		   || err == ERROR_ACCESS_DENIED)
6476 	    errno = ENOTSUP;
6477 	  else
6478 	    errno = EIO;
6479 	}
6480       else if (!errno)
6481 	errno = e;
6482     }
6483   else if (type != ACL_TYPE_DEFAULT)
6484     errno = EINVAL;
6485 
6486   return psd;
6487 }
6488 
6489 int
acl_set_file(const char * fname,acl_type_t type,acl_t acl)6490 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
6491 {
6492   TOKEN_PRIVILEGES old1, old2;
6493   DWORD err;
6494   int st = 0, retval = -1;
6495   SECURITY_INFORMATION flags = 0;
6496   PSID psidOwner, psidGroup;
6497   PACL pacl;
6498   BOOL dflt;
6499   BOOL dacl_present;
6500   int e;
6501   const char *filename;
6502 
6503   if (acl_valid (acl) != 0
6504       || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
6505     {
6506       errno = EINVAL;
6507       return -1;
6508     }
6509 
6510   if (type == ACL_TYPE_DEFAULT)
6511     {
6512       errno = ENOSYS;
6513       return -1;
6514     }
6515 
6516   filename = map_w32_filename (fname, NULL);
6517   if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6518     fname = chase_symlinks (filename);
6519   else
6520     fname = filename;
6521 
6522   if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
6523 				     &dflt)
6524       && psidOwner)
6525     flags |= OWNER_SECURITY_INFORMATION;
6526   if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
6527 				     &dflt)
6528       && psidGroup)
6529     flags |= GROUP_SECURITY_INFORMATION;
6530   if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
6531 				    &pacl, &dflt)
6532       && dacl_present)
6533     flags |= DACL_SECURITY_INFORMATION;
6534   if (!flags)
6535     return 0;
6536 
6537   /* According to KB-245153, setting the owner will succeed if either:
6538      (1) the caller is the user who will be the new owner, and has the
6539          SE_TAKE_OWNERSHIP privilege, or
6540      (2) the caller has the SE_RESTORE privilege, in which case she can
6541          set any valid user or group as the owner
6542 
6543      We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
6544      privileges, and disregard any failures in obtaining them.  If
6545      these privileges cannot be obtained, and do not already exist in
6546      the calling thread's security token, this function could fail
6547      with EPERM.  */
6548   if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
6549     st++;
6550   if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
6551     st++;
6552 
6553   e = errno;
6554   errno = 0;
6555   /* SetFileSecurity is deprecated by MS, and sometimes fails when
6556      DACL inheritance is involved, but it seems to preserve ownership
6557      better than SetNamedSecurityInfo, which is important e.g., in
6558      copy-file.  */
6559   if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
6560     {
6561       err = GetLastError ();
6562 
6563       if (errno != ENOTSUP)
6564 	err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
6565 				       psidOwner, psidGroup, pacl, NULL);
6566     }
6567   else
6568     err = ERROR_SUCCESS;
6569   if (err != ERROR_SUCCESS)
6570     {
6571       if (errno == ENOTSUP)
6572 	;
6573       else if (err == ERROR_INVALID_OWNER
6574 	       || err == ERROR_NOT_ALL_ASSIGNED
6575 	       || err == ERROR_ACCESS_DENIED)
6576 	{
6577 	  /* Maybe the requested ACL and the one the file already has
6578 	     are identical, in which case we can silently ignore the
6579 	     failure.  (And no, Windows doesn't.)  */
6580 	  acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
6581 
6582 	  errno = EPERM;
6583 	  if (current_acl)
6584 	    {
6585 	      char *acl_from = acl_to_text (current_acl, NULL);
6586 	      char *acl_to = acl_to_text (acl, NULL);
6587 
6588 	      if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
6589 		{
6590 		  retval = 0;
6591 		  errno = e;
6592 		}
6593 	      if (acl_from)
6594 		acl_free (acl_from);
6595 	      if (acl_to)
6596 		acl_free (acl_to);
6597 	      acl_free (current_acl);
6598 	    }
6599 	}
6600       else if (err == ERROR_FILE_NOT_FOUND
6601 	       || err == ERROR_PATH_NOT_FOUND
6602 	       /* ERROR_INVALID_NAME is what we get if
6603 		  w32-unicode-filenames is nil and the file cannot be
6604 		  encoded in the current ANSI codepage. */
6605 	       || err == ERROR_INVALID_NAME)
6606 	errno = ENOENT;
6607       else
6608 	errno = EACCES;
6609     }
6610   else
6611     {
6612       retval = 0;
6613       errno = e;
6614     }
6615 
6616   if (st)
6617     {
6618       if (st >= 2)
6619 	restore_privilege (&old2);
6620       restore_privilege (&old1);
6621       revert_to_self ();
6622     }
6623 
6624   return retval;
6625 }
6626 
6627 /* Return true if errno value ERRNUM indicates that ACLs are well
6628    supported on this system.  ERRNUM should be an errno value obtained
6629    after an ACL-related system call fails.  */
6630 bool
acl_errno_valid(int errnum)6631 acl_errno_valid (int errnum)
6632 {
6633   switch (errnum)
6634     {
6635     case EBUSY:
6636     case EINVAL:
6637     case ENOTSUP:
6638       return false;
6639     default:
6640       return true;
6641     }
6642 }
6643 
6644 
6645 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c).  We
6646    have a fixed max size for file names, so we don't need the kind of
6647    alloc/malloc/realloc dance the gnulib version does.  We also don't
6648    support FD-relative symlinks.  */
6649 char *
careadlinkat(int fd,char const * filename,char * buffer,size_t buffer_size,struct allocator const * alloc,ssize_t (* preadlinkat)(int,char const *,char *,size_t))6650 careadlinkat (int fd, char const *filename,
6651               char *buffer, size_t buffer_size,
6652               struct allocator const *alloc,
6653               ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6654 {
6655   char linkname[MAX_UTF8_PATH];
6656   ssize_t link_size;
6657 
6658   link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6659 
6660   if (link_size > 0)
6661     {
6662       char *retval = buffer;
6663 
6664       linkname[link_size++] = '\0';
6665       if (link_size > buffer_size)
6666 	retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6667       if (retval)
6668 	memcpy (retval, linkname, link_size);
6669 
6670       return retval;
6671     }
6672   return NULL;
6673 }
6674 
6675 int
w32_copy_file(const char * from,const char * to,int keep_time,int preserve_ownership,int copy_acls)6676 w32_copy_file (const char *from, const char *to,
6677 	       int keep_time, int preserve_ownership, int copy_acls)
6678 {
6679   acl_t acl = NULL;
6680   BOOL copy_result;
6681   wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6682   char from_a[MAX_PATH], to_a[MAX_PATH];
6683 
6684   /* We ignore preserve_ownership for now.  */
6685   preserve_ownership = preserve_ownership;
6686 
6687   if (copy_acls)
6688     {
6689       acl = acl_get_file (from, ACL_TYPE_ACCESS);
6690       if (acl == NULL && acl_errno_valid (errno))
6691 	return -2;
6692     }
6693   if (w32_unicode_filenames)
6694     {
6695       filename_to_utf16 (from, from_w);
6696       filename_to_utf16 (to, to_w);
6697       copy_result = CopyFileW (from_w, to_w, FALSE);
6698     }
6699   else
6700     {
6701       filename_to_ansi (from, from_a);
6702       filename_to_ansi (to, to_a);
6703       copy_result = CopyFileA (from_a, to_a, FALSE);
6704     }
6705   if (!copy_result)
6706     {
6707       /* CopyFile doesn't set errno when it fails.  By far the most
6708 	 "popular" reason is that the target is read-only.  */
6709       DWORD err = GetLastError ();
6710 
6711       switch (err)
6712 	{
6713 	case ERROR_FILE_NOT_FOUND:
6714 	  errno = ENOENT;
6715 	  break;
6716 	case ERROR_ACCESS_DENIED:
6717 	  errno = EACCES;
6718 	  break;
6719 	case ERROR_ENCRYPTION_FAILED:
6720 	  errno = EIO;
6721 	  break;
6722 	default:
6723 	  errno = EPERM;
6724 	  break;
6725 	}
6726 
6727       if (acl)
6728 	acl_free (acl);
6729       return -1;
6730     }
6731   /* CopyFile retains the timestamp by default.  However, see
6732      "Community Additions" for CopyFile: it sounds like that is not
6733      entirely true.  Testing on Windows XP confirms that modified time
6734      is copied, but creation and last-access times are not.
6735      FIXME?  */
6736   else if (!keep_time)
6737     {
6738       struct timespec now;
6739       DWORD attributes;
6740 
6741       if (w32_unicode_filenames)
6742 	{
6743 	  /* Ensure file is writable while its times are set.  */
6744 	  attributes = GetFileAttributesW (to_w);
6745 	  SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6746 	  now = current_timespec ();
6747 	  if (set_file_times (-1, to, now, now))
6748 	    {
6749 	      /* Restore original attributes.  */
6750 	      SetFileAttributesW (to_w, attributes);
6751 	      if (acl)
6752 		acl_free (acl);
6753 	      return -3;
6754 	    }
6755 	  /* Restore original attributes.  */
6756 	  SetFileAttributesW (to_w, attributes);
6757 	}
6758       else
6759 	{
6760 	  attributes = GetFileAttributesA (to_a);
6761 	  SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6762 	  now = current_timespec ();
6763 	  if (set_file_times (-1, to, now, now))
6764 	    {
6765 	      SetFileAttributesA (to_a, attributes);
6766 	      if (acl)
6767 		acl_free (acl);
6768 	      return -3;
6769 	    }
6770 	  SetFileAttributesA (to_a, attributes);
6771 	}
6772     }
6773   if (acl != NULL)
6774     {
6775       bool fail =
6776 	acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6777       acl_free (acl);
6778       if (fail && acl_errno_valid (errno))
6779 	return -4;
6780     }
6781 
6782   return 0;
6783 }
6784 
6785 
6786 /* Support for browsing other processes and their attributes.  See
6787    process.c for the Lisp bindings.  */
6788 
6789 /* Helper wrapper functions.  */
6790 
6791 static HANDLE WINAPI
create_toolhelp32_snapshot(DWORD Flags,DWORD Ignored)6792 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6793 {
6794   static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6795 
6796   if (g_b_init_create_toolhelp32_snapshot == 0)
6797     {
6798       g_b_init_create_toolhelp32_snapshot = 1;
6799       s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6800 	get_proc_addr (GetModuleHandle ("kernel32.dll"),
6801                               "CreateToolhelp32Snapshot");
6802     }
6803   if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6804     {
6805       return INVALID_HANDLE_VALUE;
6806     }
6807   return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6808 }
6809 
6810 static BOOL WINAPI
process32_first(HANDLE hSnapshot,LPPROCESSENTRY32 lppe)6811 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6812 {
6813   static Process32First_Proc s_pfn_Process32_First = NULL;
6814 
6815   if (g_b_init_process32_first == 0)
6816     {
6817       g_b_init_process32_first = 1;
6818       s_pfn_Process32_First = (Process32First_Proc)
6819 	get_proc_addr (GetModuleHandle ("kernel32.dll"),
6820                               "Process32First");
6821     }
6822   if (s_pfn_Process32_First == NULL)
6823     {
6824       return FALSE;
6825     }
6826   return (s_pfn_Process32_First (hSnapshot, lppe));
6827 }
6828 
6829 static BOOL WINAPI
process32_next(HANDLE hSnapshot,LPPROCESSENTRY32 lppe)6830 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6831 {
6832   static Process32Next_Proc s_pfn_Process32_Next = NULL;
6833 
6834   if (g_b_init_process32_next == 0)
6835     {
6836       g_b_init_process32_next = 1;
6837       s_pfn_Process32_Next = (Process32Next_Proc)
6838 	get_proc_addr (GetModuleHandle ("kernel32.dll"),
6839                               "Process32Next");
6840     }
6841   if (s_pfn_Process32_Next == NULL)
6842     {
6843       return FALSE;
6844     }
6845   return (s_pfn_Process32_Next (hSnapshot, lppe));
6846 }
6847 
6848 static BOOL WINAPI
open_thread_token(HANDLE ThreadHandle,DWORD DesiredAccess,BOOL OpenAsSelf,PHANDLE TokenHandle)6849 open_thread_token (HANDLE ThreadHandle,
6850 		   DWORD DesiredAccess,
6851 		   BOOL OpenAsSelf,
6852 		   PHANDLE TokenHandle)
6853 {
6854   static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6855   HMODULE hm_advapi32 = NULL;
6856   if (is_windows_9x () == TRUE)
6857     {
6858       SetLastError (ERROR_NOT_SUPPORTED);
6859       return FALSE;
6860     }
6861   if (g_b_init_open_thread_token == 0)
6862     {
6863       g_b_init_open_thread_token = 1;
6864       hm_advapi32 = LoadLibrary ("Advapi32.dll");
6865       s_pfn_Open_Thread_Token = (OpenThreadToken_Proc)
6866         get_proc_addr (hm_advapi32, "OpenThreadToken");
6867     }
6868   if (s_pfn_Open_Thread_Token == NULL)
6869     {
6870       SetLastError (ERROR_NOT_SUPPORTED);
6871       return FALSE;
6872     }
6873   return (
6874       s_pfn_Open_Thread_Token (
6875           ThreadHandle,
6876           DesiredAccess,
6877 	  OpenAsSelf,
6878           TokenHandle)
6879       );
6880 }
6881 
6882 static BOOL WINAPI
impersonate_self(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)6883 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6884 {
6885   static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6886   HMODULE hm_advapi32 = NULL;
6887   if (is_windows_9x () == TRUE)
6888     {
6889       return FALSE;
6890     }
6891   if (g_b_init_impersonate_self == 0)
6892     {
6893       g_b_init_impersonate_self = 1;
6894       hm_advapi32 = LoadLibrary ("Advapi32.dll");
6895       s_pfn_Impersonate_Self = (ImpersonateSelf_Proc)
6896         get_proc_addr (hm_advapi32, "ImpersonateSelf");
6897     }
6898   if (s_pfn_Impersonate_Self == NULL)
6899     {
6900       return FALSE;
6901     }
6902   return s_pfn_Impersonate_Self (ImpersonationLevel);
6903 }
6904 
6905 static BOOL WINAPI
revert_to_self(void)6906 revert_to_self (void)
6907 {
6908   static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6909   HMODULE hm_advapi32 = NULL;
6910   if (is_windows_9x () == TRUE)
6911     {
6912       return FALSE;
6913     }
6914   if (g_b_init_revert_to_self == 0)
6915     {
6916       g_b_init_revert_to_self = 1;
6917       hm_advapi32 = LoadLibrary ("Advapi32.dll");
6918       s_pfn_Revert_To_Self = (RevertToSelf_Proc)
6919         get_proc_addr (hm_advapi32, "RevertToSelf");
6920     }
6921   if (s_pfn_Revert_To_Self == NULL)
6922     {
6923       return FALSE;
6924     }
6925   return s_pfn_Revert_To_Self ();
6926 }
6927 
6928 static BOOL WINAPI
get_process_memory_info(HANDLE h_proc,PPROCESS_MEMORY_COUNTERS mem_counters,DWORD bufsize)6929 get_process_memory_info (HANDLE h_proc,
6930 			 PPROCESS_MEMORY_COUNTERS mem_counters,
6931 			 DWORD bufsize)
6932 {
6933   static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6934   HMODULE hm_psapi = NULL;
6935   if (is_windows_9x () == TRUE)
6936     {
6937       return FALSE;
6938     }
6939   if (g_b_init_get_process_memory_info == 0)
6940     {
6941       g_b_init_get_process_memory_info = 1;
6942       hm_psapi = LoadLibrary ("Psapi.dll");
6943       if (hm_psapi)
6944 	s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6945 	  get_proc_addr (hm_psapi, "GetProcessMemoryInfo");
6946     }
6947   if (s_pfn_Get_Process_Memory_Info == NULL)
6948     {
6949       return FALSE;
6950     }
6951   return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6952 }
6953 
6954 static BOOL WINAPI
get_process_working_set_size(HANDLE h_proc,PSIZE_T minrss,PSIZE_T maxrss)6955 get_process_working_set_size (HANDLE h_proc,
6956 			      PSIZE_T minrss,
6957 			      PSIZE_T maxrss)
6958 {
6959   static GetProcessWorkingSetSize_Proc
6960     s_pfn_Get_Process_Working_Set_Size = NULL;
6961 
6962   if (is_windows_9x () == TRUE)
6963     {
6964       return FALSE;
6965     }
6966   if (g_b_init_get_process_working_set_size == 0)
6967     {
6968       g_b_init_get_process_working_set_size = 1;
6969       s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6970 	get_proc_addr (GetModuleHandle ("kernel32.dll"),
6971                               "GetProcessWorkingSetSize");
6972     }
6973   if (s_pfn_Get_Process_Working_Set_Size == NULL)
6974     {
6975       return FALSE;
6976     }
6977   return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6978 }
6979 
6980 static BOOL WINAPI
global_memory_status(MEMORYSTATUS * buf)6981 global_memory_status (MEMORYSTATUS *buf)
6982 {
6983   static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6984 
6985   if (is_windows_9x () == TRUE)
6986     {
6987       return FALSE;
6988     }
6989   if (g_b_init_global_memory_status == 0)
6990     {
6991       g_b_init_global_memory_status = 1;
6992       s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6993 	get_proc_addr (GetModuleHandle ("kernel32.dll"),
6994                               "GlobalMemoryStatus");
6995     }
6996   if (s_pfn_Global_Memory_Status == NULL)
6997     {
6998       return FALSE;
6999     }
7000   return s_pfn_Global_Memory_Status (buf);
7001 }
7002 
7003 static BOOL WINAPI
global_memory_status_ex(MEMORY_STATUS_EX * buf)7004 global_memory_status_ex (MEMORY_STATUS_EX *buf)
7005 {
7006   static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
7007 
7008   if (is_windows_9x () == TRUE)
7009     {
7010       return FALSE;
7011     }
7012   if (g_b_init_global_memory_status_ex == 0)
7013     {
7014       g_b_init_global_memory_status_ex = 1;
7015       s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
7016 	get_proc_addr (GetModuleHandle ("kernel32.dll"),
7017                               "GlobalMemoryStatusEx");
7018     }
7019   if (s_pfn_Global_Memory_Status_Ex == NULL)
7020     {
7021       return FALSE;
7022     }
7023   return s_pfn_Global_Memory_Status_Ex (buf);
7024 }
7025 
7026 Lisp_Object
list_system_processes(void)7027 list_system_processes (void)
7028 {
7029   Lisp_Object proclist = Qnil;
7030   HANDLE h_snapshot;
7031 
7032   h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
7033 
7034   if (h_snapshot != INVALID_HANDLE_VALUE)
7035     {
7036       PROCESSENTRY32 proc_entry;
7037       DWORD proc_id;
7038       BOOL res;
7039 
7040       proc_entry.dwSize = sizeof (PROCESSENTRY32);
7041       for (res = process32_first (h_snapshot, &proc_entry); res;
7042 	   res = process32_next  (h_snapshot, &proc_entry))
7043 	{
7044 	  proc_id = proc_entry.th32ProcessID;
7045 	  proclist = Fcons (INT_TO_INTEGER (proc_id), proclist);
7046 	}
7047 
7048       CloseHandle (h_snapshot);
7049       proclist = Fnreverse (proclist);
7050     }
7051 
7052   return proclist;
7053 }
7054 
7055 static int
enable_privilege(LPCTSTR priv_name,BOOL enable_p,TOKEN_PRIVILEGES * old_priv)7056 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
7057 {
7058   TOKEN_PRIVILEGES priv;
7059   DWORD priv_size = sizeof (priv);
7060   DWORD opriv_size = sizeof (*old_priv);
7061   HANDLE h_token = NULL;
7062   HANDLE h_thread = GetCurrentThread ();
7063   int ret_val = 0;
7064   BOOL res;
7065 
7066   res = open_thread_token (h_thread,
7067 			   TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
7068 			   FALSE, &h_token);
7069   if (!res && GetLastError () == ERROR_NO_TOKEN)
7070     {
7071       if (impersonate_self (SecurityImpersonation))
7072 	  res = open_thread_token (h_thread,
7073 				   TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
7074 				   FALSE, &h_token);
7075     }
7076   if (res)
7077     {
7078       priv.PrivilegeCount = 1;
7079       priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
7080       LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
7081       if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
7082 				 old_priv, &opriv_size)
7083 	  && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
7084 	ret_val = 1;
7085     }
7086   if (h_token)
7087     CloseHandle (h_token);
7088 
7089   return ret_val;
7090 }
7091 
7092 static int
restore_privilege(TOKEN_PRIVILEGES * priv)7093 restore_privilege (TOKEN_PRIVILEGES *priv)
7094 {
7095   DWORD priv_size = sizeof (*priv);
7096   HANDLE h_token = NULL;
7097   int ret_val = 0;
7098 
7099   if (open_thread_token (GetCurrentThread (),
7100 			 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
7101 			 FALSE, &h_token))
7102     {
7103       if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
7104 	  && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
7105 	ret_val = 1;
7106     }
7107   if (h_token)
7108     CloseHandle (h_token);
7109 
7110   return ret_val;
7111 }
7112 
7113 static Lisp_Object
ltime(ULONGLONG time_100ns)7114 ltime (ULONGLONG time_100ns)
7115 {
7116   ULONGLONG time_sec = time_100ns / 10000000;
7117   int subsec = time_100ns % 10000000;
7118   return list4i (time_sec >> 16, time_sec & 0xffff,
7119 		 subsec / 10, subsec % 10 * 100000);
7120 }
7121 
7122 #define U64_TO_LISP_TIME(time) ltime (time)
7123 
7124 static int
process_times(HANDLE h_proc,Lisp_Object * ctime,Lisp_Object * etime,Lisp_Object * stime,Lisp_Object * utime,Lisp_Object * ttime,double * pcpu)7125 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
7126 	       Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
7127 	       double *pcpu)
7128 {
7129   FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
7130   ULONGLONG tem1, tem2, tem3, tem;
7131 
7132   if (!h_proc
7133       || !get_process_times_fn
7134       || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
7135 				   &ft_kernel, &ft_user))
7136     return 0;
7137 
7138   GetSystemTimeAsFileTime (&ft_current);
7139 
7140   FILETIME_TO_U64 (tem1, ft_kernel);
7141   *stime = U64_TO_LISP_TIME (tem1);
7142 
7143   FILETIME_TO_U64 (tem2, ft_user);
7144   *utime = U64_TO_LISP_TIME (tem2);
7145 
7146   tem3 = tem1 + tem2;
7147   *ttime = U64_TO_LISP_TIME (tem3);
7148 
7149   FILETIME_TO_U64 (tem, ft_creation);
7150   /* Process no 4 (System) returns zero creation time.  */
7151   if (tem)
7152     tem -= utc_base;
7153   *ctime = U64_TO_LISP_TIME (tem);
7154 
7155   if (tem)
7156     {
7157       FILETIME_TO_U64 (tem3, ft_current);
7158       tem = (tem3 - utc_base) - tem;
7159     }
7160   *etime = U64_TO_LISP_TIME (tem);
7161 
7162   if (tem)
7163     {
7164       *pcpu = 100.0 * (tem1 + tem2) / tem;
7165       if (*pcpu > 100)
7166 	*pcpu = 100.0;
7167     }
7168   else
7169     *pcpu = 0;
7170 
7171   return 1;
7172 }
7173 
7174 Lisp_Object
system_process_attributes(Lisp_Object pid)7175 system_process_attributes (Lisp_Object pid)
7176 {
7177   Lisp_Object attrs = Qnil;
7178   Lisp_Object cmd_str, decoded_cmd, tem;
7179   HANDLE h_snapshot, h_proc;
7180   DWORD proc_id;
7181   int found_proc = 0;
7182   char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
7183   DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
7184   DWORD glength = sizeof (gname);
7185   HANDLE token = NULL;
7186   SID_NAME_USE user_type;
7187   unsigned char *buf = NULL;
7188   DWORD blen = 0;
7189   TOKEN_USER user_token;
7190   TOKEN_PRIMARY_GROUP group_token;
7191   unsigned euid;
7192   unsigned egid;
7193   PROCESS_MEMORY_COUNTERS mem;
7194   PROCESS_MEMORY_COUNTERS_EX mem_ex;
7195   SIZE_T minrss, maxrss;
7196   MEMORYSTATUS memst;
7197   MEMORY_STATUS_EX memstex;
7198   double totphys = 0.0;
7199   Lisp_Object ctime, stime, utime, etime, ttime;
7200   double pcpu;
7201   BOOL result = FALSE;
7202 
7203   CHECK_NUMBER (pid);
7204   proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XFIXNUM (pid);
7205 
7206   h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
7207 
7208   if (h_snapshot != INVALID_HANDLE_VALUE)
7209     {
7210       PROCESSENTRY32 pe;
7211       BOOL res;
7212 
7213       pe.dwSize = sizeof (PROCESSENTRY32);
7214       for (res = process32_first (h_snapshot, &pe); res;
7215 	   res = process32_next  (h_snapshot, &pe))
7216 	{
7217 	  if (proc_id == pe.th32ProcessID)
7218 	    {
7219 	      if (proc_id == 0)
7220 		decoded_cmd = build_string ("Idle");
7221 	      else
7222 		{
7223 		  /* Decode the command name from locale-specific
7224 		     encoding.  */
7225 		  cmd_str = build_unibyte_string (pe.szExeFile);
7226 
7227 		  decoded_cmd =
7228 		    code_convert_string_norecord (cmd_str,
7229 						  Vlocale_coding_system, 0);
7230 		}
7231 	      attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
7232 	      attrs = Fcons (Fcons (Qppid,
7233 				    INT_TO_INTEGER (pe.th32ParentProcessID)),
7234 			     attrs);
7235 	      attrs = Fcons (Fcons (Qpri, make_fixnum (pe.pcPriClassBase)),
7236 			     attrs);
7237 	      attrs = Fcons (Fcons (Qthcount,
7238 				    INT_TO_INTEGER (pe.cntThreads)),
7239 			     attrs);
7240 	      found_proc = 1;
7241 	      break;
7242 	    }
7243 	}
7244 
7245       CloseHandle (h_snapshot);
7246     }
7247 
7248   if (!found_proc)
7249     return Qnil;
7250 
7251   h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
7252 			FALSE, proc_id);
7253   /* If we were denied a handle to the process, try again after
7254      enabling the SeDebugPrivilege in our process.  */
7255   if (!h_proc)
7256     {
7257       TOKEN_PRIVILEGES priv_current;
7258 
7259       if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
7260 	{
7261 	  h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
7262 				FALSE, proc_id);
7263 	  restore_privilege (&priv_current);
7264 	  revert_to_self ();
7265 	}
7266     }
7267   if (h_proc)
7268     {
7269       result = open_process_token (h_proc, TOKEN_QUERY, &token);
7270       if (result)
7271 	{
7272 	  result = get_token_information (token, TokenUser, NULL, 0, &blen);
7273 	  if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7274 	    {
7275 	      buf = xmalloc (blen);
7276 	      result = get_token_information (token, TokenUser,
7277 					      (LPVOID)buf, blen, &needed);
7278 	      if (result)
7279 		{
7280 		  memcpy (&user_token, buf, sizeof (user_token));
7281 		  if (!w32_cached_id (user_token.User.Sid, &euid, uname))
7282 		    {
7283 		      euid = get_rid (user_token.User.Sid);
7284 		      result = lookup_account_sid (NULL, user_token.User.Sid,
7285 						   uname, &ulength,
7286 						   domain, &dlength,
7287 						   &user_type);
7288 		      if (result)
7289 			w32_add_to_cache (user_token.User.Sid, euid, uname);
7290 		      else
7291 			{
7292 			  strcpy (uname, "unknown");
7293 			  result = TRUE;
7294 			}
7295 		    }
7296 		  ulength = strlen (uname);
7297 		}
7298 	    }
7299 	}
7300       if (result)
7301 	{
7302 	  /* Determine a reasonable euid and gid values.  */
7303 	  if (xstrcasecmp ("administrator", uname) == 0)
7304 	    {
7305 	      euid = 500;	/* well-known Administrator uid */
7306 	      egid = 513;	/* well-known None gid */
7307 	    }
7308 	  else
7309 	    {
7310 	      /* Get group id and name.  */
7311 	      result = get_token_information (token, TokenPrimaryGroup,
7312 					      (LPVOID)buf, blen, &needed);
7313 	      if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7314 		{
7315 		  buf = xrealloc (buf, blen = needed);
7316 		  result = get_token_information (token, TokenPrimaryGroup,
7317 						  (LPVOID)buf, blen, &needed);
7318 		}
7319 	      if (result)
7320 		{
7321 		  memcpy (&group_token, buf, sizeof (group_token));
7322 		  if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
7323 		    {
7324 		      egid = get_rid (group_token.PrimaryGroup);
7325 		      dlength = sizeof (domain);
7326 		      result =
7327 			lookup_account_sid (NULL, group_token.PrimaryGroup,
7328 					    gname, &glength, NULL, &dlength,
7329 					    &user_type);
7330 		      if (result)
7331 			w32_add_to_cache (group_token.PrimaryGroup,
7332 					  egid, gname);
7333 		      else
7334 			{
7335 			  strcpy (gname, "None");
7336 			  result = TRUE;
7337 			}
7338 		    }
7339 		  glength = strlen (gname);
7340 		}
7341 	    }
7342 	}
7343       xfree (buf);
7344     }
7345   if (!result)
7346     {
7347       if (!is_windows_9x ())
7348 	{
7349 	  /* We couldn't open the process token, presumably because of
7350 	     insufficient access rights.  Assume this process is run
7351 	     by the system.  */
7352 	  strcpy (uname, "SYSTEM");
7353 	  strcpy (gname, "None");
7354 	  euid = 18;	/* SYSTEM */
7355 	  egid = 513;	/* None */
7356 	  glength = strlen (gname);
7357 	  ulength = strlen (uname);
7358 	}
7359       /* If we are running under Windows 9X, where security calls are
7360 	 not supported, we assume all processes are run by the current
7361 	 user.  */
7362       else if (GetUserName (uname, &ulength))
7363 	{
7364 	  if (xstrcasecmp ("administrator", uname) == 0)
7365 	    euid = 0;
7366 	  else
7367 	    euid = 123;
7368 	  egid = euid;
7369 	  strcpy (gname, "None");
7370 	  glength = strlen (gname);
7371 	  ulength = strlen (uname);
7372 	}
7373       else
7374 	{
7375 	  euid = 123;
7376 	  egid = 123;
7377 	  strcpy (uname, "administrator");
7378 	  ulength = strlen (uname);
7379 	  strcpy (gname, "None");
7380 	  glength = strlen (gname);
7381 	}
7382       if (token)
7383 	CloseHandle (token);
7384     }
7385 
7386   attrs = Fcons (Fcons (Qeuid, INT_TO_INTEGER (euid)), attrs);
7387   tem = make_unibyte_string (uname, ulength);
7388   attrs = Fcons (Fcons (Quser,
7389 			 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7390 		 attrs);
7391   attrs = Fcons (Fcons (Qegid, INT_TO_INTEGER (egid)), attrs);
7392   tem = make_unibyte_string (gname, glength);
7393   attrs = Fcons (Fcons (Qgroup,
7394 			 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7395 		 attrs);
7396 
7397   memstex.dwLength = sizeof (memstex);
7398   if (global_memory_status_ex (&memstex))
7399 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
7400     totphys = memstex.ullTotalPhys / 1024.0;
7401 #else
7402   /* Visual Studio 6 cannot convert an unsigned __int64 type to
7403      double, so we need to do this for it...  */
7404     {
7405       DWORD tot_hi = memstex.ullTotalPhys >> 32;
7406       DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
7407       DWORD tot_lo = memstex.ullTotalPhys % 1024;
7408 
7409       totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
7410     }
7411 #endif	/* __GNUC__ || _MSC_VER >= 1300 */
7412   else if (global_memory_status (&memst))
7413     totphys = memst.dwTotalPhys / 1024.0;
7414 
7415   if (h_proc
7416       && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
7417 				  sizeof (mem_ex)))
7418     {
7419       SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7420 
7421       attrs = Fcons (Fcons (Qmajflt,
7422 			    INT_TO_INTEGER (mem_ex.PageFaultCount)),
7423 		     attrs);
7424       attrs = Fcons (Fcons (Qvsize,
7425 			    INT_TO_INTEGER (mem_ex.PrivateUsage / 1024)),
7426 		     attrs);
7427       attrs = Fcons (Fcons (Qrss, INT_TO_INTEGER (rss)), attrs);
7428       if (totphys)
7429 	attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7430     }
7431   else if (h_proc
7432 	   && get_process_memory_info (h_proc, &mem, sizeof (mem)))
7433     {
7434       SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7435 
7436       attrs = Fcons (Fcons (Qmajflt,
7437 			    INT_TO_INTEGER (mem.PageFaultCount)),
7438 		     attrs);
7439       attrs = Fcons (Fcons (Qrss, INT_TO_INTEGER (rss)), attrs);
7440       if (totphys)
7441 	attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7442     }
7443   else if (h_proc
7444 	   && get_process_working_set_size (h_proc, &minrss, &maxrss))
7445     {
7446       DWORD rss = maxrss / 1024;
7447 
7448       attrs = Fcons (Fcons (Qrss, INT_TO_INTEGER (maxrss / 1024)), attrs);
7449       if (totphys)
7450 	attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7451     }
7452 
7453   if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
7454     {
7455       attrs = Fcons (Fcons (Qutime, utime), attrs);
7456       attrs = Fcons (Fcons (Qstime, stime), attrs);
7457       attrs = Fcons (Fcons (Qtime,  ttime), attrs);
7458       attrs = Fcons (Fcons (Qstart, ctime), attrs);
7459       attrs = Fcons (Fcons (Qetime, etime), attrs);
7460       attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
7461     }
7462 
7463   /* FIXME: Retrieve command line by walking the PEB of the process.  */
7464 
7465   if (h_proc)
7466     CloseHandle (h_proc);
7467   return attrs;
7468 }
7469 
7470 int
w32_memory_info(unsigned long long * totalram,unsigned long long * freeram,unsigned long long * totalswap,unsigned long long * freeswap)7471 w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
7472 		 unsigned long long *totalswap, unsigned long long *freeswap)
7473 {
7474   MEMORYSTATUS memst;
7475   MEMORY_STATUS_EX memstex;
7476 
7477   /* Use GlobalMemoryStatusEx if available, as it can report more than
7478      2GB of memory.  */
7479   if (global_memory_status_ex (&memstex))
7480     {
7481       *totalram  = memstex.ullTotalPhys;
7482       *freeram   = memstex.ullAvailPhys;
7483       *totalswap = memstex.ullTotalPageFile;
7484       *freeswap  = memstex.ullAvailPageFile;
7485       return 0;
7486     }
7487   else if (global_memory_status (&memst))
7488     {
7489       *totalram = memst.dwTotalPhys;
7490       *freeram   = memst.dwAvailPhys;
7491       *totalswap = memst.dwTotalPageFile;
7492       *freeswap  = memst.dwAvailPageFile;
7493       return 0;
7494     }
7495   else
7496     return -1;
7497 }
7498 
7499 
7500 /* Wrappers for  winsock functions to map between our file descriptors
7501    and winsock's handles; also set h_errno for convenience.
7502 
7503    To allow Emacs to run on systems which don't have winsock support
7504    installed, we dynamically link to winsock on startup if present, and
7505    otherwise provide the minimum necessary functionality
7506    (eg. gethostname). */
7507 
7508 /* function pointers for relevant socket functions */
7509 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
7510 void (PASCAL *pfn_WSASetLastError) (int iError);
7511 int (PASCAL *pfn_WSAGetLastError) (void);
7512 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
7513 int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject,
7514 					WSANETWORKEVENTS *NetworkEvents);
7515 
7516 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
7517 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
7518 int (PASCAL *pfn_socket) (int af, int type, int protocol);
7519 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
7520 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
7521 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
7522 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
7523 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
7524 int (PASCAL *pfn_closesocket) (SOCKET s);
7525 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
7526 int (PASCAL *pfn_WSACleanup) (void);
7527 
7528 u_short (PASCAL *pfn_htons) (u_short hostshort);
7529 u_short (PASCAL *pfn_ntohs) (u_short netshort);
7530 u_long (PASCAL *pfn_htonl) (u_long hostlong);
7531 u_long (PASCAL *pfn_ntohl) (u_long netlong);
7532 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
7533 int (PASCAL *pfn_gethostname) (char * name, int namelen);
7534 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
7535 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
7536 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
7537 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
7538 			      const char * optval, int optlen);
7539 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
7540 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
7541 			       int * namelen);
7542 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
7543 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
7544 		       struct sockaddr * from, int * fromlen);
7545 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
7546 			  const struct sockaddr * to, int tolen);
7547 
7548 int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
7549 			       const struct addrinfo *, struct addrinfo **);
7550 void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
7551 
7552 /* SetHandleInformation is only needed to make sockets non-inheritable. */
7553 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7554 #ifndef HANDLE_FLAG_INHERIT
7555 #define HANDLE_FLAG_INHERIT	1
7556 #endif
7557 
7558 HANDLE winsock_lib;
7559 static int winsock_inuse;
7560 
7561 BOOL term_winsock (void);
7562 
7563 BOOL
term_winsock(void)7564 term_winsock (void)
7565 {
7566   if (winsock_lib != NULL && winsock_inuse == 0)
7567     {
7568       release_listen_threads ();
7569       /* Not sure what would cause WSAENETDOWN, or even if it can happen
7570 	 after WSAStartup returns successfully, but it seems reasonable
7571 	 to allow unloading winsock anyway in that case. */
7572       if (pfn_WSACleanup () == 0 ||
7573 	  pfn_WSAGetLastError () == WSAENETDOWN)
7574 	{
7575 	  if (FreeLibrary (winsock_lib))
7576 	  winsock_lib = NULL;
7577 	  return TRUE;
7578 	}
7579     }
7580   return FALSE;
7581 }
7582 
7583 BOOL
init_winsock(int load_now)7584 init_winsock (int load_now)
7585 {
7586   WSADATA  winsockData;
7587 
7588   if (winsock_lib != NULL)
7589     return TRUE;
7590 
7591   pfn_SetHandleInformation
7592     = (void *) get_proc_addr (GetModuleHandle ("kernel32.dll"),
7593                                      "SetHandleInformation");
7594 
7595   winsock_lib = LoadLibrary ("Ws2_32.dll");
7596 
7597   if (winsock_lib != NULL)
7598     {
7599       /* dynamically link to socket functions */
7600 
7601 #define LOAD_PROC(fn) \
7602       if ((pfn_##fn = (void *) get_proc_addr (winsock_lib, #fn)) == NULL) \
7603         goto fail;
7604 
7605       LOAD_PROC (WSAStartup);
7606       LOAD_PROC (WSASetLastError);
7607       LOAD_PROC (WSAGetLastError);
7608       LOAD_PROC (WSAEventSelect);
7609       LOAD_PROC (WSAEnumNetworkEvents);
7610       LOAD_PROC (WSACreateEvent);
7611       LOAD_PROC (WSACloseEvent);
7612       LOAD_PROC (socket);
7613       LOAD_PROC (bind);
7614       LOAD_PROC (connect);
7615       LOAD_PROC (ioctlsocket);
7616       LOAD_PROC (recv);
7617       LOAD_PROC (send);
7618       LOAD_PROC (closesocket);
7619       LOAD_PROC (shutdown);
7620       LOAD_PROC (htons);
7621       LOAD_PROC (ntohs);
7622       LOAD_PROC (htonl);
7623       LOAD_PROC (ntohl);
7624       LOAD_PROC (inet_addr);
7625       LOAD_PROC (gethostname);
7626       LOAD_PROC (gethostbyname);
7627       LOAD_PROC (getservbyname);
7628       LOAD_PROC (getpeername);
7629       LOAD_PROC (WSACleanup);
7630       LOAD_PROC (setsockopt);
7631       LOAD_PROC (listen);
7632       LOAD_PROC (getsockname);
7633       LOAD_PROC (accept);
7634       LOAD_PROC (recvfrom);
7635       LOAD_PROC (sendto);
7636 #undef LOAD_PROC
7637 
7638       /* Try loading functions not available before XP.  */
7639       pfn_getaddrinfo = (void *) get_proc_addr (winsock_lib, "getaddrinfo");
7640       pfn_freeaddrinfo = (void *) get_proc_addr (winsock_lib, "freeaddrinfo");
7641       /* Paranoia: these two functions should go together, so if one
7642 	 is absent, we cannot use the other.  */
7643       if (pfn_getaddrinfo == NULL)
7644 	pfn_freeaddrinfo = NULL;
7645       else if (pfn_freeaddrinfo == NULL)
7646 	pfn_getaddrinfo = NULL;
7647 
7648       /* specify version 1.1 of winsock */
7649       if (pfn_WSAStartup (0x101, &winsockData) == 0)
7650         {
7651 	  if (winsockData.wVersion != 0x101)
7652 	    goto fail;
7653 
7654 	  if (!load_now)
7655 	    {
7656 	      /* Report that winsock exists and is usable, but leave
7657 		 socket functions disabled.  I am assuming that calling
7658 		 WSAStartup does not require any network interaction,
7659 		 and in particular does not cause or require a dial-up
7660 		 connection to be established. */
7661 
7662 	      pfn_WSACleanup ();
7663 	      FreeLibrary (winsock_lib);
7664 	      winsock_lib = NULL;
7665 	    }
7666 	  winsock_inuse = 0;
7667 	  return TRUE;
7668 	}
7669 
7670     fail:
7671       FreeLibrary (winsock_lib);
7672       winsock_lib = NULL;
7673     }
7674 
7675   return FALSE;
7676 }
7677 
7678 
7679 int h_errno = 0;
7680 
7681 /* Function to map winsock error codes to errno codes for those errno
7682    code defined in errno.h (errno values not defined by errno.h are
7683    already in nt/inc/sys/socket.h).  */
7684 static void
set_errno(void)7685 set_errno (void)
7686 {
7687   int wsa_err;
7688 
7689   h_errno = 0;
7690   if (winsock_lib == NULL)
7691     wsa_err = EINVAL;
7692   else
7693     wsa_err = pfn_WSAGetLastError ();
7694 
7695   switch (wsa_err)
7696     {
7697     case WSAEACCES:		errno = EACCES; break;
7698     case WSAEBADF: 		errno = EBADF; break;
7699     case WSAEFAULT:		errno = EFAULT; break;
7700     case WSAEINTR: 		errno = EINTR; break;
7701     case WSAEINVAL:		errno = EINVAL; break;
7702     case WSAEMFILE:		errno = EMFILE; break;
7703     case WSAENAMETOOLONG: 	errno = ENAMETOOLONG; break;
7704     case WSAENOTEMPTY:		errno = ENOTEMPTY; break;
7705     case WSAEWOULDBLOCK:	errno = EWOULDBLOCK; break;
7706     case WSAENOTCONN:		errno = ENOTCONN; break;
7707     default:			errno = wsa_err; break;
7708     }
7709 }
7710 
7711 static void
check_errno(void)7712 check_errno (void)
7713 {
7714   h_errno = 0;
7715   if (winsock_lib != NULL)
7716     pfn_WSASetLastError (0);
7717 }
7718 
7719 /* Extend strerror to handle the winsock-specific error codes.  */
7720 struct {
7721   int errnum;
7722   const char * msg;
7723 } _wsa_errlist[] = {
7724   {WSAEINTR                , "Interrupted function call"},
7725   {WSAEBADF                , "Bad file descriptor"},
7726   {WSAEACCES               , "Permission denied"},
7727   {WSAEFAULT               , "Bad address"},
7728   {WSAEINVAL               , "Invalid argument"},
7729   {WSAEMFILE               , "Too many open files"},
7730 
7731   {WSAEWOULDBLOCK          , "Resource temporarily unavailable"},
7732   {WSAEINPROGRESS          , "Operation now in progress"},
7733   {WSAEALREADY             , "Operation already in progress"},
7734   {WSAENOTSOCK             , "Socket operation on non-socket"},
7735   {WSAEDESTADDRREQ         , "Destination address required"},
7736   {WSAEMSGSIZE             , "Message too long"},
7737   {WSAEPROTOTYPE           , "Protocol wrong type for socket"},
7738   {WSAENOPROTOOPT          , "Bad protocol option"},
7739   {WSAEPROTONOSUPPORT      , "Protocol not supported"},
7740   {WSAESOCKTNOSUPPORT      , "Socket type not supported"},
7741   {WSAEOPNOTSUPP           , "Operation not supported"},
7742   {WSAEPFNOSUPPORT         , "Protocol family not supported"},
7743   {WSAEAFNOSUPPORT         , "Address family not supported by protocol family"},
7744   {WSAEADDRINUSE           , "Address already in use"},
7745   {WSAEADDRNOTAVAIL        , "Cannot assign requested address"},
7746   {WSAENETDOWN             , "Network is down"},
7747   {WSAENETUNREACH          , "Network is unreachable"},
7748   {WSAENETRESET            , "Network dropped connection on reset"},
7749   {WSAECONNABORTED         , "Software caused connection abort"},
7750   {WSAECONNRESET           , "Connection reset by peer"},
7751   {WSAENOBUFS              , "No buffer space available"},
7752   {WSAEISCONN              , "Socket is already connected"},
7753   {WSAENOTCONN             , "Socket is not connected"},
7754   {WSAESHUTDOWN            , "Cannot send after socket shutdown"},
7755   {WSAETOOMANYREFS         , "Too many references"},	    /* not sure */
7756   {WSAETIMEDOUT            , "Connection timed out"},
7757   {WSAECONNREFUSED         , "Connection refused"},
7758   {WSAELOOP                , "Network loop"},		    /* not sure */
7759   {WSAENAMETOOLONG         , "Name is too long"},
7760   {WSAEHOSTDOWN            , "Host is down"},
7761   {WSAEHOSTUNREACH         , "No route to host"},
7762   {WSAENOTEMPTY            , "Buffer not empty"},	    /* not sure */
7763   {WSAEPROCLIM             , "Too many processes"},
7764   {WSAEUSERS               , "Too many users"},		    /* not sure */
7765   {WSAEDQUOT               , "Double quote in host name"},  /* really not sure */
7766   {WSAESTALE               , "Data is stale"},		    /* not sure */
7767   {WSAEREMOTE              , "Remote error"},		    /* not sure */
7768 
7769   {WSASYSNOTREADY          , "Network subsystem is unavailable"},
7770   {WSAVERNOTSUPPORTED      , "WINSOCK.DLL version out of range"},
7771   {WSANOTINITIALISED       , "Winsock not initialized successfully"},
7772   {WSAEDISCON              , "Graceful shutdown in progress"},
7773 #ifdef WSAENOMORE
7774   {WSAENOMORE              , "No more operations allowed"}, /* not sure */
7775   {WSAECANCELLED           , "Operation cancelled"},	    /* not sure */
7776   {WSAEINVALIDPROCTABLE    , "Invalid procedure table from service provider"},
7777   {WSAEINVALIDPROVIDER     , "Invalid service provider version number"},
7778   {WSAEPROVIDERFAILEDINIT  , "Unable to initialize a service provider"},
7779   {WSASYSCALLFAILURE       , "System call failure"},
7780   {WSASERVICE_NOT_FOUND    , "Service not found"},	    /* not sure */
7781   {WSATYPE_NOT_FOUND       , "Class type not found"},
7782   {WSA_E_NO_MORE           , "No more resources available"}, /* really not sure */
7783   {WSA_E_CANCELLED         , "Operation already cancelled"}, /* really not sure */
7784   {WSAEREFUSED             , "Operation refused"},	    /* not sure */
7785 #endif
7786 
7787   {WSAHOST_NOT_FOUND       , "Host not found"},
7788   {WSATRY_AGAIN            , "Authoritative host not found during name lookup"},
7789   {WSANO_RECOVERY          , "Non-recoverable error during name lookup"},
7790   {WSANO_DATA              , "Valid name, no data record of requested type"},
7791 
7792   {-1, NULL}
7793 };
7794 
7795 char *
sys_strerror(int error_no)7796 sys_strerror (int error_no)
7797 {
7798   int i;
7799   static char unknown_msg[40];
7800 
7801   if (error_no >= 0 && error_no < sys_nerr)
7802     return sys_errlist[error_no];
7803 
7804   for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7805     if (_wsa_errlist[i].errnum == error_no)
7806       return (char *)_wsa_errlist[i].msg;
7807 
7808   sprintf (unknown_msg, "Unidentified error: %d", error_no);
7809   return unknown_msg;
7810 }
7811 
7812 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7813    but I believe the method of keeping the socket handle separate (and
7814    insuring it is not inheritable) is the correct one. */
7815 
7816 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7817 
7818 static int socket_to_fd (SOCKET s);
7819 
7820 int
sys_socket(int af,int type,int protocol)7821 sys_socket (int af, int type, int protocol)
7822 {
7823   SOCKET s;
7824 
7825   if (winsock_lib == NULL)
7826     {
7827       errno = ENETDOWN;
7828       return -1;
7829     }
7830 
7831   check_errno ();
7832 
7833   /* call the real socket function */
7834   s = pfn_socket (af, type, protocol);
7835 
7836   if (s != INVALID_SOCKET)
7837     return socket_to_fd (s);
7838 
7839   set_errno ();
7840   return -1;
7841 }
7842 
7843 /* Convert a SOCKET to a file descriptor.  */
7844 static int
socket_to_fd(SOCKET s)7845 socket_to_fd (SOCKET s)
7846 {
7847   int fd;
7848   child_process * cp;
7849 
7850   /* Although under NT 3.5 _open_osfhandle will accept a socket
7851      handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7852      that does not work under NT 3.1.  However, we can get the same
7853      effect by using a backdoor function to replace an existing
7854      descriptor handle with the one we want. */
7855 
7856   /* allocate a file descriptor (with appropriate flags) */
7857   fd = _open ("NUL:", _O_RDWR);
7858   if (fd >= 0)
7859     {
7860       /* Make a non-inheritable copy of the socket handle.  Note
7861 	 that it is possible that sockets aren't actually kernel
7862 	 handles, which appears to be the case on Windows 9x when
7863 	 the MS Proxy winsock client is installed.  */
7864       {
7865 	/* Apparently there is a bug in NT 3.51 with some service
7866 	   packs, which prevents using DuplicateHandle to make a
7867 	   socket handle non-inheritable (causes WSACleanup to
7868 	   hang).  The work-around is to use SetHandleInformation
7869 	   instead if it is available and implemented. */
7870 	if (pfn_SetHandleInformation)
7871 	  {
7872 	    pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7873 	  }
7874 	else
7875 	  {
7876 	    HANDLE parent = GetCurrentProcess ();
7877 	    HANDLE new_s = INVALID_HANDLE_VALUE;
7878 
7879 	    if (DuplicateHandle (parent,
7880 				 (HANDLE) s,
7881 				 parent,
7882 				 &new_s,
7883 				 0,
7884 				 FALSE,
7885 				 DUPLICATE_SAME_ACCESS))
7886 	      {
7887 		/* It is possible that DuplicateHandle succeeds even
7888 		   though the socket wasn't really a kernel handle,
7889 		   because a real handle has the same value.  So
7890 		   test whether the new handle really is a socket.  */
7891 		unsigned long nonblocking = 0;
7892 		if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7893 		  {
7894 		    pfn_closesocket (s);
7895 		    s = (SOCKET) new_s;
7896 		  }
7897 		else
7898 		  {
7899 		    CloseHandle (new_s);
7900 		  }
7901 	      }
7902 	  }
7903       }
7904       eassert (fd < MAXDESC);
7905       fd_info[fd].hnd = (HANDLE) s;
7906 
7907       /* set our own internal flags */
7908       fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7909 
7910       cp = new_child ();
7911       if (cp)
7912 	{
7913 	  cp->fd = fd;
7914 	  cp->status = STATUS_READ_ACKNOWLEDGED;
7915 
7916 	  /* attach child_process to fd_info */
7917 	  if (fd_info[ fd ].cp != NULL)
7918 	    {
7919 	      DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7920 	      emacs_abort ();
7921 	    }
7922 
7923 	  fd_info[ fd ].cp = cp;
7924 
7925 	  /* success! */
7926 	  winsock_inuse++;	/* count open sockets */
7927 	  return fd;
7928 	}
7929 
7930       /* clean up */
7931       _close (fd);
7932     }
7933   else
7934   pfn_closesocket (s);
7935   errno = EMFILE;
7936   return -1;
7937 }
7938 
7939 int
sys_bind(int s,const struct sockaddr * addr,int namelen)7940 sys_bind (int s, const struct sockaddr * addr, int namelen)
7941 {
7942   if (winsock_lib == NULL)
7943     {
7944       errno = ENOTSOCK;
7945       return SOCKET_ERROR;
7946     }
7947 
7948   check_errno ();
7949   if (fd_info[s].flags & FILE_SOCKET)
7950     {
7951       int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7952       if (rc == SOCKET_ERROR)
7953 	set_errno ();
7954       return rc;
7955     }
7956   errno = ENOTSOCK;
7957   return SOCKET_ERROR;
7958 }
7959 
7960 int
sys_connect(int s,const struct sockaddr * name,int namelen)7961 sys_connect (int s, const struct sockaddr * name, int namelen)
7962 {
7963   if (winsock_lib == NULL)
7964     {
7965       errno = ENOTSOCK;
7966       return SOCKET_ERROR;
7967     }
7968 
7969   check_errno ();
7970   if (fd_info[s].flags & FILE_SOCKET)
7971     {
7972       int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7973       if (rc == SOCKET_ERROR)
7974 	{
7975 	  set_errno ();
7976 	  /* If this is a non-blocking 'connect', set the bit in flags
7977 	     that will tell reader_thread to wait for connection
7978 	     before trying to read.  */
7979 	  if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0)
7980 	    {
7981 	      errno = EINPROGRESS; /* that's what process.c expects */
7982 	      fd_info[s].flags |= FILE_CONNECT;
7983 	    }
7984 	}
7985       return rc;
7986     }
7987   errno = ENOTSOCK;
7988   return SOCKET_ERROR;
7989 }
7990 
7991 u_short
sys_htons(u_short hostshort)7992 sys_htons (u_short hostshort)
7993 {
7994   return (winsock_lib != NULL) ?
7995     pfn_htons (hostshort) : hostshort;
7996 }
7997 
7998 u_short
sys_ntohs(u_short netshort)7999 sys_ntohs (u_short netshort)
8000 {
8001   return (winsock_lib != NULL) ?
8002     pfn_ntohs (netshort) : netshort;
8003 }
8004 u_long
sys_htonl(u_long hostlong)8005 sys_htonl (u_long hostlong)
8006 {
8007   return (winsock_lib != NULL) ?
8008     pfn_htonl (hostlong) : hostlong;
8009 }
8010 
8011 u_long
sys_ntohl(u_long netlong)8012 sys_ntohl (u_long netlong)
8013 {
8014   return (winsock_lib != NULL) ?
8015     pfn_ntohl (netlong) : netlong;
8016 }
8017 
8018 unsigned long
sys_inet_addr(const char * cp)8019 sys_inet_addr (const char * cp)
8020 {
8021   return (winsock_lib != NULL) ?
8022     pfn_inet_addr (cp) : INADDR_NONE;
8023 }
8024 
8025 int
sys_gethostname(char * name,int namelen)8026 sys_gethostname (char * name, int namelen)
8027 {
8028   if (winsock_lib != NULL)
8029     {
8030       int retval;
8031 
8032       check_errno ();
8033       retval = pfn_gethostname (name, namelen);
8034       if (retval == SOCKET_ERROR)
8035 	set_errno ();
8036       return retval;
8037     }
8038 
8039   if (namelen > MAX_COMPUTERNAME_LENGTH)
8040     return !GetComputerName (name, (DWORD *)&namelen);
8041 
8042   errno = EFAULT;
8043   return SOCKET_ERROR;
8044 }
8045 
8046 struct hostent *
sys_gethostbyname(const char * name)8047 sys_gethostbyname (const char * name)
8048 {
8049   struct hostent * host;
8050   int h_err = h_errno;
8051 
8052   if (winsock_lib == NULL)
8053     {
8054       h_errno = NO_RECOVERY;
8055       errno = ENETDOWN;
8056       return NULL;
8057     }
8058 
8059   check_errno ();
8060   host = pfn_gethostbyname (name);
8061   if (!host)
8062     {
8063       set_errno ();
8064       h_errno = errno;
8065     }
8066   else
8067     h_errno = h_err;
8068   return host;
8069 }
8070 
8071 struct servent *
sys_getservbyname(const char * name,const char * proto)8072 sys_getservbyname (const char * name, const char * proto)
8073 {
8074   struct servent * serv;
8075 
8076   if (winsock_lib == NULL)
8077     {
8078       errno = ENETDOWN;
8079       return NULL;
8080     }
8081 
8082   check_errno ();
8083   serv = pfn_getservbyname (name, proto);
8084   if (!serv)
8085     set_errno ();
8086   return serv;
8087 }
8088 
8089 int
sys_getpeername(int s,struct sockaddr * addr,int * namelen)8090 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
8091 {
8092   if (winsock_lib == NULL)
8093     {
8094       errno = ENETDOWN;
8095       return SOCKET_ERROR;
8096     }
8097 
8098   check_errno ();
8099   if (fd_info[s].flags & FILE_SOCKET)
8100     {
8101       int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
8102       if (rc == SOCKET_ERROR)
8103 	set_errno ();
8104       return rc;
8105     }
8106   errno = ENOTSOCK;
8107   return SOCKET_ERROR;
8108 }
8109 
8110 int
sys_getaddrinfo(const char * node,const char * service,const struct addrinfo * hints,struct addrinfo ** res)8111 sys_getaddrinfo (const char *node, const char *service,
8112 		 const struct addrinfo *hints, struct addrinfo **res)
8113 {
8114   int rc;
8115 
8116   if (winsock_lib == NULL)
8117     {
8118       errno = ENETDOWN;
8119       return SOCKET_ERROR;
8120     }
8121 
8122   check_errno ();
8123   if (pfn_getaddrinfo)
8124     rc = pfn_getaddrinfo (node, service, hints, res);
8125   else
8126     {
8127       int port = 0;
8128       struct hostent *host_info;
8129       struct gai_storage {
8130 	struct addrinfo addrinfo;
8131 	struct sockaddr_in sockaddr_in;
8132       } *gai_storage;
8133 
8134       /* We don't (yet) support any flags, as Emacs doesn't need that.  */
8135       if (hints && hints->ai_flags != 0)
8136 	return WSAEINVAL;
8137       /* NODE cannot be NULL, since process.c has fallbacks for that.  */
8138       if (!node)
8139 	return WSAHOST_NOT_FOUND;
8140 
8141       if (service)
8142 	{
8143 	  const char *protocol =
8144 	    (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
8145 	  struct servent *srv = sys_getservbyname (service, protocol);
8146 
8147 	  if (srv)
8148 	    port = srv->s_port;
8149 	  else if (*service >= '0' && *service <= '9')
8150 	    {
8151 	      char *endp;
8152 
8153 	      port = strtoul (service, &endp, 10);
8154 	      if (*endp || port > 65536)
8155 		return WSAHOST_NOT_FOUND;
8156 	      port = sys_htons ((unsigned short) port);
8157 	    }
8158 	  else
8159 	    return WSAHOST_NOT_FOUND;
8160 	}
8161 
8162       gai_storage = xzalloc (sizeof *gai_storage);
8163       gai_storage->sockaddr_in.sin_port = port;
8164       host_info = sys_gethostbyname (node);
8165       if (host_info)
8166 	{
8167 	  memcpy (&gai_storage->sockaddr_in.sin_addr,
8168 		  host_info->h_addr, host_info->h_length);
8169 	  gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
8170 	}
8171       else
8172 	{
8173 	  /* Attempt to interpret host as numeric inet address.  */
8174 	  unsigned long numeric_addr = sys_inet_addr (node);
8175 
8176 	  if (numeric_addr == -1)
8177 	    {
8178 	      free (gai_storage);
8179 	      return WSAHOST_NOT_FOUND;
8180 	    }
8181 
8182 	  memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
8183 		  sizeof (gai_storage->sockaddr_in.sin_addr));
8184 	  gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
8185 	}
8186 
8187       gai_storage->addrinfo.ai_addr =
8188 	(struct sockaddr *)&gai_storage->sockaddr_in;
8189       gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
8190       gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
8191       gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
8192       gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
8193       gai_storage->addrinfo.ai_next = NULL;
8194 
8195       *res = &gai_storage->addrinfo;
8196       rc = 0;
8197     }
8198 
8199   return rc;
8200 }
8201 
8202 void
sys_freeaddrinfo(struct addrinfo * ai)8203 sys_freeaddrinfo (struct addrinfo *ai)
8204 {
8205   if (winsock_lib == NULL)
8206     {
8207       errno = ENETDOWN;
8208       return;
8209     }
8210 
8211   check_errno ();
8212   if (pfn_freeaddrinfo)
8213     pfn_freeaddrinfo (ai);
8214   else
8215     {
8216       eassert (ai->ai_next == NULL);
8217       xfree (ai);
8218     }
8219 }
8220 
8221 int
sys_shutdown(int s,int how)8222 sys_shutdown (int s, int how)
8223 {
8224   if (winsock_lib == NULL)
8225     {
8226       errno = ENETDOWN;
8227       return SOCKET_ERROR;
8228     }
8229 
8230   check_errno ();
8231   if (fd_info[s].flags & FILE_SOCKET)
8232     {
8233       int rc = pfn_shutdown (SOCK_HANDLE (s), how);
8234       if (rc == SOCKET_ERROR)
8235 	set_errno ();
8236       return rc;
8237     }
8238   errno = ENOTSOCK;
8239   return SOCKET_ERROR;
8240 }
8241 
8242 int
sys_setsockopt(int s,int level,int optname,const void * optval,int optlen)8243 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
8244 {
8245   if (winsock_lib == NULL)
8246     {
8247       errno = ENETDOWN;
8248       return SOCKET_ERROR;
8249     }
8250 
8251   check_errno ();
8252   if (fd_info[s].flags & FILE_SOCKET)
8253     {
8254       int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
8255 			       (const char *)optval, optlen);
8256       if (rc == SOCKET_ERROR)
8257 	set_errno ();
8258       return rc;
8259     }
8260   errno = ENOTSOCK;
8261   return SOCKET_ERROR;
8262 }
8263 
8264 int
sys_listen(int s,int backlog)8265 sys_listen (int s, int backlog)
8266 {
8267   if (winsock_lib == NULL)
8268     {
8269       errno = ENETDOWN;
8270       return SOCKET_ERROR;
8271     }
8272 
8273   check_errno ();
8274   if (fd_info[s].flags & FILE_SOCKET)
8275     {
8276       int rc = pfn_listen (SOCK_HANDLE (s), backlog);
8277       if (rc == SOCKET_ERROR)
8278 	set_errno ();
8279       else
8280 	fd_info[s].flags |= FILE_LISTEN;
8281       return rc;
8282     }
8283   errno = ENOTSOCK;
8284   return SOCKET_ERROR;
8285 }
8286 
8287 int
sys_getsockname(int s,struct sockaddr * name,int * namelen)8288 sys_getsockname (int s, struct sockaddr * name, int * namelen)
8289 {
8290   if (winsock_lib == NULL)
8291     {
8292       errno = ENETDOWN;
8293       return SOCKET_ERROR;
8294     }
8295 
8296   check_errno ();
8297   if (fd_info[s].flags & FILE_SOCKET)
8298     {
8299       int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
8300       if (rc == SOCKET_ERROR)
8301 	set_errno ();
8302       return rc;
8303     }
8304   errno = ENOTSOCK;
8305   return SOCKET_ERROR;
8306 }
8307 
8308 int
sys_accept(int s,struct sockaddr * addr,int * addrlen)8309 sys_accept (int s, struct sockaddr * addr, int * addrlen)
8310 {
8311   if (winsock_lib == NULL)
8312     {
8313       errno = ENETDOWN;
8314       return -1;
8315     }
8316 
8317   check_errno ();
8318   if (fd_info[s].flags & FILE_LISTEN)
8319     {
8320       SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
8321       int fd = -1;
8322       if (t == INVALID_SOCKET)
8323 	set_errno ();
8324       else
8325 	fd = socket_to_fd (t);
8326 
8327       if (fd >= 0)
8328 	{
8329 	  fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
8330 	  ResetEvent (fd_info[s].cp->char_avail);
8331 	}
8332       return fd;
8333     }
8334   errno = ENOTSOCK;
8335   return -1;
8336 }
8337 
8338 int
sys_recvfrom(int s,char * buf,int len,int flags,struct sockaddr * from,int * fromlen)8339 sys_recvfrom (int s, char * buf, int len, int flags,
8340 	      struct sockaddr * from, int * fromlen)
8341 {
8342   if (winsock_lib == NULL)
8343     {
8344       errno = ENETDOWN;
8345       return SOCKET_ERROR;
8346     }
8347 
8348   check_errno ();
8349   if (fd_info[s].flags & FILE_SOCKET)
8350     {
8351       int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
8352       if (rc == SOCKET_ERROR)
8353 	set_errno ();
8354       return rc;
8355     }
8356   errno = ENOTSOCK;
8357   return SOCKET_ERROR;
8358 }
8359 
8360 int
sys_sendto(int s,const char * buf,int len,int flags,const struct sockaddr * to,int tolen)8361 sys_sendto (int s, const char * buf, int len, int flags,
8362 	    const struct sockaddr * to, int tolen)
8363 {
8364   if (winsock_lib == NULL)
8365     {
8366       errno = ENETDOWN;
8367       return SOCKET_ERROR;
8368     }
8369 
8370   check_errno ();
8371   if (fd_info[s].flags & FILE_SOCKET)
8372     {
8373       int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
8374       if (rc == SOCKET_ERROR)
8375 	set_errno ();
8376       return rc;
8377     }
8378   errno = ENOTSOCK;
8379   return SOCKET_ERROR;
8380 }
8381 
8382 /* Windows does not have an fcntl function.  Provide an implementation
8383    good enough for Emacs.  */
8384 int
fcntl(int s,int cmd,int options)8385 fcntl (int s, int cmd, int options)
8386 {
8387   /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
8388      invoked in a context where fd1 is closed and all descriptors less
8389      than fd1 are open, so sys_dup is an adequate implementation.  */
8390   if (cmd == F_DUPFD_CLOEXEC)
8391     return sys_dup (s);
8392 
8393   check_errno ();
8394   if (fd_info[s].flags & FILE_SOCKET)
8395     {
8396       if (winsock_lib == NULL)
8397 	{
8398 	  errno = ENETDOWN;
8399 	  return -1;
8400 	}
8401 
8402       if (cmd == F_SETFL && options == O_NONBLOCK)
8403 	{
8404 	  unsigned long nblock = 1;
8405 	  int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
8406 	  if (rc == SOCKET_ERROR)
8407 	    set_errno ();
8408 	  /* Keep track of the fact that we set this to non-blocking.  */
8409 	  fd_info[s].flags |= FILE_NDELAY;
8410 	  return rc;
8411 	}
8412       else
8413 	{
8414 	  errno = EINVAL;
8415 	  return SOCKET_ERROR;
8416 	}
8417     }
8418   else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE))
8419 	   == (FILE_PIPE | FILE_WRITE))
8420     {
8421       /* Force our writes to pipes be non-blocking.  */
8422       if (cmd == F_SETFL && options == O_NONBLOCK)
8423 	{
8424 	  HANDLE h = (HANDLE)_get_osfhandle (s);
8425 	  DWORD pipe_mode = PIPE_NOWAIT;
8426 
8427 	  if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL))
8428 	    {
8429 	      DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ()));
8430 	      return SOCKET_ERROR;
8431 	    }
8432 	  fd_info[s].flags |= FILE_NDELAY;
8433 	  return 0;
8434 	}
8435       else
8436 	{
8437 	  errno = EINVAL;
8438 	  return SOCKET_ERROR;
8439 	}
8440     }
8441   errno = ENOTSOCK;
8442   return SOCKET_ERROR;
8443 }
8444 
8445 
8446 /* Shadow main io functions: we need to handle pipes and sockets more
8447    intelligently.  */
8448 
8449 int
sys_close(int fd)8450 sys_close (int fd)
8451 {
8452   int rc;
8453 
8454   if (fd < 0)
8455     {
8456       errno = EBADF;
8457       return -1;
8458     }
8459 
8460   if (fd < MAXDESC && fd_info[fd].cp)
8461     {
8462       child_process * cp = fd_info[fd].cp;
8463 
8464       fd_info[fd].cp = NULL;
8465 
8466       if (CHILD_ACTIVE (cp))
8467         {
8468 	  /* if last descriptor to active child_process then cleanup */
8469 	  int i;
8470 	  for (i = 0; i < MAXDESC; i++)
8471 	    {
8472 	      if (i == fd)
8473 		continue;
8474 	      if (fd_info[i].cp == cp)
8475 		break;
8476 	    }
8477 	  if (i == MAXDESC)
8478 	    {
8479 	      if (fd_info[fd].flags & FILE_SOCKET)
8480 		{
8481 		  if (winsock_lib == NULL) emacs_abort ();
8482 
8483 		  pfn_shutdown (SOCK_HANDLE (fd), 2);
8484 		  rc = pfn_closesocket (SOCK_HANDLE (fd));
8485 
8486 		  winsock_inuse--; /* count open sockets */
8487 		}
8488 	      /* If the process handle is NULL, it's either a socket
8489 		 or serial connection, or a subprocess that was
8490 		 already reaped by reap_subprocess, but whose
8491 		 resources were not yet freed, because its output was
8492 		 not fully read yet by the time it was reaped.  (This
8493 		 usually happens with async subprocesses whose output
8494 		 is being read by Emacs.)  Otherwise, this process was
8495 		 not reaped yet, so we set its FD to a negative value
8496 		 to make sure sys_select will eventually get to
8497 		 calling the SIGCHLD handler for it, which will then
8498 		 invoke waitpid and reap_subprocess.  */
8499 	      if (cp->procinfo.hProcess == NULL)
8500 		delete_child (cp);
8501 	      else
8502 		cp->fd = -1;
8503 	    }
8504 	}
8505     }
8506 
8507   if (fd >= 0 && fd < MAXDESC)
8508     fd_info[fd].flags = 0;
8509 
8510   /* Note that sockets do not need special treatment here (at least on
8511      NT and Windows 95 using the standard tcp/ip stacks) - it appears that
8512      closesocket is equivalent to CloseHandle, which is to be expected
8513      because socket handles are fully fledged kernel handles. */
8514   rc = _close (fd);
8515 
8516   return rc;
8517 }
8518 
8519 int
sys_dup(int fd)8520 sys_dup (int fd)
8521 {
8522   int new_fd;
8523 
8524   new_fd = _dup (fd);
8525   if (new_fd >= 0 && new_fd < MAXDESC)
8526     {
8527       /* duplicate our internal info as well */
8528       fd_info[new_fd] = fd_info[fd];
8529     }
8530   return new_fd;
8531 }
8532 
8533 int
sys_dup2(int src,int dst)8534 sys_dup2 (int src, int dst)
8535 {
8536   int rc;
8537 
8538   if (dst < 0 || dst >= MAXDESC)
8539     {
8540       errno = EBADF;
8541       return -1;
8542     }
8543 
8544   /* MS _dup2 seems to have weird side effect when invoked with 2
8545      identical arguments: an attempt to fclose the corresponding stdio
8546      stream after that hangs (we do close standard streams in
8547      init_ntproc).  Attempt to avoid that by not calling _dup2 that
8548      way: if SRC is valid, we know that dup2 should be a no-op, so do
8549      nothing and return DST.  */
8550   if (src == dst)
8551     {
8552       if ((HANDLE)_get_osfhandle (src) == INVALID_HANDLE_VALUE)
8553 	{
8554 	  errno = EBADF;
8555 	  return -1;
8556 	}
8557       return dst;
8558     }
8559 
8560   /* Make sure we close the destination first if it's a pipe or socket.  */
8561   if (fd_info[dst].flags != 0)
8562     sys_close (dst);
8563 
8564   rc = _dup2 (src, dst);
8565   if (rc == 0)
8566     {
8567       /* Duplicate our internal info as well.  */
8568       fd_info[dst] = fd_info[src];
8569     }
8570   return rc == 0 ? dst : rc;
8571 }
8572 
8573 int
pipe2(int * phandles,int pipe2_flags)8574 pipe2 (int * phandles, int pipe2_flags)
8575 {
8576   int rc;
8577   unsigned flags;
8578   unsigned pipe_size = 0;
8579 
8580   eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
8581 
8582   /* Allow Lisp to override the default buffer size of the pipe.  */
8583   if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
8584     pipe_size = w32_pipe_buffer_size;
8585 
8586   /* make pipe handles non-inheritable; when we spawn a child, we
8587      replace the relevant handle with an inheritable one.  Also put
8588      pipes into binary mode; we will do text mode translation ourselves
8589      if required.  */
8590   rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
8591 
8592   if (rc == 0)
8593     {
8594       /* Protect against overflow, since Windows can open more handles than
8595 	 our fd_info array has room for.  */
8596       if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
8597 	{
8598 	  _close (phandles[0]);
8599 	  _close (phandles[1]);
8600 	  errno = EMFILE;
8601 	  rc = -1;
8602 	}
8603       else
8604 	{
8605 	  flags = FILE_PIPE | FILE_READ | FILE_BINARY;
8606 	  fd_info[phandles[0]].flags = flags;
8607 
8608 	  flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
8609 	  fd_info[phandles[1]].flags = flags;
8610 	}
8611     }
8612 
8613   return rc;
8614 }
8615 
8616 /* Function to do blocking read of one byte, needed to implement
8617    select.  It is only allowed on communication ports, sockets, or
8618    pipes. */
8619 int
_sys_read_ahead(int fd)8620 _sys_read_ahead (int fd)
8621 {
8622   child_process * cp;
8623   int rc;
8624 
8625   if (fd < 0 || fd >= MAXDESC)
8626     return STATUS_READ_ERROR;
8627 
8628   cp = fd_info[fd].cp;
8629 
8630   if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8631     return STATUS_READ_ERROR;
8632 
8633   if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
8634       || (fd_info[fd].flags & FILE_READ) == 0)
8635     {
8636       DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
8637       emacs_abort ();
8638     }
8639 
8640   if ((fd_info[fd].flags & FILE_CONNECT) != 0)
8641     DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd));
8642   cp->status = STATUS_READ_IN_PROGRESS;
8643 
8644   if (fd_info[fd].flags & FILE_PIPE)
8645     {
8646       rc = _read (fd, &cp->chr, sizeof (char));
8647 
8648       /* Optionally give subprocess time to buffer some more output
8649 	 for us before reporting that input is available; we may need
8650 	 this because Windows 9X connects DOS programs to pipes by
8651 	 making the pipe appear to be the normal console stdout -- as
8652 	 a result most DOS programs will write to stdout without
8653 	 buffering, i.e., one character at a time.  Even some W32
8654 	 programs do this -- "dir" in a command shell on NT is very
8655 	 slow if we don't do this.  */
8656       if (rc > 0)
8657 	{
8658 	  int wait = w32_pipe_read_delay;
8659 
8660 	  if (wait > 0)
8661 	    Sleep (wait);
8662 	  else if (wait < 0)
8663 	    while (++wait <= 0)
8664 	      /* Yield remainder of our time slice, effectively giving a
8665 		 temporary priority boost to the child process. */
8666 	      Sleep (0);
8667 	}
8668     }
8669   else if (fd_info[fd].flags & FILE_SERIAL)
8670     {
8671       HANDLE hnd = fd_info[fd].hnd;
8672       OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8673       COMMTIMEOUTS ct;
8674 
8675       /* Configure timeouts for blocking read.  */
8676       if (!GetCommTimeouts (hnd, &ct))
8677 	{
8678 	  cp->status = STATUS_READ_ERROR;
8679 	  return STATUS_READ_ERROR;
8680 	}
8681       ct.ReadIntervalTimeout		= 0;
8682       ct.ReadTotalTimeoutMultiplier	= 0;
8683       ct.ReadTotalTimeoutConstant	= 0;
8684       if (!SetCommTimeouts (hnd, &ct))
8685 	{
8686 	  cp->status = STATUS_READ_ERROR;
8687 	  return STATUS_READ_ERROR;
8688 	}
8689 
8690       if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
8691 	{
8692 	  if (GetLastError () != ERROR_IO_PENDING)
8693 	    {
8694 	      cp->status = STATUS_READ_ERROR;
8695 	      return STATUS_READ_ERROR;
8696 	    }
8697 	  if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8698 	    {
8699 	      cp->status = STATUS_READ_ERROR;
8700 	      return STATUS_READ_ERROR;
8701 	    }
8702 	}
8703     }
8704   else if (fd_info[fd].flags & FILE_SOCKET)
8705     {
8706       unsigned long nblock = 0;
8707       /* We always want this to block, so temporarily disable NDELAY.  */
8708       if (fd_info[fd].flags & FILE_NDELAY)
8709 	pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8710 
8711       rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
8712 
8713       if (fd_info[fd].flags & FILE_NDELAY)
8714 	{
8715 	  nblock = 1;
8716 	  pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8717 	}
8718     }
8719 
8720   if (rc == sizeof (char))
8721     cp->status = STATUS_READ_SUCCEEDED;
8722   else
8723     cp->status = STATUS_READ_FAILED;
8724 
8725   return cp->status;
8726 }
8727 
8728 int
_sys_wait_accept(int fd)8729 _sys_wait_accept (int fd)
8730 {
8731   HANDLE hEv;
8732   child_process * cp;
8733   int rc;
8734 
8735   if (fd < 0 || fd >= MAXDESC)
8736     return STATUS_READ_ERROR;
8737 
8738   cp = fd_info[fd].cp;
8739 
8740   if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8741     return STATUS_READ_ERROR;
8742 
8743   cp->status = STATUS_READ_FAILED;
8744 
8745   hEv = pfn_WSACreateEvent ();
8746   rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
8747   if (rc != SOCKET_ERROR)
8748     {
8749       do {
8750 	rc = WaitForSingleObject (hEv, 500);
8751 	Sleep (5);
8752       } while (rc == WAIT_TIMEOUT
8753 	       && cp->status != STATUS_READ_ERROR
8754 	       && cp->char_avail);
8755       pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8756       if (rc == WAIT_OBJECT_0)
8757 	cp->status = STATUS_READ_SUCCEEDED;
8758     }
8759   pfn_WSACloseEvent (hEv);
8760 
8761   return cp->status;
8762 }
8763 
8764 int
_sys_wait_connect(int fd)8765 _sys_wait_connect (int fd)
8766 {
8767   HANDLE hEv;
8768   child_process * cp;
8769   int rc;
8770 
8771   if (fd < 0 || fd >= MAXDESC)
8772     return STATUS_READ_ERROR;
8773 
8774   cp = fd_info[fd].cp;
8775   if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8776     return STATUS_READ_ERROR;
8777 
8778   cp->status = STATUS_READ_FAILED;
8779 
8780   hEv = pfn_WSACreateEvent ();
8781   rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT);
8782   if (rc != SOCKET_ERROR)
8783     {
8784       do {
8785 	rc = WaitForSingleObject (hEv, 500);
8786 	Sleep (5);
8787       } while (rc == WAIT_TIMEOUT
8788 	       && cp->status != STATUS_READ_ERROR
8789 	       && cp->char_avail);
8790       if (rc == WAIT_OBJECT_0)
8791 	{
8792 	  /* We've got an event, but it could be a successful
8793 	     connection, or it could be a failure.  Find out
8794 	     which one is it.  */
8795 	  WSANETWORKEVENTS events;
8796 
8797 	  pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events);
8798 	  if ((events.lNetworkEvents & FD_CONNECT) != 0
8799 	      && events.iErrorCode[FD_CONNECT_BIT])
8800 	    {
8801 	      cp->status = STATUS_CONNECT_FAILED;
8802 	      cp->errcode = events.iErrorCode[FD_CONNECT_BIT];
8803 	    }
8804 	  else
8805 	    {
8806 	      cp->status = STATUS_READ_SUCCEEDED;
8807 	      cp->errcode = 0;
8808 	    }
8809 	}
8810       pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8811     }
8812   else
8813     pfn_WSACloseEvent (hEv);
8814 
8815   return cp->status;
8816 }
8817 
8818 int
sys_read(int fd,char * buffer,unsigned int count)8819 sys_read (int fd, char * buffer, unsigned int count)
8820 {
8821   int nchars;
8822   int to_read;
8823   DWORD waiting;
8824   char * orig_buffer = buffer;
8825 
8826   if (fd < 0)
8827     {
8828       errno = EBADF;
8829       return -1;
8830     }
8831 
8832   if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8833     {
8834       child_process *cp = fd_info[fd].cp;
8835 
8836       if ((fd_info[fd].flags & FILE_READ) == 0)
8837         {
8838 	  errno = EBADF;
8839 	  return -1;
8840 	}
8841 
8842       nchars = 0;
8843 
8844       /* re-read CR carried over from last read */
8845       if (fd_info[fd].flags & FILE_LAST_CR)
8846 	{
8847 	  if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
8848 	  *buffer++ = 0x0d;
8849 	  count--;
8850 	  nchars++;
8851 	  fd_info[fd].flags &= ~FILE_LAST_CR;
8852 	}
8853 
8854       /* presence of a child_process structure means we are operating in
8855 	 non-blocking mode - otherwise we just call _read directly.
8856 	 Note that the child_process structure might be missing because
8857 	 reap_subprocess has been called; in this case the pipe is
8858 	 already broken, so calling _read on it is okay. */
8859       if (cp)
8860         {
8861 	  int current_status = cp->status;
8862 
8863 	  switch (current_status)
8864 	    {
8865 	    case STATUS_READ_FAILED:
8866 	    case STATUS_READ_ERROR:
8867 	      /* report normal EOF if nothing in buffer */
8868 	      if (nchars <= 0)
8869 		fd_info[fd].flags |= FILE_AT_EOF;
8870 	      return nchars;
8871 
8872 	    case STATUS_READ_READY:
8873 	    case STATUS_READ_IN_PROGRESS:
8874 #if 0
8875 	      /* This happens all the time during GnuTLS handshake
8876 		 with the remote, evidently because GnuTLS waits for
8877 		 the read to complete by retrying the read operation
8878 		 upon EAGAIN.  So I'm disabling the DebPrint to avoid
8879 		 wasting cycles on something that is not a real
8880 		 problem.  Enable if you need to debug something that
8881 		 bumps into this.  */
8882 	      DebPrint (("sys_read called when read is in progress %d\n",
8883 			 current_status));
8884 #endif
8885 	      errno = EWOULDBLOCK;
8886 	      return -1;
8887 
8888 	    case STATUS_READ_SUCCEEDED:
8889 	      /* consume read-ahead char */
8890 	      *buffer++ = cp->chr;
8891 	      count--;
8892 	      nchars++;
8893 	      cp->status = STATUS_READ_ACKNOWLEDGED;
8894 	      ResetEvent (cp->char_avail);
8895 
8896 	    case STATUS_READ_ACKNOWLEDGED:
8897 	    case STATUS_CONNECT_FAILED:
8898 	      break;
8899 
8900 	    default:
8901 	      DebPrint (("sys_read: bad status %d\n", current_status));
8902 	      errno = EBADF;
8903 	      return -1;
8904 	    }
8905 
8906 	  if (fd_info[fd].flags & FILE_PIPE)
8907 	    {
8908 	      PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
8909 	      to_read = min (waiting, (DWORD) count);
8910 
8911 	      if (to_read > 0)
8912 		nchars += _read (fd, buffer, to_read);
8913 	    }
8914 	  else if (fd_info[fd].flags & FILE_SERIAL)
8915 	    {
8916 	      HANDLE hnd = fd_info[fd].hnd;
8917 	      OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8918 	      int rc = 0;
8919 	      COMMTIMEOUTS ct;
8920 
8921 	      if (count > 0)
8922 		{
8923 		  /* Configure timeouts for non-blocking read.  */
8924 		  if (!GetCommTimeouts (hnd, &ct))
8925 		    {
8926 		      errno = EIO;
8927 		      return -1;
8928 		    }
8929 		  ct.ReadIntervalTimeout	 = MAXDWORD;
8930 		  ct.ReadTotalTimeoutMultiplier	 = 0;
8931 		  ct.ReadTotalTimeoutConstant	 = 0;
8932 		  if (!SetCommTimeouts (hnd, &ct))
8933 		    {
8934 		      errno = EIO;
8935 		      return -1;
8936 		    }
8937 
8938 		  if (!ResetEvent (ovl->hEvent))
8939 		    {
8940 		      errno = EIO;
8941 		      return -1;
8942 		    }
8943 		  if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8944 		    {
8945 		      if (GetLastError () != ERROR_IO_PENDING)
8946 			{
8947 			  errno = EIO;
8948 			  return -1;
8949 			}
8950 		      if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8951 			{
8952 			  errno = EIO;
8953 			  return -1;
8954 			}
8955 		    }
8956 		  nchars += rc;
8957 		}
8958 	    }
8959 	  else /* FILE_SOCKET */
8960 	    {
8961 	      if (winsock_lib == NULL) emacs_abort ();
8962 
8963 	      /* When a non-blocking 'connect' call fails,
8964 		 wait_reading_process_output detects this by calling
8965 		 'getpeername', and then attempts to obtain the connection
8966 		 error code by trying to read 1 byte from the socket.  If
8967 		 we try to serve that read by calling 'recv' below, the
8968 		 error we get is a generic WSAENOTCONN, not the actual
8969 		 connection error.  So instead, we use the actual error
8970 		 code stashed by '_sys_wait_connect' in cp->errcode.
8971 		 Alternatively, we could have used 'getsockopt', like on
8972 		 GNU/Linux, but: (a) I have no idea whether the winsock
8973 		 version could hang, as it does "on some systems" (see the
8974 		 comment in process.c); and (b) 'getsockopt' on Windows is
8975 		 documented to clear the socket error for the entire
8976 		 process, which I'm not sure is TRT; FIXME.  */
8977 	      if (current_status == STATUS_CONNECT_FAILED
8978 		  && (fd_info[fd].flags & FILE_CONNECT) != 0
8979 		  && cp->errcode != 0)
8980 		{
8981 		  pfn_WSASetLastError (cp->errcode);
8982 		  set_errno ();
8983 		  return -1;
8984 		}
8985 	      /* Do the equivalent of a non-blocking read.  */
8986 	      pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8987 	      if (waiting == 0 && nchars == 0)
8988 	        {
8989 		  errno = EWOULDBLOCK;
8990 		  return -1;
8991 		}
8992 
8993 	      if (waiting)
8994 	        {
8995 		  /* always use binary mode for sockets */
8996 		  int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8997 		  if (res == SOCKET_ERROR)
8998 		    {
8999 		      set_errno ();
9000 		      DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
9001 				 errno, SOCK_HANDLE (fd)));
9002 		      return -1;
9003 		    }
9004 		  nchars += res;
9005 		}
9006 	    }
9007 	}
9008       else
9009 	{
9010 	  int nread = _read (fd, buffer, count);
9011 	  if (nread >= 0)
9012 	    nchars += nread;
9013 	  else if (nchars == 0)
9014 	    nchars = nread;
9015 	}
9016 
9017       if (nchars <= 0)
9018 	fd_info[fd].flags |= FILE_AT_EOF;
9019       /* Perform text mode translation if required.  */
9020       else if ((fd_info[fd].flags & FILE_BINARY) == 0)
9021 	{
9022 	  nchars = crlf_to_lf (nchars, orig_buffer);
9023 	  /* If buffer contains only CR, return that.  To be absolutely
9024 	     sure we should attempt to read the next char, but in
9025 	     practice a CR to be followed by LF would not appear by
9026 	     itself in the buffer.  */
9027 	  if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
9028 	    {
9029 	      fd_info[fd].flags |= FILE_LAST_CR;
9030 	      nchars--;
9031 	    }
9032 	}
9033     }
9034   else
9035     nchars = _read (fd, buffer, count);
9036 
9037   return nchars;
9038 }
9039 
9040 /* From w32xfns.c */
9041 extern HANDLE interrupt_handle;
9042 
9043 int
sys_write(int fd,const void * buffer,unsigned int count)9044 sys_write (int fd, const void * buffer, unsigned int count)
9045 {
9046   int nchars;
9047   USE_SAFE_ALLOCA;
9048 
9049   if (fd < 0)
9050     {
9051       errno = EBADF;
9052       return -1;
9053     }
9054 
9055   if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
9056     {
9057       if ((fd_info[fd].flags & FILE_WRITE) == 0)
9058 	{
9059 	  errno = EBADF;
9060 	  return -1;
9061 	}
9062 
9063       /* Perform text mode translation if required.  */
9064       if ((fd_info[fd].flags & FILE_BINARY) == 0)
9065 	{
9066 	  char * tmpbuf;
9067 	  const unsigned char * src = buffer;
9068 	  unsigned char * dst;
9069 	  int nbytes = count;
9070 
9071 	  SAFE_NALLOCA (tmpbuf, 2, count);
9072 	  dst = (unsigned char *)tmpbuf;
9073 
9074 	  while (1)
9075 	    {
9076 	      unsigned char *next;
9077 	      /* Copy next line or remaining bytes.  */
9078 	      next = _memccpy (dst, src, '\n', nbytes);
9079 	      if (next)
9080 		{
9081 		  /* Copied one line ending with '\n'.  */
9082 		  int copied = next - dst;
9083 		  nbytes -= copied;
9084 		  src += copied;
9085 		  /* Insert '\r' before '\n'.  */
9086 		  next[-1] = '\r';
9087 		  next[0] = '\n';
9088 		  dst = next + 1;
9089 		  count++;
9090 		}
9091 	      else
9092 		/* Copied remaining partial line -> now finished.  */
9093 		break;
9094 	    }
9095 	  buffer = tmpbuf;
9096 	}
9097     }
9098 
9099   if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
9100     {
9101       HANDLE hnd = (HANDLE) _get_osfhandle (fd);
9102       OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
9103       HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
9104       DWORD active = 0;
9105 
9106       /* This is async (a.k.a. "overlapped") I/O, so the return value
9107 	 of FALSE from WriteFile means either an error or the output
9108 	 will be completed asynchronously (ERROR_IO_PENDING).  */
9109       if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
9110 	{
9111 	  if (GetLastError () != ERROR_IO_PENDING)
9112 	    {
9113 	      errno = EIO;
9114 	      nchars = -1;
9115 	    }
9116 	  else
9117 	    {
9118 	      /* Wait for the write to complete, and watch C-g while
9119 		 at that.  */
9120 	      if (detect_input_pending ())
9121 		active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
9122 						    INFINITE, QS_ALLINPUT);
9123 	      else
9124 		active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
9125 	      switch (active)
9126 		{
9127 		case WAIT_OBJECT_0:
9128 		  /* User pressed C-g, cancel write, then leave.
9129 		     Don't bother cleaning up as we may only get stuck
9130 		     in buggy drivers.  */
9131 		  PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
9132 		  CancelIo (hnd);
9133 		  errno = EIO;	/* Why not EINTR? */
9134 		  nchars = -1;
9135 		  break;
9136 		case WAIT_OBJECT_0 + 1:
9137 		  if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
9138 		    {
9139 		      errno = EIO;
9140 		      nchars = -1;
9141 		    }
9142 		  break;
9143 		}
9144 	    }
9145 	}
9146     }
9147   else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
9148     {
9149       unsigned long nblock = 0;
9150       if (winsock_lib == NULL) emacs_abort ();
9151 
9152       child_process *cp = fd_info[fd].cp;
9153 
9154       /* If this is a non-blocking socket whose connection is in
9155 	 progress or terminated with an error already, return the
9156 	 proper error code to the caller. */
9157       if (cp != NULL && (fd_info[fd].flags & FILE_CONNECT) != 0)
9158 	{
9159 	  /* In case connection is in progress, ENOTCONN that would
9160 	     result from calling pfn_send is not what callers expect. */
9161 	  if (cp->status != STATUS_CONNECT_FAILED)
9162 	    {
9163 	      errno = EWOULDBLOCK;
9164 	      return -1;
9165 	    }
9166 	  /* In case connection failed, use the actual error code
9167 	     stashed by '_sys_wait_connect' in cp->errcode. */
9168 	  else if (cp->errcode != 0)
9169 	    {
9170 	      pfn_WSASetLastError (cp->errcode);
9171 	      set_errno ();
9172 	      return -1;
9173 	    }
9174 	}
9175 
9176       /* TODO: implement select() properly so non-blocking I/O works. */
9177       /* For now, make sure the write blocks.  */
9178       if (fd_info[fd].flags & FILE_NDELAY)
9179 	pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
9180 
9181       nchars =  pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
9182 
9183       if (nchars == SOCKET_ERROR)
9184         {
9185 	  set_errno ();
9186 	  DebPrint (("sys_write.send failed with error %d on socket %ld\n",
9187 		     pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
9188 	}
9189 
9190       /* Set the socket back to non-blocking if it was before,
9191 	 for other operations that support it.  */
9192       if (fd_info[fd].flags & FILE_NDELAY)
9193 	{
9194 	  nblock = 1;
9195 	  pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
9196 	}
9197     }
9198   else
9199     {
9200       /* Some networked filesystems don't like too large writes, so
9201 	 break them into smaller chunks.  See the Comments section of
9202 	 the MSDN documentation of WriteFile for details behind the
9203 	 choice of the value of CHUNK below.  See also the thread
9204 	 http://thread.gmane.org/gmane.comp.version-control.git/145294
9205 	 in the git mailing list.  */
9206       const unsigned char *p = buffer;
9207       const bool is_pipe = (fd < MAXDESC
9208 			    && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
9209 				== (FILE_PIPE | FILE_NDELAY)));
9210       /* Some programs, notably Node.js's node.exe, seem to never
9211 	 completely empty the pipe, so writing more than the size of
9212 	 the pipe's buffer always returns ENOSPC, and we loop forever
9213 	 between send_process and here.  As a workaround, write no
9214 	 more than the pipe's buffer can hold.  */
9215       DWORD pipe_buffer_size;
9216       if (is_pipe)
9217 	{
9218 	  if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
9219 				NULL, &pipe_buffer_size, NULL, NULL))
9220 	    {
9221 	      DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
9222 	      pipe_buffer_size = 4096;
9223 	    }
9224 	}
9225       const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
9226 
9227       nchars = 0;
9228       errno = 0;
9229       while (count > 0)
9230 	{
9231 	  unsigned this_chunk = count < chunk ? count : chunk;
9232 	  int n = _write (fd, p, this_chunk);
9233 
9234 	  if (n > 0)
9235 	    nchars += n;
9236 	  if (n < 0)
9237 	    {
9238 	      /* When there's no buffer space in a pipe that is in the
9239 		 non-blocking mode, _write returns ENOSPC.  We return
9240 		 EAGAIN instead, which should trigger the logic in
9241 		 send_process that enters waiting loop and calls
9242 		 wait_reading_process_output to allow process input to
9243 		 be accepted during the wait.  Those calls to
9244 		 wait_reading_process_output allow sys_select to
9245 		 notice when process input becomes available, thus
9246 		 avoiding deadlock whereby each side of the pipe is
9247 		 blocked on write, waiting for the other party to read
9248 		 its end of the pipe.  */
9249 	      if (errno == ENOSPC && is_pipe)
9250 		errno = EAGAIN;
9251 	      if (nchars == 0)
9252 		nchars = -1;
9253 	      break;
9254 	    }
9255 	  else if (n < this_chunk)
9256 	    break;
9257 	  count -= n;
9258 	  p += n;
9259 	}
9260     }
9261 
9262   SAFE_FREE ();
9263   return nchars;
9264 }
9265 
9266 
9267 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c.  */
9268 
9269 /* Return information about network interface IFNAME, or about all
9270    interfaces (if IFNAME is nil).  */
9271 static Lisp_Object
network_interface_get_info(Lisp_Object ifname)9272 network_interface_get_info (Lisp_Object ifname)
9273 {
9274   ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
9275   IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
9276   DWORD retval = get_adapters_info (ainfo, &ainfo_len);
9277   Lisp_Object res = Qnil;
9278 
9279   if (retval == ERROR_BUFFER_OVERFLOW)
9280     {
9281       ainfo = xrealloc (ainfo, ainfo_len);
9282       retval = get_adapters_info (ainfo, &ainfo_len);
9283     }
9284 
9285   if (retval == ERROR_SUCCESS)
9286     {
9287       int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
9288       int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
9289       int if_num;
9290       struct sockaddr_in sa;
9291 
9292       /* For the below, we need some winsock functions, so make sure
9293 	 the winsock DLL is loaded.  If we cannot successfully load
9294 	 it, they will have no use of the information we provide,
9295 	 anyway, so punt.  */
9296       if (!winsock_lib && !init_winsock (1))
9297 	goto done;
9298 
9299       for (adapter = ainfo; adapter; adapter = adapter->Next)
9300 	{
9301 	  char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
9302 	  u_long ip_addr;
9303 	  /* Present Unix-compatible interface names, instead of the
9304 	     Windows names, which are really GUIDs not readable by
9305 	     humans.  */
9306 	  static const char *ifmt[] = {
9307 	    "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
9308 	    "lo", "ifx%d"
9309 	  };
9310 	  enum {
9311 	    NONE = -1,
9312 	    ETHERNET = 0,
9313 	    TOKENRING = 1,
9314 	    FDDI = 2,
9315 	    PPP = 3,
9316 	    SLIP = 4,
9317 	    WLAN = 5,
9318 	    LOOPBACK = 6,
9319 	    OTHER_IF = 7
9320 	  } ifmt_idx;
9321 
9322 	  switch (adapter->Type)
9323 	    {
9324 	    case MIB_IF_TYPE_ETHERNET:
9325 	      /* Windows before Vista reports wireless adapters as
9326 		 Ethernet.  Work around by looking at the Description
9327 		 string.  */
9328 	      if (strstr (adapter->Description, "Wireless "))
9329 		{
9330 		  ifmt_idx = WLAN;
9331 		  if_num = wlan_count++;
9332 		}
9333 	      else
9334 		{
9335 		  ifmt_idx = ETHERNET;
9336 		  if_num = eth_count++;
9337 		}
9338 	      break;
9339 	    case MIB_IF_TYPE_TOKENRING:
9340 	      ifmt_idx = TOKENRING;
9341 	      if_num = tr_count++;
9342 	      break;
9343 	    case MIB_IF_TYPE_FDDI:
9344 	      ifmt_idx = FDDI;
9345 	      if_num = fddi_count++;
9346 	      break;
9347 	    case MIB_IF_TYPE_PPP:
9348 	      ifmt_idx = PPP;
9349 	      if_num = ppp_count++;
9350 	      break;
9351 	    case MIB_IF_TYPE_SLIP:
9352 	      ifmt_idx = SLIP;
9353 	      if_num = sl_count++;
9354 	      break;
9355 	    case IF_TYPE_IEEE80211:
9356 	      ifmt_idx = WLAN;
9357 	      if_num = wlan_count++;
9358 	      break;
9359 	    case MIB_IF_TYPE_LOOPBACK:
9360 	      if (lo_count < 0)
9361 		{
9362 		  ifmt_idx = LOOPBACK;
9363 		  if_num = lo_count++;
9364 		}
9365 	      else
9366 		ifmt_idx = NONE;
9367 	      break;
9368 	    default:
9369 	      ifmt_idx = OTHER_IF;
9370 	      if_num = ifx_count++;
9371 	      break;
9372 	    }
9373 	  if (ifmt_idx == NONE)
9374 	    continue;
9375 	  sprintf (namebuf, ifmt[ifmt_idx], if_num);
9376 
9377 	  sa.sin_family = AF_INET;
9378 	  ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
9379 	  if (ip_addr == INADDR_NONE)
9380 	    {
9381 	      /* Bogus address, skip this interface.  */
9382 	      continue;
9383 	    }
9384 	  sa.sin_addr.s_addr = ip_addr;
9385 	  sa.sin_port = 0;
9386 	  if (NILP (ifname))
9387 	    res = Fcons (Fcons (build_string (namebuf),
9388 				conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9389 						       sizeof (struct sockaddr))),
9390 			 res);
9391 	  else if (strcmp (namebuf, SSDATA (ifname)) == 0)
9392 	    {
9393 	      Lisp_Object hwaddr = Fmake_vector (make_fixnum (6), Qnil);
9394 	      register struct Lisp_Vector *p = XVECTOR (hwaddr);
9395 	      Lisp_Object flags = Qnil;
9396 	      int n;
9397 	      u_long net_mask;
9398 
9399 	      /* Flags.  We guess most of them by type, since the
9400 		 Windows flags are different and hard to get by.  */
9401 	      flags = Fcons (intern ("up"), flags);
9402 	      if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
9403 		{
9404 		  flags = Fcons (intern ("broadcast"), flags);
9405 		  flags = Fcons (intern ("multicast"), flags);
9406 		}
9407 	      flags = Fcons (intern ("running"), flags);
9408 	      if (ifmt_idx == PPP)
9409 		{
9410 		  flags = Fcons (intern ("pointopoint"), flags);
9411 		  flags = Fcons (intern ("noarp"), flags);
9412 		}
9413 	      if (adapter->HaveWins)
9414 		flags = Fcons (intern ("WINS"), flags);
9415 	      if (adapter->DhcpEnabled)
9416 		flags = Fcons (intern ("dynamic"), flags);
9417 
9418 	      res = Fcons (flags, res);
9419 
9420 	      /* Hardware address and its family.  */
9421 	      for (n = 0; n < adapter->AddressLength; n++)
9422 		p->contents[n] = make_fixnum ((int) adapter->Address[n]);
9423 	      /* Windows does not support AF_LINK or AF_PACKET family
9424 		 of addresses.  Use an arbitrary family number that is
9425 		 identical to what GNU/Linux returns.  */
9426 	      res = Fcons (Fcons (make_fixnum (1), hwaddr), res);
9427 
9428 	      /* Network mask.  */
9429 	      sa.sin_family = AF_INET;
9430 	      net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
9431 	      if (net_mask != INADDR_NONE)
9432 		{
9433 		  sa.sin_addr.s_addr = net_mask;
9434 		  sa.sin_port = 0;
9435 		  res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9436 						      sizeof (struct sockaddr)),
9437 			       res);
9438 		}
9439 	      else
9440 		res = Fcons (Qnil, res);
9441 
9442 	      sa.sin_family = AF_INET;
9443 	      if (ip_addr != INADDR_NONE)
9444 		{
9445 		  /* Broadcast address is only reported by
9446 		     GetAdaptersAddresses, which is of limited
9447 		     availability.  Generate it on our own.  */
9448 		  u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
9449 
9450 		  sa.sin_addr.s_addr = bcast_addr;
9451 		  sa.sin_port = 0;
9452 		  res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9453 						      sizeof (struct sockaddr)),
9454 			       res);
9455 
9456 		  /* IP address.  */
9457 		  sa.sin_addr.s_addr = ip_addr;
9458 		  sa.sin_port = 0;
9459 		  res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9460 						      sizeof (struct sockaddr)),
9461 			       res);
9462 		}
9463 	      else
9464 		res = Fcons (Qnil, Fcons (Qnil, res));
9465 	    }
9466 	}
9467       /* GetAdaptersInfo is documented to not report loopback
9468 	 interfaces, so we generate one out of thin air.  */
9469       if (!lo_count)
9470 	{
9471 	  sa.sin_family = AF_INET;
9472 	  sa.sin_port = 0;
9473 	  if (NILP (ifname))
9474 	    {
9475 	      sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9476 	      res = Fcons (Fcons (build_string ("lo"),
9477 				  conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9478 							 sizeof (struct sockaddr))),
9479 			   res);
9480 	    }
9481 	  else if (strcmp (SSDATA (ifname), "lo") == 0)
9482 	    {
9483 	      res = Fcons (Fcons (intern ("running"),
9484 				  Fcons (intern ("loopback"),
9485 					 Fcons (intern ("up"), Qnil))), Qnil);
9486 	      /* 772 is what 3 different GNU/Linux systems report for
9487 		 the loopback interface.  */
9488 	      res = Fcons (Fcons (make_fixnum (772),
9489 				  Fmake_vector (make_fixnum (6),
9490 						make_fixnum (0))),
9491 			   res);
9492 	      sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
9493 	      res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9494 						  sizeof (struct sockaddr)),
9495 			   res);
9496 	      sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
9497 	      res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9498 						  sizeof (struct sockaddr)),
9499 			   res);
9500 	      sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9501 	      res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9502 						  sizeof (struct sockaddr)),
9503 			   res);
9504 	    }
9505 
9506 	}
9507     }
9508 
9509  done:
9510   xfree (ainfo);
9511   return res;
9512 }
9513 
9514 static bool
address_prefix_match(int family,struct sockaddr * address,struct sockaddr * prefix_address,ULONG prefix_len)9515 address_prefix_match (int family, struct sockaddr *address,
9516 		      struct sockaddr *prefix_address, ULONG prefix_len)
9517 {
9518   UINT8 *address_data;
9519   UINT8 *prefix_address_data;
9520   int i;
9521 
9522   if (family == AF_INET6)
9523     {
9524       address_data = (UINT8 *) &(((struct sockaddr_in6 *) address)->sin6_addr);
9525       prefix_address_data =
9526 	(UINT8 *) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
9527     }
9528   else
9529     {
9530       address_data = (UINT8 *) &(((struct sockaddr_in *) address)->sin_addr);
9531       prefix_address_data =
9532 	(UINT8 *) &(((struct sockaddr_in *) prefix_address)->sin_addr);
9533     }
9534 
9535   for (i = 0; i < prefix_len >> 3; i++)
9536     {
9537       if (address_data[i] != prefix_address_data[i])
9538 	return false;
9539     }
9540 
9541   if (prefix_len % 8)
9542     return (prefix_address_data[i] ==
9543 	    (address_data[i] & (0xff << (8 - prefix_len % 8))));
9544 
9545   return true;
9546 }
9547 
9548 Lisp_Object
network_interface_list(bool full,unsigned short match)9549 network_interface_list (bool full, unsigned short match)
9550 {
9551   ULONG ainfo_len = sizeof (IP_ADAPTER_ADDRESSES);
9552   ULONG family = match;
9553   IP_ADAPTER_ADDRESSES *adapter, *ainfo = xmalloc (ainfo_len);
9554   DWORD retval = get_adapters_addresses (family, ainfo, &ainfo_len);
9555   Lisp_Object res = Qnil;
9556 
9557   if (retval == ERROR_BUFFER_OVERFLOW)
9558     {
9559       ainfo = xrealloc (ainfo, ainfo_len);
9560       retval = get_adapters_addresses (family, ainfo, &ainfo_len);
9561     }
9562 
9563   if (retval != ERROR_SUCCESS)
9564     {
9565       xfree (ainfo);
9566       return res;
9567     }
9568 
9569   /* For the below, we need some winsock functions, so make sure
9570      the winsock DLL is loaded.  If we cannot successfully load
9571      it, they will have no use of the information we provide,
9572      anyway, so punt.  */
9573   if (!winsock_lib && !init_winsock (1))
9574     return res;
9575 
9576   int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
9577   int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
9578   int tnl_count = 0;
9579   int if_num;
9580   char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
9581   static const char *ifmt[] = {
9582     "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
9583     "lo%d", "ifx%d", "tunnel%d"
9584   };
9585   enum {
9586     NONE = -1,
9587     ETHERNET = 0,
9588     TOKENRING = 1,
9589     FDDI = 2,
9590     PPP = 3,
9591     SLIP = 4,
9592     WLAN = 5,
9593     LOOPBACK = 6,
9594     OTHER_IF = 7,
9595     TUNNEL = 8
9596   } ifmt_idx;
9597 
9598   for (adapter = ainfo; adapter; adapter = adapter->Next)
9599     {
9600 
9601       /* Present Unix-compatible interface names, instead of the
9602          Windows names, which are really GUIDs not readable by
9603          humans.  */
9604 
9605       switch (adapter->IfType)
9606         {
9607         case IF_TYPE_ETHERNET_CSMACD:
9608           /* Windows before Vista reports wireless adapters as
9609              Ethernet.  Work around by looking at the Description
9610              string.  */
9611           {
9612           char description[MAX_UTF8_PATH];
9613           if (filename_from_utf16 (adapter->Description, description) == 0
9614               && strstr (description, "Wireless "))
9615             {
9616               ifmt_idx = WLAN;
9617               if_num = wlan_count++;
9618             }
9619           else
9620             {
9621               ifmt_idx = ETHERNET;
9622               if_num = eth_count++;
9623             }
9624           }
9625           break;
9626         case IF_TYPE_ISO88025_TOKENRING:
9627           ifmt_idx = TOKENRING;
9628           if_num = tr_count++;
9629           break;
9630         case IF_TYPE_FDDI:
9631           ifmt_idx = FDDI;
9632           if_num = fddi_count++;
9633           break;
9634         case IF_TYPE_PPP:
9635           ifmt_idx = PPP;
9636           if_num = ppp_count++;
9637           break;
9638         case IF_TYPE_SLIP:
9639           ifmt_idx = SLIP;
9640           if_num = sl_count++;
9641           break;
9642         case IF_TYPE_IEEE80211:
9643           ifmt_idx = WLAN;
9644           if_num = wlan_count++;
9645           break;
9646         case IF_TYPE_SOFTWARE_LOOPBACK:
9647           ifmt_idx = LOOPBACK;
9648           if_num = lo_count++;
9649           break;
9650         case IF_TYPE_TUNNEL:
9651           ifmt_idx = TUNNEL;
9652           if_num = tnl_count++;
9653           break;
9654         default:
9655           ifmt_idx = OTHER_IF;
9656           if_num = ifx_count++;
9657           break;
9658         }
9659       sprintf (namebuf, ifmt[ifmt_idx], if_num);
9660 
9661       IP_ADAPTER_UNICAST_ADDRESS *address;
9662       for (address = adapter->FirstUnicastAddress; address; address = address->Next)
9663         {
9664           int len;
9665           int addr_len;
9666           uint32_t *maskp;
9667           uint32_t *addrp;
9668           Lisp_Object elt = Qnil;
9669           struct sockaddr *ifa_addr = address->Address.lpSockaddr;
9670 
9671           if (ifa_addr == NULL)
9672             continue;
9673           if (match && ifa_addr->sa_family != match)
9674             continue;
9675 
9676           struct sockaddr_in ipv4;
9677 #ifdef AF_INET6
9678           struct sockaddr_in6 ipv6;
9679 #endif
9680           struct sockaddr *sin;
9681 
9682           if (ifa_addr->sa_family == AF_INET)
9683             {
9684               ipv4.sin_family = AF_INET;
9685               ipv4.sin_port = 0;
9686               DECLARE_POINTER_ALIAS (sin_in, struct sockaddr_in, ifa_addr);
9687               addrp = (uint32_t *)&sin_in->sin_addr;
9688               maskp = (uint32_t *)&ipv4.sin_addr;
9689               sin = (struct sockaddr *)&ipv4;
9690               len = sizeof (struct sockaddr_in);
9691               addr_len = 1;
9692             }
9693 #ifdef AF_INET6
9694           else if (ifa_addr->sa_family == AF_INET6)
9695             {
9696               ipv6.sin6_family = AF_INET6;
9697               ipv6.sin6_port = 0;
9698               DECLARE_POINTER_ALIAS (sin_in6, struct sockaddr_in6, ifa_addr);
9699               addrp = (uint32_t *)&sin_in6->sin6_addr;
9700               maskp = (uint32_t *)&ipv6.sin6_addr;
9701               sin = (struct sockaddr *)&ipv6;
9702               len = sizeof (struct sockaddr_in6);
9703               addr_len = 4;
9704             }
9705 #endif
9706           else
9707             continue;
9708 
9709           Lisp_Object addr = conv_sockaddr_to_lisp (ifa_addr, len);
9710 
9711           if (full)
9712             {
9713               /* GetAdaptersAddress returns information in network
9714                  byte order, so convert from host to network order
9715                  when generating the netmask.  */
9716               int i;
9717               ULONG numbits;
9718 	      if (w32_major_version >= 6) /* Vista or later */
9719 		{
9720 #if _WIN32_WINNT >= 0x0600
9721 		  numbits = address->OnLinkPrefixLength;
9722 #else
9723 		  /* Kludge alert!  OnLinkPrefixLength is only defined
9724 		     when compiling for Vista and later.  */
9725 		  numbits = *(UINT8 *) (&address->LeaseLifetime + 1);
9726 #endif
9727 		}
9728 	      else		/* Windows XP */
9729 		{
9730 		  IP_ADAPTER_PREFIX *prefix = adapter->FirstPrefix;
9731 		  numbits = 0;
9732 		  for ( ; prefix; prefix = prefix->Next)
9733 		    {
9734 		      /* We want the longest matching prefix.  */
9735 		      if ((prefix->Address.lpSockaddr->sa_family
9736 			   == ifa_addr->sa_family)
9737 			  && (prefix->PrefixLength > numbits)
9738 			  && address_prefix_match (ifa_addr->sa_family,
9739 						   ifa_addr,
9740 						   prefix->Address.lpSockaddr,
9741 						   prefix->PrefixLength))
9742 			numbits = prefix->PrefixLength;
9743 		    }
9744 		  if (!numbits)
9745 		    numbits = (ifa_addr->sa_family == AF_INET6) ? 128 : 32;
9746 		}
9747               for (i = 0; i < addr_len; i++)
9748                 {
9749                   if (numbits >= 32)
9750                     {
9751                       maskp[i] = -1U;
9752                       numbits -= 32;
9753                     }
9754                   else if (numbits)
9755                     {
9756                       maskp[i] = sys_htonl (-1U << (32 - numbits));
9757                       numbits = 0;
9758                     }
9759                   else
9760                     {
9761                       maskp[i] = 0;
9762                     }
9763                 }
9764               elt = Fcons (conv_sockaddr_to_lisp (sin, len), elt);
9765               uint32_t mask;
9766               for (i = 0; i < addr_len; i++)
9767                 {
9768                   mask = maskp[i];
9769                   maskp[i] = (addrp[i] & mask) | ~mask;
9770 
9771                 }
9772               elt = Fcons (conv_sockaddr_to_lisp (sin, len), elt);
9773               elt = Fcons (addr, elt);
9774             }
9775           else
9776             {
9777               elt = addr;
9778             }
9779           res = Fcons (Fcons (build_string (namebuf), elt), res);
9780         }
9781     }
9782   xfree (ainfo);
9783   return res;
9784 }
9785 
9786 Lisp_Object
network_interface_info(Lisp_Object ifname)9787 network_interface_info (Lisp_Object ifname)
9788 {
9789   CHECK_STRING (ifname);
9790   return network_interface_get_info (ifname);
9791 }
9792 
9793 
9794 /* Workhorse for w32-read-registry, which see.  */
9795 Lisp_Object
w32_read_registry(HKEY rootkey,Lisp_Object lkey,Lisp_Object lname)9796 w32_read_registry (HKEY rootkey, Lisp_Object lkey, Lisp_Object lname)
9797 {
9798   HKEY hkey = NULL;
9799   LONG status;
9800   DWORD vsize, vtype;
9801   LPBYTE pvalue;
9802   Lisp_Object val, retval;
9803   const char *key, *value_name = NULL;
9804   /* The following sizes are according to size limitations
9805      documented in MSDN.  */
9806   wchar_t key_w[255+1];
9807   wchar_t value_w[16*1024+1];
9808   bool use_unicode = is_windows_9x () == 0;
9809 
9810   if (use_unicode)
9811     {
9812       Lisp_Object encoded_key, encoded_vname;
9813 
9814       /* Convert input strings to UTF-16.  */
9815       encoded_key = code_convert_string_norecord (lkey, Qutf_16le, 1);
9816       memcpy (key_w, SSDATA (encoded_key), SBYTES (encoded_key));
9817       /* wchar_t strings need to be terminated by 2 NUL bytes.  */
9818       key_w [SBYTES (encoded_key)/2] = L'\0';
9819       encoded_vname = code_convert_string_norecord (lname, Qutf_16le, 1);
9820       memcpy (value_w, SSDATA (encoded_vname), SBYTES (encoded_vname));
9821       value_w[SBYTES (encoded_vname)/2] = L'\0';
9822 
9823       /* Mirror the slashes, if required.  */
9824       for (int i = 0; i < SBYTES (encoded_key)/2; i++)
9825 	{
9826 	  if (key_w[i] == L'/')
9827 	    key_w[i] = L'\\';
9828 	}
9829       if ((status = reg_open_key_ex_w (rootkey, key_w, 0,
9830 				       KEY_READ, &hkey)) == ERROR_NOT_SUPPORTED
9831 	  || (status = reg_query_value_ex_w (hkey, value_w, NULL, NULL, NULL,
9832 					     &vsize)) == ERROR_NOT_SUPPORTED
9833 	  || status != ERROR_SUCCESS)
9834 	{
9835 	  if (hkey)
9836 	    RegCloseKey (hkey);
9837 	  if (status != ERROR_NOT_SUPPORTED)
9838 	    return Qnil;
9839 	  use_unicode = 0;	/* fall back to non-Unicode calls */
9840 	}
9841     }
9842   if (!use_unicode)
9843     {
9844       /* Need to copy LKEY because we are going to modify it.  */
9845       Lisp_Object local_lkey = Fcopy_sequence (lkey);
9846 
9847       /* Mirror the slashes.  Note: this has to be done before
9848 	 encoding, because after encoding we cannot guarantee that a
9849 	 slash '/' always stands for itself, it could be part of some
9850 	 multibyte sequence.  */
9851       for (int i = 0; i < SBYTES (local_lkey); i++)
9852 	{
9853 	  if (SSDATA (local_lkey)[i] == '/')
9854 	    SSDATA (local_lkey)[i] = '\\';
9855 	}
9856 
9857       key = SSDATA (ENCODE_SYSTEM (local_lkey));
9858       value_name = SSDATA (ENCODE_SYSTEM (lname));
9859 
9860       if ((status = RegOpenKeyEx (rootkey, key, 0,
9861 				  KEY_READ, &hkey)) != ERROR_SUCCESS
9862 	  || (status = RegQueryValueEx (hkey, value_name, NULL,
9863 					NULL, NULL, &vsize)) != ERROR_SUCCESS)
9864 	{
9865 	  if (hkey)
9866 	    RegCloseKey (hkey);
9867 	  return Qnil;
9868 	}
9869     }
9870 
9871   pvalue = xzalloc (vsize);
9872   if (use_unicode)
9873     status = reg_query_value_ex_w (hkey, value_w, NULL, &vtype, pvalue, &vsize);
9874   else
9875     status = RegQueryValueEx (hkey, value_name, NULL, &vtype, pvalue, &vsize);
9876   if (status != ERROR_SUCCESS)
9877     {
9878       xfree (pvalue);
9879       RegCloseKey (hkey);
9880       return Qnil;
9881     }
9882 
9883   switch (vtype)
9884     {
9885       case REG_NONE:
9886 	retval = Qt;
9887 	break;
9888       case REG_DWORD:
9889 	retval = INT_TO_INTEGER (*((DWORD *)pvalue));
9890 	break;
9891       case REG_QWORD:
9892 	retval = INT_TO_INTEGER (*((long long *)pvalue));
9893 	break;
9894       case REG_BINARY:
9895 	{
9896 	  int i;
9897 	  unsigned char *dbuf = (unsigned char *)pvalue;
9898 
9899 	  val = make_uninit_vector (vsize);
9900 	  for (i = 0; i < vsize; i++)
9901 	    ASET (val, i, make_fixnum (dbuf[i]));
9902 
9903 	  retval = val;
9904 	  break;
9905 	}
9906       case REG_SZ:
9907 	if (use_unicode)
9908 	  {
9909 	    /* pvalue ends with 2 NUL bytes, but we need only one,
9910 	       and AUTO_STRING_WITH_LEN will add it.  */
9911 	    if (pvalue[vsize - 1] == '\0')
9912 	      vsize -= 2;
9913 	    AUTO_STRING_WITH_LEN (sval, (char *)pvalue, vsize);
9914 	    retval = from_unicode (sval);
9915 	  }
9916 	else
9917 	  {
9918 	    /* Don't waste a byte on the terminating NUL character,
9919 	       since make_unibyte_string will add one anyway.  */
9920 	    if (pvalue[vsize - 1] == '\0')
9921 	      vsize--;
9922 	    retval = DECODE_SYSTEM (make_unibyte_string (pvalue, vsize));
9923 	  }
9924 	break;
9925       case REG_EXPAND_SZ:
9926 	if (use_unicode)
9927 	  {
9928 	    wchar_t expanded_w[32*1024];
9929 	    DWORD dsize = sizeof (expanded_w) / 2;
9930 	    DWORD produced = expand_environment_strings_w ((wchar_t *)pvalue,
9931 							   expanded_w,
9932 							   dsize);
9933 	    if (produced > 0 && produced < dsize)
9934 	      {
9935 		AUTO_STRING_WITH_LEN (sval, (char *)expanded_w,
9936 				      produced * 2 - 2);
9937 		retval = from_unicode (sval);
9938 	      }
9939 	    else
9940 	      {
9941 		if (pvalue[vsize - 1] == '\0')
9942 		  vsize -= 2;
9943 		AUTO_STRING_WITH_LEN (sval, (char *)pvalue, vsize);
9944 		retval = from_unicode (sval);
9945 	      }
9946 	  }
9947 	else
9948 	  {
9949 	    char expanded[32*1024]; /* size limitation according to MSDN */
9950 	    DWORD produced = ExpandEnvironmentStrings ((char *)pvalue,
9951 						       expanded,
9952 						       sizeof (expanded));
9953 	    if (produced > 0 && produced < sizeof (expanded))
9954 	      retval = make_unibyte_string (expanded, produced - 1);
9955 	    else
9956 	      {
9957 		if (pvalue[vsize - 1] == '\0')
9958 		  vsize--;
9959 		retval = make_unibyte_string (pvalue, vsize);
9960 	      }
9961 
9962 	    retval = DECODE_SYSTEM (retval);
9963 	  }
9964 	break;
9965       case REG_MULTI_SZ:
9966 	if (use_unicode)
9967 	  {
9968 	    wchar_t *wp = (wchar_t *)pvalue;
9969 
9970 	    val = Qnil;
9971 	    do {
9972 	      size_t wslen = wcslen (wp);
9973 	      AUTO_STRING_WITH_LEN (sval, (char *)wp, wslen * 2);
9974 	      val = Fcons (from_unicode (sval), val);
9975 	      wp += wslen + 1;
9976 	    } while (*wp);
9977 	  }
9978 	else
9979 	  {
9980 	    char *p = (char *)pvalue;
9981 
9982 	    val = Qnil;
9983 	    do {
9984 	      size_t slen = strlen (p);
9985 
9986 	      val = Fcons (DECODE_SYSTEM (make_unibyte_string (p, slen)), val);
9987 	      p += slen + 1;
9988 	    } while (*p);
9989 	  }
9990 
9991 	retval = Fnreverse (val);
9992 	break;
9993       default:
9994 	error ("unsupported registry data type: %d", (int)vtype);
9995     }
9996 
9997   xfree (pvalue);
9998   RegCloseKey (hkey);
9999   return retval;
10000 }
10001 
10002 
10003 /* The Windows CRT functions are "optimized for speed", so they don't
10004    check for timezone and DST changes if they were last called less
10005    than 1 minute ago (see http://support.microsoft.com/kb/821231).  So
10006    all Emacs features that repeatedly call time functions (e.g.,
10007    display-time) are in real danger of missing timezone and DST
10008    changes.  Calling tzset before each localtime call fixes that.  */
10009 struct tm *
sys_localtime(const time_t * t)10010 sys_localtime (const time_t *t)
10011 {
10012   tzset ();
10013   return localtime (t);
10014 }
10015 
10016 
10017 
10018 /* Try loading LIBRARY_ID from the file(s) specified in
10019    Vdynamic_library_alist.  If the library is loaded successfully,
10020    return the handle of the DLL, and record the filename in the
10021    property :loaded-from of LIBRARY_ID.  If the library could not be
10022    found, or when it was already loaded (because the handle is not
10023    recorded anywhere, and so is lost after use), return NULL.
10024 
10025    We could also save the handle in :loaded-from, but currently
10026    there's no use case for it.  */
10027 HMODULE
w32_delayed_load(Lisp_Object library_id)10028 w32_delayed_load (Lisp_Object library_id)
10029 {
10030   HMODULE dll_handle = NULL;
10031 
10032   CHECK_SYMBOL (library_id);
10033 
10034   if (CONSP (Vdynamic_library_alist)
10035       && NILP (Fassq (library_id, Vlibrary_cache)))
10036     {
10037       Lisp_Object found = Qnil;
10038       Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
10039 
10040       if (CONSP (dlls))
10041         for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
10042           {
10043 	    Lisp_Object dll = XCAR (dlls);
10044 	    char name[MAX_UTF8_PATH];
10045 	    DWORD res = -1;
10046 
10047 	    CHECK_STRING (dll);
10048 	    dll = ENCODE_FILE (dll);
10049 	    if (w32_unicode_filenames)
10050 	      {
10051 		wchar_t name_w[MAX_PATH];
10052 
10053 		filename_to_utf16 (SSDATA (dll), name_w);
10054 		dll_handle = LoadLibraryW (name_w);
10055 		if (dll_handle)
10056 		  {
10057 		    res = GetModuleFileNameW (dll_handle, name_w,
10058 					      sizeof (name_w));
10059 		    if (res > 0)
10060 		      filename_from_utf16 (name_w, name);
10061 		  }
10062 	      }
10063 	    else
10064 	      {
10065 		char name_a[MAX_PATH];
10066 
10067 		filename_to_ansi (SSDATA (dll), name_a);
10068 		dll_handle = LoadLibraryA (name_a);
10069 		if (dll_handle)
10070 		  {
10071 		    res = GetModuleFileNameA (dll_handle, name_a,
10072 					      sizeof (name_a));
10073 		    if (res > 0)
10074 		      filename_from_ansi (name_a, name);
10075 		  }
10076 	      }
10077 	    if (dll_handle)
10078 	      {
10079 		ptrdiff_t len = strlen (name);
10080 		found = Fcons (dll,
10081 			       (res > 0)
10082 			       /* Possibly truncated */
10083 			       ? make_specified_string (name, -1, len, 1)
10084 			       : Qnil);
10085 		/* This prevents thread start and end notifications
10086 		   from being sent to the DLL, for every thread we
10087 		   start.  We don't need those notifications because
10088 		   threads we create never use any of these DLLs, only
10089 		   the main thread uses them.  This is supposed to
10090 		   speed up thread creation.  */
10091 		DisableThreadLibraryCalls (dll_handle);
10092 		break;
10093 	      }
10094 	  }
10095 
10096       Fput (library_id, QCloaded_from, found);
10097     }
10098 
10099   return dll_handle;
10100 }
10101 
10102 
10103 void
check_windows_init_file(void)10104 check_windows_init_file (void)
10105 {
10106   /* A common indication that Emacs is not installed properly is when
10107      it cannot find the Windows installation file.  If this file does
10108      not exist in the expected place, tell the user.  */
10109 
10110   if (!noninteractive && !inhibit_window_system
10111       /* Vload_path is not yet initialized when we are loading
10112 	 loadup.el.  */
10113       && NILP (Vpurify_flag))
10114     {
10115       Lisp_Object init_file;
10116       int fd;
10117 
10118       /* Implementation note: this function runs early during Emacs
10119 	 startup, before startup.el is run.  So Vload_path is still in
10120 	 its initial unibyte form, but it holds UTF-8 encoded file
10121 	 names, since init_callproc was already called.  So we do not
10122 	 need to ENCODE_FILE here, but we do need to convert the file
10123 	 names from UTF-8 to ANSI.  */
10124       init_file = build_string ("term/w32-win");
10125       fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
10126       if (fd < 0)
10127 	{
10128 	  Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
10129 	  char *init_file_name = SSDATA (init_file);
10130 	  char *load_path = SSDATA (load_path_print);
10131 	  char *buffer = alloca (1024
10132 				 + strlen (init_file_name)
10133 				 + strlen (load_path));
10134 	  char *msg = buffer;
10135 	  int needed;
10136 
10137 	  sprintf (buffer,
10138 		   "The Emacs Windows initialization file \"%s.el\" "
10139 		   "could not be found in your Emacs installation.  "
10140 		   "Emacs checked the following directories for this file:\n"
10141 		   "\n%s\n\n"
10142 		   "When Emacs cannot find this file, it usually means that it "
10143 		   "was not installed properly, or its distribution file was "
10144 		   "not unpacked properly.\nSee the README.W32 file in the "
10145 		   "top-level Emacs directory for more information.",
10146 		   init_file_name, load_path);
10147 	  needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
10148 					 buffer, -1, NULL, 0);
10149 	  if (needed > 0)
10150 	    {
10151 	      wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
10152 
10153 	      pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
10154 				    -1, msg_w, needed);
10155 	      needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
10156 					     NULL, 0, NULL, NULL);
10157 	      if (needed > 0)
10158 		{
10159 		  char *msg_a = alloca (needed + 1);
10160 
10161 		  pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
10162 					NULL, NULL);
10163 		  msg = msg_a;
10164 		}
10165 	    }
10166 	  MessageBox (NULL,
10167 		      msg,
10168 		      "Emacs Abort Dialog",
10169 		      MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
10170 	  /* Use the low-level system abort. */
10171 	  abort ();
10172 	}
10173       else
10174 	{
10175 	  _close (fd);
10176 	}
10177     }
10178 }
10179 
10180 void
term_ntproc(int ignored)10181 term_ntproc (int ignored)
10182 {
10183   (void)ignored;
10184 
10185   term_timers ();
10186 
10187   /* shutdown the socket interface if necessary */
10188   term_winsock ();
10189 
10190   term_w32select ();
10191 }
10192 
10193 void
init_ntproc(int dumping)10194 init_ntproc (int dumping)
10195 {
10196   sigset_t initial_mask = 0;
10197 
10198   /* Initialize the socket interface now if available and requested by
10199      the user by defining PRELOAD_WINSOCK; otherwise loading will be
10200      delayed until open-network-stream is called (w32-has-winsock can
10201      also be used to dynamically load or reload winsock).
10202 
10203      Conveniently, init_environment is called before us, so
10204      PRELOAD_WINSOCK can be set in the registry. */
10205 
10206   /* Always initialize this correctly. */
10207   winsock_lib = NULL;
10208 
10209   if (getenv ("PRELOAD_WINSOCK") != NULL)
10210     init_winsock (TRUE);
10211 
10212   /* Initial preparation for subprocess support: replace our standard
10213      handles with non-inheritable versions. */
10214   {
10215     HANDLE parent;
10216     HANDLE stdin_save =  INVALID_HANDLE_VALUE;
10217     HANDLE stdout_save = INVALID_HANDLE_VALUE;
10218     HANDLE stderr_save = INVALID_HANDLE_VALUE;
10219 
10220     parent = GetCurrentProcess ();
10221 
10222     /* ignore errors when duplicating and closing; typically the
10223        handles will be invalid when running as a gui program. */
10224     DuplicateHandle (parent,
10225 		     GetStdHandle (STD_INPUT_HANDLE),
10226 		     parent,
10227 		     &stdin_save,
10228 		     0,
10229 		     FALSE,
10230 		     DUPLICATE_SAME_ACCESS);
10231 
10232     DuplicateHandle (parent,
10233 		     GetStdHandle (STD_OUTPUT_HANDLE),
10234 		     parent,
10235 		     &stdout_save,
10236 		     0,
10237 		     FALSE,
10238 		     DUPLICATE_SAME_ACCESS);
10239 
10240     DuplicateHandle (parent,
10241 		     GetStdHandle (STD_ERROR_HANDLE),
10242 		     parent,
10243 		     &stderr_save,
10244 		     0,
10245 		     FALSE,
10246 		     DUPLICATE_SAME_ACCESS);
10247 
10248     fclose (stdin);
10249     fclose (stdout);
10250     fclose (stderr);
10251 
10252     if (stdin_save != INVALID_HANDLE_VALUE)
10253       _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
10254     else
10255       _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
10256     _fdopen (0, "r");
10257 
10258     if (stdout_save != INVALID_HANDLE_VALUE)
10259       _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
10260     else
10261       _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
10262     _fdopen (1, "w");
10263 
10264     if (stderr_save != INVALID_HANDLE_VALUE)
10265       _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
10266     else
10267       _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
10268     _fdopen (2, "w");
10269   }
10270 
10271   /* unfortunately, atexit depends on implementation of malloc */
10272   /* atexit (term_ntproc); */
10273   if (!dumping)
10274     {
10275       /* Make sure we start with all signals unblocked.  */
10276       sigprocmask (SIG_SETMASK, &initial_mask, NULL);
10277       signal (SIGABRT, term_ntproc);
10278     }
10279   init_timers ();
10280 
10281   /* determine which drives are fixed, for GetCachedVolumeInformation */
10282   {
10283     /* GetDriveType must have trailing backslash. */
10284     char drive[] = "A:\\";
10285 
10286     /* Loop over all possible drive letters */
10287     while (*drive <= 'Z')
10288     {
10289       /* Record if this drive letter refers to a fixed drive. */
10290       fixed_drives[DRIVE_INDEX (*drive)] =
10291 	(GetDriveType (drive) == DRIVE_FIXED);
10292 
10293       (*drive)++;
10294     }
10295 
10296     /* Reset the volume info cache.  */
10297     volume_cache = NULL;
10298   }
10299 }
10300 
10301 /*
10302         shutdown_handler ensures that buffers' autosave files are
10303 	up to date when the user logs off, or the system shuts down.
10304 */
10305 static BOOL WINAPI
shutdown_handler(DWORD type)10306 shutdown_handler (DWORD type)
10307 {
10308   /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them.  */
10309   if (type == CTRL_CLOSE_EVENT        /* User closes console window.  */
10310       || type == CTRL_LOGOFF_EVENT    /* User logs off.  */
10311       || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown.  */
10312     {
10313       /* Shut down cleanly, making sure autosave files are up to date.  */
10314       shut_down_emacs (0, Qnil);
10315     }
10316 
10317   /* Allow other handlers to handle this signal.  */
10318   return FALSE;
10319 }
10320 
10321 /* On Windows 9X, load UNICOWS.DLL and return its handle, or die.  On
10322    NT, return a handle to GDI32.DLL.  */
10323 HANDLE
maybe_load_unicows_dll(void)10324 maybe_load_unicows_dll (void)
10325 {
10326   if (os_subtype == OS_9X)
10327     {
10328       HANDLE ret = LoadLibrary ("Unicows.dll");
10329       if (ret)
10330 	{
10331 	  /* These two functions are present on Windows 9X as stubs
10332 	     that always fail.  We need the real implementations from
10333 	     UNICOWS.DLL, so we must call these functions through
10334 	     pointers, and assign the correct addresses to these
10335 	     pointers at program startup (see emacs.c, which calls
10336 	     this function early on).  */
10337 	  pMultiByteToWideChar = (MultiByteToWideChar_Proc)
10338             get_proc_addr (ret, "MultiByteToWideChar");
10339 	  pWideCharToMultiByte = (WideCharToMultiByte_Proc)
10340             get_proc_addr (ret, "WideCharToMultiByte");
10341           multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
10342 	  return ret;
10343 	}
10344       else
10345 	{
10346 	  int button;
10347 
10348 	  button = MessageBox (NULL,
10349 			       "Emacs cannot load the UNICOWS.DLL library.\n"
10350 			       "This library is essential for using Emacs\n"
10351 			       "on this system.  You need to install it.\n\n"
10352 			       "Emacs will exit when you click OK.",
10353 			       "Emacs cannot load UNICOWS.DLL",
10354 			       MB_ICONERROR | MB_TASKMODAL
10355 			       | MB_SETFOREGROUND | MB_OK);
10356 	  switch (button)
10357 	    {
10358 	    case IDOK:
10359 	    default:
10360 	      exit (1);
10361 	    }
10362 	}
10363     }
10364   else
10365     {
10366       /* On NT family of Windows, these two functions are always
10367 	 linked in, so we just assign their addresses to the 2
10368 	 pointers; no need for the LoadLibrary dance.  */
10369       pMultiByteToWideChar = MultiByteToWideChar;
10370       pWideCharToMultiByte = WideCharToMultiByte;
10371       /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported.  */
10372       if (w32_major_version < 5)
10373         multiByteToWideCharFlags = 0;
10374       else
10375         multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
10376       return LoadLibrary ("Gdi32.dll");
10377     }
10378 }
10379 
10380 /* Relocate a directory specified by epaths.h, using the location of
10381    our binary as an anchor.  Note: this runs early during startup, so
10382    we cannot rely on the usual file-related facilities, and in
10383    particular the argument is assumed to be a unibyte string in system
10384    codepage encoding.  */
10385 const char *
w32_relocate(const char * epath_dir)10386 w32_relocate (const char *epath_dir)
10387 {
10388   if (strncmp (epath_dir, "%emacs_dir%/", 12) == 0)
10389     {
10390       static char relocated_dir[MAX_PATH];
10391 
10392       /* Replace "%emacs_dir%" with the parent of the directory where
10393 	 our binary lives.  Note that init_environment was not yet
10394 	 called, so we cannot rely on emacs_dir being set in the
10395 	 environment.  */
10396       if (GetModuleFileNameA (NULL, relocated_dir, MAX_PATH))
10397 	{
10398 	  char *p = _mbsrchr (relocated_dir, '\\');
10399 
10400 	  if (p)
10401 	    {
10402 	      *p = '\0';
10403 	      if ((p = _mbsrchr (relocated_dir, '\\')) != NULL)
10404 		{
10405 		  strcpy (p, epath_dir + 11);
10406 		  epath_dir = relocated_dir;
10407 		}
10408 	    }
10409 	}
10410     }
10411   return epath_dir;
10412 }
10413 
10414 /* Return the full absolute name of the running executable.  If the
10415    executable is a symlink, resolve it.
10416 
10417    Note: this function is called early during startup, when Unicode
10418    file names are not yet supported.  Thus the result must be an
10419    ANSI-encoded string.  */
10420 char *
w32_my_exename(void)10421 w32_my_exename (void)
10422 {
10423   static char exename[MAX_PATH];
10424   if (!GetModuleFileNameA (NULL, exename, MAX_PATH))
10425     return NULL;
10426   /* The caller expects us to resolve all possible symlinks in the
10427      last component of exename, i.e. if the executable itself is a
10428      symlink to a file in another directory.  */
10429   if (get_volume_info (exename, NULL)
10430       && (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
10431     {
10432       /* chase_symlinks wants its argument in UTF-8.  */
10433       char exename_utf8[MAX_UTF8_PATH];
10434       filename_from_ansi (exename, exename_utf8);
10435 
10436       /* If EXENAME is a symlink, replace it with its target.  */
10437       char *tgt = chase_symlinks (exename_utf8);
10438       if (tgt != exename_utf8)
10439 	filename_to_ansi (tgt, exename);
10440     }
10441 
10442   return exename;
10443 }
10444 
10445 /*
10446 	globals_of_w32 is used to initialize those global variables that
10447 	must always be initialized on startup even when the global variable
10448 	initialized is non zero (see the function main in emacs.c).
10449 */
10450 void
globals_of_w32(void)10451 globals_of_w32 (void)
10452 {
10453   HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
10454 
10455   get_process_times_fn = (GetProcessTimes_Proc)
10456     get_proc_addr (kernel32, "GetProcessTimes");
10457 
10458   DEFSYM (QCloaded_from, ":loaded-from");
10459 
10460   g_b_init_is_windows_9x = 0;
10461   g_b_init_open_process_token = 0;
10462   g_b_init_get_token_information = 0;
10463   g_b_init_lookup_account_sid = 0;
10464   g_b_init_get_sid_sub_authority = 0;
10465   g_b_init_get_sid_sub_authority_count = 0;
10466   g_b_init_get_security_info = 0;
10467   g_b_init_get_file_security_w = 0;
10468   g_b_init_get_file_security_a = 0;
10469   g_b_init_get_security_descriptor_owner = 0;
10470   g_b_init_get_security_descriptor_group = 0;
10471   g_b_init_is_valid_sid = 0;
10472   g_b_init_create_toolhelp32_snapshot = 0;
10473   g_b_init_process32_first = 0;
10474   g_b_init_process32_next = 0;
10475   g_b_init_open_thread_token = 0;
10476   g_b_init_impersonate_self = 0;
10477   g_b_init_revert_to_self = 0;
10478   g_b_init_get_process_memory_info = 0;
10479   g_b_init_get_process_working_set_size = 0;
10480   g_b_init_global_memory_status = 0;
10481   g_b_init_global_memory_status_ex = 0;
10482   g_b_init_equal_sid = 0;
10483   g_b_init_copy_sid = 0;
10484   g_b_init_get_length_sid = 0;
10485   g_b_init_get_native_system_info = 0;
10486   g_b_init_get_system_times = 0;
10487   g_b_init_create_symbolic_link_w = 0;
10488   g_b_init_create_symbolic_link_a = 0;
10489   g_b_init_get_security_descriptor_dacl = 0;
10490   g_b_init_convert_sd_to_sddl = 0;
10491   g_b_init_convert_sddl_to_sd = 0;
10492   g_b_init_is_valid_security_descriptor = 0;
10493   g_b_init_set_file_security_w = 0;
10494   g_b_init_set_file_security_a = 0;
10495   g_b_init_set_named_security_info_w = 0;
10496   g_b_init_set_named_security_info_a = 0;
10497   g_b_init_get_adapters_info = 0;
10498   g_b_init_get_adapters_addresses = 0;
10499   g_b_init_reg_open_key_ex_w = 0;
10500   g_b_init_reg_query_value_ex_w = 0;
10501   g_b_init_expand_environment_strings_w = 0;
10502   g_b_init_compare_string_w = 0;
10503   g_b_init_debug_break_process = 0;
10504   g_b_init_get_user_default_ui_language = 0;
10505   num_of_processors = 0;
10506   /* The following sets a handler for shutdown notifications for
10507      console apps. This actually applies to Emacs in both console and
10508      GUI modes, since we had to fool windows into thinking emacs is a
10509      console application to get console mode to work.  */
10510   SetConsoleCtrlHandler (shutdown_handler, TRUE);
10511 
10512   /* "None" is the default group name on standalone workstations.  */
10513   strcpy (dflt_group_name, "None");
10514 
10515   /* Reset, in case it has some value inherited from dump time.  */
10516   w32_stat_get_owner_group = 0;
10517 
10518   /* If w32_unicode_filenames is non-zero, we will be using Unicode
10519      (a.k.a. "wide") APIs to invoke functions that accept file
10520      names.  */
10521   if (is_windows_9x ())
10522     w32_unicode_filenames = 0;
10523   else
10524     w32_unicode_filenames = 1;
10525 
10526 #ifdef HAVE_MODULES
10527   dynlib_reset_last_error ();
10528 #endif
10529 
10530   w32_crypto_hprov = (HCRYPTPROV)0;
10531 }
10532 
10533 /* For make-serial-process  */
10534 int
serial_open(Lisp_Object port_obj)10535 serial_open (Lisp_Object port_obj)
10536 {
10537   char *port = SSDATA (port_obj);
10538   HANDLE hnd;
10539   child_process *cp;
10540   int fd = -1;
10541 
10542   hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
10543 		    OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
10544   if (hnd == INVALID_HANDLE_VALUE)
10545     error ("Could not open %s", port);
10546   fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
10547   if (fd == -1)
10548     error ("Could not open %s", port);
10549 
10550   cp = new_child ();
10551   if (!cp)
10552     error ("Could not create child process");
10553   cp->fd = fd;
10554   cp->status = STATUS_READ_ACKNOWLEDGED;
10555   fd_info[ fd ].hnd = hnd;
10556   fd_info[ fd ].flags |=
10557     FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
10558   if (fd_info[ fd ].cp != NULL)
10559     {
10560       error ("fd_info[fd = %d] is already in use", fd);
10561     }
10562   fd_info[ fd ].cp = cp;
10563   cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
10564   if (cp->ovl_read.hEvent == NULL)
10565       error ("Could not create read event");
10566   cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
10567   if (cp->ovl_write.hEvent == NULL)
10568       error ("Could not create write event");
10569 
10570   return fd;
10571 }
10572 
10573 /* For serial-process-configure  */
10574 void
serial_configure(struct Lisp_Process * p,Lisp_Object contact)10575 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
10576 {
10577   Lisp_Object childp2 = Qnil;
10578   Lisp_Object tem = Qnil;
10579   HANDLE hnd;
10580   DCB dcb;
10581   COMMTIMEOUTS ct;
10582   char summary[4] = "???"; /* This usually becomes "8N1".  */
10583 
10584   if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
10585     error ("Not a serial process");
10586   hnd = fd_info[ p->outfd ].hnd;
10587 
10588   childp2 = Fcopy_sequence (p->childp);
10589 
10590   /* Initialize timeouts for blocking read and blocking write.  */
10591   if (!GetCommTimeouts (hnd, &ct))
10592     error ("GetCommTimeouts() failed");
10593   ct.ReadIntervalTimeout	 = 0;
10594   ct.ReadTotalTimeoutMultiplier	 = 0;
10595   ct.ReadTotalTimeoutConstant	 = 0;
10596   ct.WriteTotalTimeoutMultiplier = 0;
10597   ct.WriteTotalTimeoutConstant	 = 0;
10598   if (!SetCommTimeouts (hnd, &ct))
10599     error ("SetCommTimeouts() failed");
10600   /* Read port attributes and prepare default configuration.  */
10601   memset (&dcb, 0, sizeof (dcb));
10602   dcb.DCBlength = sizeof (DCB);
10603   if (!GetCommState (hnd, &dcb))
10604     error ("GetCommState() failed");
10605   dcb.fBinary	    = TRUE;
10606   dcb.fNull	    = FALSE;
10607   dcb.fAbortOnError = FALSE;
10608   /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
10609   dcb.ErrorChar	    = 0;
10610   dcb.EofChar	    = 0;
10611   dcb.EvtChar       = 0;
10612 
10613   /* Configure speed.  */
10614   if (!NILP (Fplist_member (contact, QCspeed)))
10615     tem = Fplist_get (contact, QCspeed);
10616   else
10617     tem = Fplist_get (p->childp, QCspeed);
10618   CHECK_FIXNUM (tem);
10619   dcb.BaudRate = XFIXNUM (tem);
10620   childp2 = Fplist_put (childp2, QCspeed, tem);
10621 
10622   /* Configure bytesize.  */
10623   if (!NILP (Fplist_member (contact, QCbytesize)))
10624     tem = Fplist_get (contact, QCbytesize);
10625   else
10626     tem = Fplist_get (p->childp, QCbytesize);
10627   if (NILP (tem))
10628     tem = make_fixnum (8);
10629   CHECK_FIXNUM (tem);
10630   if (XFIXNUM (tem) != 7 && XFIXNUM (tem) != 8)
10631     error (":bytesize must be nil (8), 7, or 8");
10632   dcb.ByteSize = XFIXNUM (tem);
10633   summary[0] = XFIXNUM (tem) + '0';
10634   childp2 = Fplist_put (childp2, QCbytesize, tem);
10635 
10636   /* Configure parity.  */
10637   if (!NILP (Fplist_member (contact, QCparity)))
10638     tem = Fplist_get (contact, QCparity);
10639   else
10640     tem = Fplist_get (p->childp, QCparity);
10641   if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
10642     error (":parity must be nil (no parity), `even', or `odd'");
10643   dcb.fParity = FALSE;
10644   dcb.Parity = NOPARITY;
10645   dcb.fErrorChar = FALSE;
10646   if (NILP (tem))
10647     {
10648       summary[1] = 'N';
10649     }
10650   else if (EQ (tem, Qeven))
10651     {
10652       summary[1] = 'E';
10653       dcb.fParity = TRUE;
10654       dcb.Parity = EVENPARITY;
10655       dcb.fErrorChar = TRUE;
10656     }
10657   else if (EQ (tem, Qodd))
10658     {
10659       summary[1] = 'O';
10660       dcb.fParity = TRUE;
10661       dcb.Parity = ODDPARITY;
10662       dcb.fErrorChar = TRUE;
10663     }
10664   childp2 = Fplist_put (childp2, QCparity, tem);
10665 
10666   /* Configure stopbits.  */
10667   if (!NILP (Fplist_member (contact, QCstopbits)))
10668     tem = Fplist_get (contact, QCstopbits);
10669   else
10670     tem = Fplist_get (p->childp, QCstopbits);
10671   if (NILP (tem))
10672     tem = make_fixnum (1);
10673   CHECK_FIXNUM (tem);
10674   if (XFIXNUM (tem) != 1 && XFIXNUM (tem) != 2)
10675     error (":stopbits must be nil (1 stopbit), 1, or 2");
10676   summary[2] = XFIXNUM (tem) + '0';
10677   if (XFIXNUM (tem) == 1)
10678     dcb.StopBits = ONESTOPBIT;
10679   else if (XFIXNUM (tem) == 2)
10680     dcb.StopBits = TWOSTOPBITS;
10681   childp2 = Fplist_put (childp2, QCstopbits, tem);
10682 
10683   /* Configure flowcontrol.  */
10684   if (!NILP (Fplist_member (contact, QCflowcontrol)))
10685     tem = Fplist_get (contact, QCflowcontrol);
10686   else
10687     tem = Fplist_get (p->childp, QCflowcontrol);
10688   if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
10689     error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
10690   dcb.fOutxCtsFlow	= FALSE;
10691   dcb.fOutxDsrFlow	= FALSE;
10692   dcb.fDtrControl	= DTR_CONTROL_DISABLE;
10693   dcb.fDsrSensitivity	= FALSE;
10694   dcb.fTXContinueOnXoff	= FALSE;
10695   dcb.fOutX		= FALSE;
10696   dcb.fInX		= FALSE;
10697   dcb.fRtsControl	= RTS_CONTROL_DISABLE;
10698   dcb.XonChar		= 17; /* Control-Q  */
10699   dcb.XoffChar		= 19; /* Control-S  */
10700   if (NILP (tem))
10701     {
10702       /* Already configured.  */
10703     }
10704   else if (EQ (tem, Qhw))
10705     {
10706       dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
10707       dcb.fOutxCtsFlow = TRUE;
10708     }
10709   else if (EQ (tem, Qsw))
10710     {
10711       dcb.fOutX = TRUE;
10712       dcb.fInX = TRUE;
10713     }
10714   childp2 = Fplist_put (childp2, QCflowcontrol, tem);
10715 
10716   /* Activate configuration.  */
10717   if (!SetCommState (hnd, &dcb))
10718     error ("SetCommState() failed");
10719 
10720   childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
10721   pset_childp (p, childp2);
10722 }
10723 
10724 /* For make-pipe-process */
10725 void
register_aux_fd(int infd)10726 register_aux_fd (int infd)
10727 {
10728   child_process *cp;
10729 
10730   cp = new_child ();
10731   if (!cp)
10732     error ("Could not create child process");
10733   cp->fd = infd;
10734   cp->status = STATUS_READ_ACKNOWLEDGED;
10735 
10736   if (fd_info[ infd ].cp != NULL)
10737     {
10738       error ("fd_info[fd = %d] is already in use", infd);
10739     }
10740   fd_info[ infd ].cp = cp;
10741   fd_info[ infd ].hnd = (HANDLE) _get_osfhandle (infd);
10742 }
10743 
10744 #ifdef HAVE_GNUTLS
10745 
10746 ssize_t
emacs_gnutls_pull(gnutls_transport_ptr_t p,void * buf,size_t sz)10747 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
10748 {
10749   int n, err;
10750   struct Lisp_Process *process = (struct Lisp_Process *)p;
10751   int fd = process->infd;
10752 
10753   n = sys_read (fd, (char*)buf, sz);
10754 
10755   if (n >= 0)
10756     return n;
10757 
10758   err = errno;
10759 
10760   /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
10761   if (err == EWOULDBLOCK)
10762     err = EAGAIN;
10763 
10764   emacs_gnutls_transport_set_errno (process->gnutls_state, err);
10765 
10766   return -1;
10767 }
10768 
10769 ssize_t
emacs_gnutls_push(gnutls_transport_ptr_t p,const void * buf,size_t sz)10770 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
10771 {
10772   struct Lisp_Process *process = (struct Lisp_Process *)p;
10773   int fd = process->outfd;
10774   ssize_t n = sys_write (fd, buf, sz);
10775 
10776   /* 0 or more bytes written means everything went fine.  */
10777   if (n >= 0)
10778     return n;
10779 
10780   /* Negative bytes written means we got an error in errno.
10781      Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.  */
10782   emacs_gnutls_transport_set_errno (process->gnutls_state,
10783                                     errno == EWOULDBLOCK ? EAGAIN : errno);
10784 
10785   return -1;
10786 }
10787 #endif /* HAVE_GNUTLS */
10788 
10789 /* end of w32.c */
10790