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