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