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