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