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