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