* net/ange-ftp.el (ange-ftp-canonize-filename): Check, that
[emacs.git] / src / w32.c
blobf610a36ecf464cc6d81bdc9dac586f7d2fdd2b88
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994-1995, 2000-2012 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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.
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.
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/>. */
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
22 #include <stddef.h> /* for offsetof */
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <float.h> /* for DBL_EPSILON */
26 #include <io.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <ctype.h>
30 #include <signal.h>
31 #include <sys/file.h>
32 #include <sys/time.h>
33 #include <sys/utime.h>
34 #include <mbstring.h> /* for _mbspbrk */
35 #include <math.h>
36 #include <setjmp.h>
37 #include <time.h>
39 /* must include CRT headers *before* config.h */
41 #include <config.h>
43 #undef access
44 #undef chdir
45 #undef chmod
46 #undef creat
47 #undef ctime
48 #undef fopen
49 #undef link
50 #undef mkdir
51 #undef mktemp
52 #undef open
53 #undef rename
54 #undef rmdir
55 #undef unlink
57 #undef close
58 #undef dup
59 #undef dup2
60 #undef pipe
61 #undef read
62 #undef write
64 #undef strerror
66 #undef localtime
68 #include "lisp.h"
70 #include <pwd.h>
71 #include <grp.h>
73 #ifdef __GNUC__
74 #define _ANONYMOUS_UNION
75 #define _ANONYMOUS_STRUCT
76 #endif
77 #include <windows.h>
78 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
79 use a different name to avoid compilation problems. */
80 typedef struct _MEMORY_STATUS_EX {
81 DWORD dwLength;
82 DWORD dwMemoryLoad;
83 DWORDLONG ullTotalPhys;
84 DWORDLONG ullAvailPhys;
85 DWORDLONG ullTotalPageFile;
86 DWORDLONG ullAvailPageFile;
87 DWORDLONG ullTotalVirtual;
88 DWORDLONG ullAvailVirtual;
89 DWORDLONG ullAvailExtendedVirtual;
90 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
92 #include <lmcons.h>
93 #include <shlobj.h>
95 #include <tlhelp32.h>
96 #include <psapi.h>
97 #ifndef _MSC_VER
98 #include <w32api.h>
99 #endif
100 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
101 /* This either is not in psapi.h or guarded by higher value of
102 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
103 defines it in psapi.h */
104 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
105 DWORD cb;
106 DWORD PageFaultCount;
107 DWORD PeakWorkingSetSize;
108 DWORD WorkingSetSize;
109 DWORD QuotaPeakPagedPoolUsage;
110 DWORD QuotaPagedPoolUsage;
111 DWORD QuotaPeakNonPagedPoolUsage;
112 DWORD QuotaNonPagedPoolUsage;
113 DWORD PagefileUsage;
114 DWORD PeakPagefileUsage;
115 DWORD PrivateUsage;
116 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
117 #endif
119 /* TCP connection support. */
120 #include <sys/socket.h>
121 #undef socket
122 #undef bind
123 #undef connect
124 #undef htons
125 #undef ntohs
126 #undef inet_addr
127 #undef gethostname
128 #undef gethostbyname
129 #undef getservbyname
130 #undef getpeername
131 #undef shutdown
132 #undef setsockopt
133 #undef listen
134 #undef getsockname
135 #undef accept
136 #undef recvfrom
137 #undef sendto
139 #include "w32.h"
140 #include "ndir.h"
141 #include "w32heap.h"
142 #include "systime.h"
143 #include "dispextern.h" /* for xstrcasecmp */
144 #include "coding.h" /* for Vlocale_coding_system */
146 #include "careadlinkat.h"
147 #include "allocator.h"
149 /* For serial_configure and serial_open. */
150 #include "process.h"
152 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
153 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
155 Lisp_Object QCloaded_from;
157 void globals_of_w32 (void);
158 static DWORD get_rid (PSID);
161 /* Initialization states.
163 WARNING: If you add any more such variables for additional APIs,
164 you MUST add initialization for them to globals_of_w32
165 below. This is because these variables might get set
166 to non-NULL values during dumping, but the dumped Emacs
167 cannot reuse those values, because it could be run on a
168 different version of the OS, where API addresses are
169 different. */
170 static BOOL g_b_init_is_windows_9x;
171 static BOOL g_b_init_open_process_token;
172 static BOOL g_b_init_get_token_information;
173 static BOOL g_b_init_lookup_account_sid;
174 static BOOL g_b_init_get_sid_sub_authority;
175 static BOOL g_b_init_get_sid_sub_authority_count;
176 static BOOL g_b_init_get_file_security;
177 static BOOL g_b_init_get_security_descriptor_owner;
178 static BOOL g_b_init_get_security_descriptor_group;
179 static BOOL g_b_init_is_valid_sid;
180 static BOOL g_b_init_create_toolhelp32_snapshot;
181 static BOOL g_b_init_process32_first;
182 static BOOL g_b_init_process32_next;
183 static BOOL g_b_init_open_thread_token;
184 static BOOL g_b_init_impersonate_self;
185 static BOOL g_b_init_revert_to_self;
186 static BOOL g_b_init_get_process_memory_info;
187 static BOOL g_b_init_get_process_working_set_size;
188 static BOOL g_b_init_global_memory_status;
189 static BOOL g_b_init_global_memory_status_ex;
190 static BOOL g_b_init_get_length_sid;
191 static BOOL g_b_init_equal_sid;
192 static BOOL g_b_init_copy_sid;
193 static BOOL g_b_init_get_native_system_info;
194 static BOOL g_b_init_get_system_times;
197 BEGIN: Wrapper functions around OpenProcessToken
198 and other functions in advapi32.dll that are only
199 supported in Windows NT / 2k / XP
201 /* ** Function pointer typedefs ** */
202 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
203 HANDLE ProcessHandle,
204 DWORD DesiredAccess,
205 PHANDLE TokenHandle);
206 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
207 HANDLE TokenHandle,
208 TOKEN_INFORMATION_CLASS TokenInformationClass,
209 LPVOID TokenInformation,
210 DWORD TokenInformationLength,
211 PDWORD ReturnLength);
212 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
213 HANDLE process_handle,
214 LPFILETIME creation_time,
215 LPFILETIME exit_time,
216 LPFILETIME kernel_time,
217 LPFILETIME user_time);
219 GetProcessTimes_Proc get_process_times_fn = NULL;
221 #ifdef _UNICODE
222 const char * const LookupAccountSid_Name = "LookupAccountSidW";
223 const char * const GetFileSecurity_Name = "GetFileSecurityW";
224 #else
225 const char * const LookupAccountSid_Name = "LookupAccountSidA";
226 const char * const GetFileSecurity_Name = "GetFileSecurityA";
227 #endif
228 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
229 LPCTSTR lpSystemName,
230 PSID Sid,
231 LPTSTR Name,
232 LPDWORD cbName,
233 LPTSTR DomainName,
234 LPDWORD cbDomainName,
235 PSID_NAME_USE peUse);
236 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
237 PSID pSid,
238 DWORD n);
239 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
240 PSID pSid);
241 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
242 LPCTSTR lpFileName,
243 SECURITY_INFORMATION RequestedInformation,
244 PSECURITY_DESCRIPTOR pSecurityDescriptor,
245 DWORD nLength,
246 LPDWORD lpnLengthNeeded);
247 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
248 PSECURITY_DESCRIPTOR pSecurityDescriptor,
249 PSID *pOwner,
250 LPBOOL lpbOwnerDefaulted);
251 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
252 PSECURITY_DESCRIPTOR pSecurityDescriptor,
253 PSID *pGroup,
254 LPBOOL lpbGroupDefaulted);
255 typedef BOOL (WINAPI * IsValidSid_Proc) (
256 PSID sid);
257 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
258 DWORD dwFlags,
259 DWORD th32ProcessID);
260 typedef BOOL (WINAPI * Process32First_Proc) (
261 HANDLE hSnapshot,
262 LPPROCESSENTRY32 lppe);
263 typedef BOOL (WINAPI * Process32Next_Proc) (
264 HANDLE hSnapshot,
265 LPPROCESSENTRY32 lppe);
266 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
267 HANDLE ThreadHandle,
268 DWORD DesiredAccess,
269 BOOL OpenAsSelf,
270 PHANDLE TokenHandle);
271 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
272 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
273 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
274 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
275 HANDLE Process,
276 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
277 DWORD cb);
278 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
279 HANDLE hProcess,
280 DWORD * lpMinimumWorkingSetSize,
281 DWORD * lpMaximumWorkingSetSize);
282 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
283 LPMEMORYSTATUS lpBuffer);
284 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
285 LPMEMORY_STATUS_EX lpBuffer);
286 typedef BOOL (WINAPI * CopySid_Proc) (
287 DWORD nDestinationSidLength,
288 PSID pDestinationSid,
289 PSID pSourceSid);
290 typedef BOOL (WINAPI * EqualSid_Proc) (
291 PSID pSid1,
292 PSID pSid2);
293 typedef DWORD (WINAPI * GetLengthSid_Proc) (
294 PSID pSid);
295 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
296 LPSYSTEM_INFO lpSystemInfo);
297 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
298 LPFILETIME lpIdleTime,
299 LPFILETIME lpKernelTime,
300 LPFILETIME lpUserTime);
302 /* ** A utility function ** */
303 static BOOL
304 is_windows_9x (void)
306 static BOOL s_b_ret = 0;
307 OSVERSIONINFO os_ver;
308 if (g_b_init_is_windows_9x == 0)
310 g_b_init_is_windows_9x = 1;
311 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
312 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
313 if (GetVersionEx (&os_ver))
315 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
318 return s_b_ret;
321 /* Get total user and system times for get-internal-run-time.
322 Returns a list of three integers if the times are provided by the OS
323 (NT derivatives), otherwise it returns the result of current-time. */
324 Lisp_Object
325 w32_get_internal_run_time (void)
327 if (get_process_times_fn)
329 FILETIME create, exit, kernel, user;
330 HANDLE proc = GetCurrentProcess ();
331 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
333 LARGE_INTEGER user_int, kernel_int, total;
334 int microseconds;
335 user_int.LowPart = user.dwLowDateTime;
336 user_int.HighPart = user.dwHighDateTime;
337 kernel_int.LowPart = kernel.dwLowDateTime;
338 kernel_int.HighPart = kernel.dwHighDateTime;
339 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
340 /* FILETIME is 100 nanosecond increments, Emacs only wants
341 microsecond resolution. */
342 total.QuadPart /= 10;
343 microseconds = total.QuadPart % 1000000;
344 total.QuadPart /= 1000000;
346 /* Sanity check to make sure we can represent the result. */
347 if (total.HighPart == 0)
349 int secs = total.LowPart;
351 return list3 (make_number ((secs >> 16) & 0xffff),
352 make_number (secs & 0xffff),
353 make_number (microseconds));
358 return Fcurrent_time ();
361 /* ** The wrapper functions ** */
363 static BOOL WINAPI
364 open_process_token (HANDLE ProcessHandle,
365 DWORD DesiredAccess,
366 PHANDLE TokenHandle)
368 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
369 HMODULE hm_advapi32 = NULL;
370 if (is_windows_9x () == TRUE)
372 return FALSE;
374 if (g_b_init_open_process_token == 0)
376 g_b_init_open_process_token = 1;
377 hm_advapi32 = LoadLibrary ("Advapi32.dll");
378 s_pfn_Open_Process_Token =
379 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
381 if (s_pfn_Open_Process_Token == NULL)
383 return FALSE;
385 return (
386 s_pfn_Open_Process_Token (
387 ProcessHandle,
388 DesiredAccess,
389 TokenHandle)
393 static BOOL WINAPI
394 get_token_information (HANDLE TokenHandle,
395 TOKEN_INFORMATION_CLASS TokenInformationClass,
396 LPVOID TokenInformation,
397 DWORD TokenInformationLength,
398 PDWORD ReturnLength)
400 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
401 HMODULE hm_advapi32 = NULL;
402 if (is_windows_9x () == TRUE)
404 return FALSE;
406 if (g_b_init_get_token_information == 0)
408 g_b_init_get_token_information = 1;
409 hm_advapi32 = LoadLibrary ("Advapi32.dll");
410 s_pfn_Get_Token_Information =
411 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
413 if (s_pfn_Get_Token_Information == NULL)
415 return FALSE;
417 return (
418 s_pfn_Get_Token_Information (
419 TokenHandle,
420 TokenInformationClass,
421 TokenInformation,
422 TokenInformationLength,
423 ReturnLength)
427 static BOOL WINAPI
428 lookup_account_sid (LPCTSTR lpSystemName,
429 PSID Sid,
430 LPTSTR Name,
431 LPDWORD cbName,
432 LPTSTR DomainName,
433 LPDWORD cbDomainName,
434 PSID_NAME_USE peUse)
436 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
437 HMODULE hm_advapi32 = NULL;
438 if (is_windows_9x () == TRUE)
440 return FALSE;
442 if (g_b_init_lookup_account_sid == 0)
444 g_b_init_lookup_account_sid = 1;
445 hm_advapi32 = LoadLibrary ("Advapi32.dll");
446 s_pfn_Lookup_Account_Sid =
447 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
449 if (s_pfn_Lookup_Account_Sid == NULL)
451 return FALSE;
453 return (
454 s_pfn_Lookup_Account_Sid (
455 lpSystemName,
456 Sid,
457 Name,
458 cbName,
459 DomainName,
460 cbDomainName,
461 peUse)
465 static PDWORD WINAPI
466 get_sid_sub_authority (PSID pSid, DWORD n)
468 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
469 static DWORD zero = 0U;
470 HMODULE hm_advapi32 = NULL;
471 if (is_windows_9x () == TRUE)
473 return &zero;
475 if (g_b_init_get_sid_sub_authority == 0)
477 g_b_init_get_sid_sub_authority = 1;
478 hm_advapi32 = LoadLibrary ("Advapi32.dll");
479 s_pfn_Get_Sid_Sub_Authority =
480 (GetSidSubAuthority_Proc) GetProcAddress (
481 hm_advapi32, "GetSidSubAuthority");
483 if (s_pfn_Get_Sid_Sub_Authority == NULL)
485 return &zero;
487 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
490 static PUCHAR WINAPI
491 get_sid_sub_authority_count (PSID pSid)
493 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
494 static UCHAR zero = 0U;
495 HMODULE hm_advapi32 = NULL;
496 if (is_windows_9x () == TRUE)
498 return &zero;
500 if (g_b_init_get_sid_sub_authority_count == 0)
502 g_b_init_get_sid_sub_authority_count = 1;
503 hm_advapi32 = LoadLibrary ("Advapi32.dll");
504 s_pfn_Get_Sid_Sub_Authority_Count =
505 (GetSidSubAuthorityCount_Proc) GetProcAddress (
506 hm_advapi32, "GetSidSubAuthorityCount");
508 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
510 return &zero;
512 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
515 static BOOL WINAPI
516 get_file_security (LPCTSTR lpFileName,
517 SECURITY_INFORMATION RequestedInformation,
518 PSECURITY_DESCRIPTOR pSecurityDescriptor,
519 DWORD nLength,
520 LPDWORD lpnLengthNeeded)
522 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
523 HMODULE hm_advapi32 = NULL;
524 if (is_windows_9x () == TRUE)
526 return FALSE;
528 if (g_b_init_get_file_security == 0)
530 g_b_init_get_file_security = 1;
531 hm_advapi32 = LoadLibrary ("Advapi32.dll");
532 s_pfn_Get_File_Security =
533 (GetFileSecurity_Proc) GetProcAddress (
534 hm_advapi32, GetFileSecurity_Name);
536 if (s_pfn_Get_File_Security == NULL)
538 return FALSE;
540 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
541 pSecurityDescriptor, nLength,
542 lpnLengthNeeded));
545 static BOOL WINAPI
546 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
547 PSID *pOwner,
548 LPBOOL lpbOwnerDefaulted)
550 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
551 HMODULE hm_advapi32 = NULL;
552 if (is_windows_9x () == TRUE)
554 return FALSE;
556 if (g_b_init_get_security_descriptor_owner == 0)
558 g_b_init_get_security_descriptor_owner = 1;
559 hm_advapi32 = LoadLibrary ("Advapi32.dll");
560 s_pfn_Get_Security_Descriptor_Owner =
561 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
562 hm_advapi32, "GetSecurityDescriptorOwner");
564 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
566 return FALSE;
568 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
569 lpbOwnerDefaulted));
572 static BOOL WINAPI
573 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
574 PSID *pGroup,
575 LPBOOL lpbGroupDefaulted)
577 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
578 HMODULE hm_advapi32 = NULL;
579 if (is_windows_9x () == TRUE)
581 return FALSE;
583 if (g_b_init_get_security_descriptor_group == 0)
585 g_b_init_get_security_descriptor_group = 1;
586 hm_advapi32 = LoadLibrary ("Advapi32.dll");
587 s_pfn_Get_Security_Descriptor_Group =
588 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
589 hm_advapi32, "GetSecurityDescriptorGroup");
591 if (s_pfn_Get_Security_Descriptor_Group == NULL)
593 return FALSE;
595 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
596 lpbGroupDefaulted));
599 static BOOL WINAPI
600 is_valid_sid (PSID sid)
602 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
603 HMODULE hm_advapi32 = NULL;
604 if (is_windows_9x () == TRUE)
606 return FALSE;
608 if (g_b_init_is_valid_sid == 0)
610 g_b_init_is_valid_sid = 1;
611 hm_advapi32 = LoadLibrary ("Advapi32.dll");
612 s_pfn_Is_Valid_Sid =
613 (IsValidSid_Proc) GetProcAddress (
614 hm_advapi32, "IsValidSid");
616 if (s_pfn_Is_Valid_Sid == NULL)
618 return FALSE;
620 return (s_pfn_Is_Valid_Sid (sid));
623 static BOOL WINAPI
624 equal_sid (PSID sid1, PSID sid2)
626 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
627 HMODULE hm_advapi32 = NULL;
628 if (is_windows_9x () == TRUE)
630 return FALSE;
632 if (g_b_init_equal_sid == 0)
634 g_b_init_equal_sid = 1;
635 hm_advapi32 = LoadLibrary ("Advapi32.dll");
636 s_pfn_Equal_Sid =
637 (EqualSid_Proc) GetProcAddress (
638 hm_advapi32, "EqualSid");
640 if (s_pfn_Equal_Sid == NULL)
642 return FALSE;
644 return (s_pfn_Equal_Sid (sid1, sid2));
647 static DWORD WINAPI
648 get_length_sid (PSID sid)
650 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
651 HMODULE hm_advapi32 = NULL;
652 if (is_windows_9x () == TRUE)
654 return 0;
656 if (g_b_init_get_length_sid == 0)
658 g_b_init_get_length_sid = 1;
659 hm_advapi32 = LoadLibrary ("Advapi32.dll");
660 s_pfn_Get_Length_Sid =
661 (GetLengthSid_Proc) GetProcAddress (
662 hm_advapi32, "GetLengthSid");
664 if (s_pfn_Get_Length_Sid == NULL)
666 return 0;
668 return (s_pfn_Get_Length_Sid (sid));
671 static BOOL WINAPI
672 copy_sid (DWORD destlen, PSID dest, PSID src)
674 static CopySid_Proc s_pfn_Copy_Sid = NULL;
675 HMODULE hm_advapi32 = NULL;
676 if (is_windows_9x () == TRUE)
678 return FALSE;
680 if (g_b_init_copy_sid == 0)
682 g_b_init_copy_sid = 1;
683 hm_advapi32 = LoadLibrary ("Advapi32.dll");
684 s_pfn_Copy_Sid =
685 (CopySid_Proc) GetProcAddress (
686 hm_advapi32, "CopySid");
688 if (s_pfn_Copy_Sid == NULL)
690 return FALSE;
692 return (s_pfn_Copy_Sid (destlen, dest, src));
696 END: Wrapper functions around OpenProcessToken
697 and other functions in advapi32.dll that are only
698 supported in Windows NT / 2k / XP
701 static void WINAPI
702 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
704 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
705 if (is_windows_9x () != TRUE)
707 if (g_b_init_get_native_system_info == 0)
709 g_b_init_get_native_system_info = 1;
710 s_pfn_Get_Native_System_Info =
711 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
712 "GetNativeSystemInfo");
714 if (s_pfn_Get_Native_System_Info != NULL)
715 s_pfn_Get_Native_System_Info (lpSystemInfo);
717 else
718 lpSystemInfo->dwNumberOfProcessors = -1;
721 static BOOL WINAPI
722 get_system_times (LPFILETIME lpIdleTime,
723 LPFILETIME lpKernelTime,
724 LPFILETIME lpUserTime)
726 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
727 if (is_windows_9x () == TRUE)
729 return FALSE;
731 if (g_b_init_get_system_times == 0)
733 g_b_init_get_system_times = 1;
734 s_pfn_Get_System_times =
735 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
736 "GetSystemTimes");
738 if (s_pfn_Get_System_times == NULL)
739 return FALSE;
740 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
743 /* Equivalent of strerror for W32 error codes. */
744 char *
745 w32_strerror (int error_no)
747 static char buf[500];
749 if (error_no == 0)
750 error_no = GetLastError ();
752 buf[0] = '\0';
753 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
754 error_no,
755 0, /* choose most suitable language */
756 buf, sizeof (buf), NULL))
757 sprintf (buf, "w32 error %u", error_no);
758 return buf;
761 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
762 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
764 This is called from alloc.c:valid_pointer_p. */
766 w32_valid_pointer_p (void *p, int size)
768 SIZE_T done;
769 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
771 if (h)
773 unsigned char *buf = alloca (size);
774 int retval = ReadProcessMemory (h, p, buf, size, &done);
776 CloseHandle (h);
777 return retval;
779 else
780 return -1;
783 static char startup_dir[MAXPATHLEN];
785 /* Get the current working directory. */
786 char *
787 getwd (char *dir)
789 #if 0
790 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
791 return dir;
792 return NULL;
793 #else
794 /* Emacs doesn't actually change directory itself, and we want to
795 force our real wd to be where emacs.exe is to avoid unnecessary
796 conflicts when trying to rename or delete directories. */
797 strcpy (dir, startup_dir);
798 return dir;
799 #endif
802 /* Emulate getloadavg. */
804 struct load_sample {
805 time_t sample_time;
806 ULONGLONG idle;
807 ULONGLONG kernel;
808 ULONGLONG user;
811 /* Number of processors on this machine. */
812 static unsigned num_of_processors;
814 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
815 static struct load_sample samples[16*60];
816 static int first_idx = -1, last_idx = -1;
817 static int max_idx = sizeof (samples) / sizeof (samples[0]);
819 static int
820 buf_next (int from)
822 int next_idx = from + 1;
824 if (next_idx >= max_idx)
825 next_idx = 0;
827 return next_idx;
830 static int
831 buf_prev (int from)
833 int prev_idx = from - 1;
835 if (prev_idx < 0)
836 prev_idx = max_idx - 1;
838 return prev_idx;
841 static void
842 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
844 SYSTEM_INFO sysinfo;
845 FILETIME ft_idle, ft_user, ft_kernel;
847 /* Initialize the number of processors on this machine. */
848 if (num_of_processors <= 0)
850 get_native_system_info (&sysinfo);
851 num_of_processors = sysinfo.dwNumberOfProcessors;
852 if (num_of_processors <= 0)
854 GetSystemInfo (&sysinfo);
855 num_of_processors = sysinfo.dwNumberOfProcessors;
857 if (num_of_processors <= 0)
858 num_of_processors = 1;
861 /* TODO: Take into account threads that are ready to run, by
862 sampling the "\System\Processor Queue Length" performance
863 counter. The code below accounts only for threads that are
864 actually running. */
866 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
868 ULARGE_INTEGER uidle, ukernel, uuser;
870 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
871 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
872 memcpy (&uuser, &ft_user, sizeof (ft_user));
873 *idle = uidle.QuadPart;
874 *kernel = ukernel.QuadPart;
875 *user = uuser.QuadPart;
877 else
879 *idle = 0;
880 *kernel = 0;
881 *user = 0;
885 /* Produce the load average for a given time interval, using the
886 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
887 1-minute, 5-minute, or 15-minute average, respectively. */
888 static double
889 getavg (int which)
891 double retval = -1.0;
892 double tdiff;
893 int idx;
894 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
895 time_t now = samples[last_idx].sample_time;
897 if (first_idx != last_idx)
899 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
901 tdiff = difftime (now, samples[idx].sample_time);
902 if (tdiff >= span - 2*DBL_EPSILON*now)
904 long double sys =
905 samples[last_idx].kernel + samples[last_idx].user
906 - (samples[idx].kernel + samples[idx].user);
907 long double idl = samples[last_idx].idle - samples[idx].idle;
909 retval = (1.0 - idl / sys) * num_of_processors;
910 break;
912 if (idx == first_idx)
913 break;
917 return retval;
921 getloadavg (double loadavg[], int nelem)
923 int elem;
924 ULONGLONG idle, kernel, user;
925 time_t now = time (NULL);
927 /* Store another sample. We ignore samples that are less than 1 sec
928 apart. */
929 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
931 sample_system_load (&idle, &kernel, &user);
932 last_idx = buf_next (last_idx);
933 samples[last_idx].sample_time = now;
934 samples[last_idx].idle = idle;
935 samples[last_idx].kernel = kernel;
936 samples[last_idx].user = user;
937 /* If the buffer has more that 15 min worth of samples, discard
938 the old ones. */
939 if (first_idx == -1)
940 first_idx = last_idx;
941 while (first_idx != last_idx
942 && (difftime (now, samples[first_idx].sample_time)
943 >= 15.0*60 + 2*DBL_EPSILON*now))
944 first_idx = buf_next (first_idx);
947 for (elem = 0; elem < nelem; elem++)
949 double avg = getavg (elem);
951 if (avg < 0)
952 break;
953 loadavg[elem] = avg;
956 return elem;
959 /* Emulate getpwuid, getpwnam and others. */
961 #define PASSWD_FIELD_SIZE 256
963 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
964 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
965 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
966 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
967 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
969 static struct passwd dflt_passwd =
971 dflt_passwd_name,
972 dflt_passwd_passwd,
976 dflt_passwd_gecos,
977 dflt_passwd_dir,
978 dflt_passwd_shell,
981 static char dflt_group_name[GNLEN+1];
983 static struct group dflt_group =
985 /* When group information is not available, we return this as the
986 group for all files. */
987 dflt_group_name,
991 unsigned
992 getuid (void)
994 return dflt_passwd.pw_uid;
997 unsigned
998 geteuid (void)
1000 /* I could imagine arguing for checking to see whether the user is
1001 in the Administrators group and returning a UID of 0 for that
1002 case, but I don't know how wise that would be in the long run. */
1003 return getuid ();
1006 unsigned
1007 getgid (void)
1009 return dflt_passwd.pw_gid;
1012 unsigned
1013 getegid (void)
1015 return getgid ();
1018 struct passwd *
1019 getpwuid (unsigned uid)
1021 if (uid == dflt_passwd.pw_uid)
1022 return &dflt_passwd;
1023 return NULL;
1026 struct group *
1027 getgrgid (gid_t gid)
1029 return &dflt_group;
1032 struct passwd *
1033 getpwnam (char *name)
1035 struct passwd *pw;
1037 pw = getpwuid (getuid ());
1038 if (!pw)
1039 return pw;
1041 if (xstrcasecmp (name, pw->pw_name))
1042 return NULL;
1044 return pw;
1047 static void
1048 init_user_info (void)
1050 /* Find the user's real name by opening the process token and
1051 looking up the name associated with the user-sid in that token.
1053 Use the relative portion of the identifier authority value from
1054 the user-sid as the user id value (same for group id using the
1055 primary group sid from the process token). */
1057 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1058 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1059 DWORD glength = sizeof (gname);
1060 HANDLE token = NULL;
1061 SID_NAME_USE user_type;
1062 unsigned char *buf = NULL;
1063 DWORD blen = 0;
1064 TOKEN_USER user_token;
1065 TOKEN_PRIMARY_GROUP group_token;
1066 BOOL result;
1068 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1069 if (result)
1071 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1072 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1074 buf = xmalloc (blen);
1075 result = get_token_information (token, TokenUser,
1076 (LPVOID)buf, blen, &needed);
1077 if (result)
1079 memcpy (&user_token, buf, sizeof (user_token));
1080 result = lookup_account_sid (NULL, user_token.User.Sid,
1081 uname, &ulength,
1082 domain, &dlength, &user_type);
1085 else
1086 result = FALSE;
1088 if (result)
1090 strcpy (dflt_passwd.pw_name, uname);
1091 /* Determine a reasonable uid value. */
1092 if (xstrcasecmp ("administrator", uname) == 0)
1094 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1095 dflt_passwd.pw_gid = 513; /* well-known None gid */
1097 else
1099 /* Use the last sub-authority value of the RID, the relative
1100 portion of the SID, as user/group ID. */
1101 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1103 /* Get group id and name. */
1104 result = get_token_information (token, TokenPrimaryGroup,
1105 (LPVOID)buf, blen, &needed);
1106 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1108 buf = xrealloc (buf, blen = needed);
1109 result = get_token_information (token, TokenPrimaryGroup,
1110 (LPVOID)buf, blen, &needed);
1112 if (result)
1114 memcpy (&group_token, buf, sizeof (group_token));
1115 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1116 dlength = sizeof (domain);
1117 /* If we can get at the real Primary Group name, use that.
1118 Otherwise, the default group name was already set to
1119 "None" in globals_of_w32. */
1120 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1121 gname, &glength, NULL, &dlength,
1122 &user_type))
1123 strcpy (dflt_group_name, gname);
1125 else
1126 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1129 /* If security calls are not supported (presumably because we
1130 are running under Windows 9X), fallback to this: */
1131 else if (GetUserName (uname, &ulength))
1133 strcpy (dflt_passwd.pw_name, uname);
1134 if (xstrcasecmp ("administrator", uname) == 0)
1135 dflt_passwd.pw_uid = 0;
1136 else
1137 dflt_passwd.pw_uid = 123;
1138 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1140 else
1142 strcpy (dflt_passwd.pw_name, "unknown");
1143 dflt_passwd.pw_uid = 123;
1144 dflt_passwd.pw_gid = 123;
1146 dflt_group.gr_gid = dflt_passwd.pw_gid;
1148 /* Ensure HOME and SHELL are defined. */
1149 if (getenv ("HOME") == NULL)
1150 abort ();
1151 if (getenv ("SHELL") == NULL)
1152 abort ();
1154 /* Set dir and shell from environment variables. */
1155 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1156 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1158 xfree (buf);
1159 if (token)
1160 CloseHandle (token);
1164 random (void)
1166 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1167 return ((rand () << 15) | rand ());
1170 void
1171 srandom (int seed)
1173 srand (seed);
1177 /* Normalize filename by converting all path separators to
1178 the specified separator. Also conditionally convert upper
1179 case path name components to lower case. */
1181 static void
1182 normalize_filename (register char *fp, char path_sep)
1184 char sep;
1185 char *elem;
1187 /* Always lower-case drive letters a-z, even if the filesystem
1188 preserves case in filenames.
1189 This is so filenames can be compared by string comparison
1190 functions that are case-sensitive. Even case-preserving filesystems
1191 do not distinguish case in drive letters. */
1192 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
1194 *fp += 'a' - 'A';
1195 fp += 2;
1198 if (NILP (Vw32_downcase_file_names))
1200 while (*fp)
1202 if (*fp == '/' || *fp == '\\')
1203 *fp = path_sep;
1204 fp++;
1206 return;
1209 sep = path_sep; /* convert to this path separator */
1210 elem = fp; /* start of current path element */
1212 do {
1213 if (*fp >= 'a' && *fp <= 'z')
1214 elem = 0; /* don't convert this element */
1216 if (*fp == 0 || *fp == ':')
1218 sep = *fp; /* restore current separator (or 0) */
1219 *fp = '/'; /* after conversion of this element */
1222 if (*fp == '/' || *fp == '\\')
1224 if (elem && elem != fp)
1226 *fp = 0; /* temporary end of string */
1227 _strlwr (elem); /* while we convert to lower case */
1229 *fp = sep; /* convert (or restore) path separator */
1230 elem = fp + 1; /* next element starts after separator */
1231 sep = path_sep;
1233 } while (*fp++);
1236 /* Destructively turn backslashes into slashes. */
1237 void
1238 dostounix_filename (register char *p)
1240 normalize_filename (p, '/');
1243 /* Destructively turn slashes into backslashes. */
1244 void
1245 unixtodos_filename (register char *p)
1247 normalize_filename (p, '\\');
1250 /* Remove all CR's that are followed by a LF.
1251 (From msdos.c...probably should figure out a way to share it,
1252 although this code isn't going to ever change.) */
1253 static int
1254 crlf_to_lf (register int n, register unsigned char *buf)
1256 unsigned char *np = buf;
1257 unsigned char *startp = buf;
1258 unsigned char *endp = buf + n;
1260 if (n == 0)
1261 return n;
1262 while (buf < endp - 1)
1264 if (*buf == 0x0d)
1266 if (*(++buf) != 0x0a)
1267 *np++ = 0x0d;
1269 else
1270 *np++ = *buf++;
1272 if (buf < endp)
1273 *np++ = *buf++;
1274 return np - startp;
1277 /* Parse the root part of file name, if present. Return length and
1278 optionally store pointer to char after root. */
1279 static int
1280 parse_root (char * name, char ** pPath)
1282 char * start = name;
1284 if (name == NULL)
1285 return 0;
1287 /* find the root name of the volume if given */
1288 if (isalpha (name[0]) && name[1] == ':')
1290 /* skip past drive specifier */
1291 name += 2;
1292 if (IS_DIRECTORY_SEP (name[0]))
1293 name++;
1295 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1297 int slashes = 2;
1298 name += 2;
1301 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1302 break;
1303 name++;
1305 while ( *name );
1306 if (IS_DIRECTORY_SEP (name[0]))
1307 name++;
1310 if (pPath)
1311 *pPath = name;
1313 return name - start;
1316 /* Get long base name for name; name is assumed to be absolute. */
1317 static int
1318 get_long_basename (char * name, char * buf, int size)
1320 WIN32_FIND_DATA find_data;
1321 HANDLE dir_handle;
1322 int len = 0;
1324 /* must be valid filename, no wild cards or other invalid characters */
1325 if (_mbspbrk (name, "*?|<>\""))
1326 return 0;
1328 dir_handle = FindFirstFile (name, &find_data);
1329 if (dir_handle != INVALID_HANDLE_VALUE)
1331 if ((len = strlen (find_data.cFileName)) < size)
1332 memcpy (buf, find_data.cFileName, len + 1);
1333 else
1334 len = 0;
1335 FindClose (dir_handle);
1337 return len;
1340 /* Get long name for file, if possible (assumed to be absolute). */
1341 BOOL
1342 w32_get_long_filename (char * name, char * buf, int size)
1344 char * o = buf;
1345 char * p;
1346 char * q;
1347 char full[ MAX_PATH ];
1348 int len;
1350 len = strlen (name);
1351 if (len >= MAX_PATH)
1352 return FALSE;
1354 /* Use local copy for destructive modification. */
1355 memcpy (full, name, len+1);
1356 unixtodos_filename (full);
1358 /* Copy root part verbatim. */
1359 len = parse_root (full, &p);
1360 memcpy (o, full, len);
1361 o += len;
1362 *o = '\0';
1363 size -= len;
1365 while (p != NULL && *p)
1367 q = p;
1368 p = strchr (q, '\\');
1369 if (p) *p = '\0';
1370 len = get_long_basename (full, o, size);
1371 if (len > 0)
1373 o += len;
1374 size -= len;
1375 if (p != NULL)
1377 *p++ = '\\';
1378 if (size < 2)
1379 return FALSE;
1380 *o++ = '\\';
1381 size--;
1382 *o = '\0';
1385 else
1386 return FALSE;
1389 return TRUE;
1392 static int
1393 is_unc_volume (const char *filename)
1395 const char *ptr = filename;
1397 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1398 return 0;
1400 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1401 return 0;
1403 return 1;
1406 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1409 sigsetmask (int signal_mask)
1411 return 0;
1415 sigmask (int sig)
1417 return 0;
1421 sigblock (int sig)
1423 return 0;
1427 sigunblock (int sig)
1429 return 0;
1433 sigemptyset (sigset_t *set)
1435 return 0;
1439 sigaddset (sigset_t *set, int signo)
1441 return 0;
1445 sigfillset (sigset_t *set)
1447 return 0;
1451 sigprocmask (int how, const sigset_t *set, sigset_t *oset)
1453 return 0;
1457 pthread_sigmask (int how, const sigset_t *set, sigset_t *oset)
1459 if (sigprocmask (how, set, oset) == -1)
1460 return EINVAL;
1461 return 0;
1465 setpgrp (int pid, int gid)
1467 return 0;
1471 alarm (int seconds)
1473 return 0;
1476 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1478 LPBYTE
1479 w32_get_resource (char *key, LPDWORD lpdwtype)
1481 LPBYTE lpvalue;
1482 HKEY hrootkey = NULL;
1483 DWORD cbData;
1485 /* Check both the current user and the local machine to see if
1486 we have any resources. */
1488 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1490 lpvalue = NULL;
1492 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1493 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1494 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1496 RegCloseKey (hrootkey);
1497 return (lpvalue);
1500 xfree (lpvalue);
1502 RegCloseKey (hrootkey);
1505 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1507 lpvalue = NULL;
1509 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1510 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1511 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1513 RegCloseKey (hrootkey);
1514 return (lpvalue);
1517 xfree (lpvalue);
1519 RegCloseKey (hrootkey);
1522 return (NULL);
1525 char *get_emacs_configuration (void);
1527 void
1528 init_environment (char ** argv)
1530 static const char * const tempdirs[] = {
1531 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1534 int i;
1536 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1538 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1539 temporary files and assume "/tmp" if $TMPDIR is unset, which
1540 will break on DOS/Windows. Refuse to work if we cannot find
1541 a directory, not even "c:/", usable for that purpose. */
1542 for (i = 0; i < imax ; i++)
1544 const char *tmp = tempdirs[i];
1546 if (*tmp == '$')
1547 tmp = getenv (tmp + 1);
1548 /* Note that `access' can lie to us if the directory resides on a
1549 read-only filesystem, like CD-ROM or a write-protected floppy.
1550 The only way to be really sure is to actually create a file and
1551 see if it succeeds. But I think that's too much to ask. */
1552 #ifdef _MSC_VER
1553 /* MSVC's _access crashes with D_OK. */
1554 if (tmp && sys_access (tmp, D_OK) == 0)
1555 #else
1556 if (tmp && _access (tmp, D_OK) == 0)
1557 #endif
1559 char * var = alloca (strlen (tmp) + 8);
1560 sprintf (var, "TMPDIR=%s", tmp);
1561 _putenv (strdup (var));
1562 break;
1565 if (i >= imax)
1566 cmd_error_internal
1567 (Fcons (Qerror,
1568 Fcons (build_string ("no usable temporary directories found!!"),
1569 Qnil)),
1570 "While setting TMPDIR: ");
1572 /* Check for environment variables and use registry settings if they
1573 don't exist. Fallback on default values where applicable. */
1575 int i;
1576 LPBYTE lpval;
1577 DWORD dwType;
1578 char locale_name[32];
1579 struct stat ignored;
1580 char default_home[MAX_PATH];
1581 int appdata = 0;
1583 static const struct env_entry
1585 char * name;
1586 char * def_value;
1587 } dflt_envvars[] =
1589 {"HOME", "C:/"},
1590 {"PRELOAD_WINSOCK", NULL},
1591 {"emacs_dir", "C:/emacs"},
1592 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1593 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1594 {"EMACSDATA", "%emacs_dir%/etc"},
1595 {"EMACSPATH", "%emacs_dir%/bin"},
1596 /* We no longer set INFOPATH because Info-default-directory-list
1597 is then ignored. */
1598 /* {"INFOPATH", "%emacs_dir%/info"}, */
1599 {"EMACSDOC", "%emacs_dir%/etc"},
1600 {"TERM", "cmd"},
1601 {"LANG", NULL},
1604 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1606 /* We need to copy dflt_envvars[] and work on the copy because we
1607 don't want the dumped Emacs to inherit the values of
1608 environment variables we saw during dumping (which could be on
1609 a different system). The defaults above must be left intact. */
1610 struct env_entry env_vars[N_ENV_VARS];
1612 for (i = 0; i < N_ENV_VARS; i++)
1613 env_vars[i] = dflt_envvars[i];
1615 /* For backwards compatibility, check if a .emacs file exists in C:/
1616 If not, then we can try to default to the appdata directory under the
1617 user's profile, which is more likely to be writable. */
1618 if (stat ("C:/.emacs", &ignored) < 0)
1620 HRESULT profile_result;
1621 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1622 of Windows 95 and NT4 that have not been updated to include
1623 MSIE 5. */
1624 ShGetFolderPath_fn get_folder_path;
1625 get_folder_path = (ShGetFolderPath_fn)
1626 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1628 if (get_folder_path != NULL)
1630 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1631 0, default_home);
1633 /* If we can't get the appdata dir, revert to old behavior. */
1634 if (profile_result == S_OK)
1636 env_vars[0].def_value = default_home;
1637 appdata = 1;
1642 /* Get default locale info and use it for LANG. */
1643 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1644 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1645 locale_name, sizeof (locale_name)))
1647 for (i = 0; i < N_ENV_VARS; i++)
1649 if (strcmp (env_vars[i].name, "LANG") == 0)
1651 env_vars[i].def_value = locale_name;
1652 break;
1657 /* When Emacs is invoked with --no-site-lisp, we must remove the
1658 site-lisp directories from the default value of EMACSLOADPATH.
1659 This assumes that the site-lisp entries are at the front, and
1660 that additional entries do exist. */
1661 if (no_site_lisp)
1663 for (i = 0; i < N_ENV_VARS; i++)
1665 if (strcmp (env_vars[i].name, "EMACSLOADPATH") == 0)
1667 char *site;
1668 while ((site = strstr (env_vars[i].def_value, "site-lisp")))
1669 env_vars[i].def_value = strchr (site, ';') + 1;
1670 break;
1675 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1677 /* Treat emacs_dir specially: set it unconditionally based on our
1678 location, if it appears that we are running from the bin subdir
1679 of a standard installation. */
1681 char *p;
1682 char modname[MAX_PATH];
1684 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1685 abort ();
1686 if ((p = strrchr (modname, '\\')) == NULL)
1687 abort ();
1688 *p = 0;
1690 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1692 char buf[SET_ENV_BUF_SIZE];
1694 *p = 0;
1695 for (p = modname; *p; p++)
1696 if (*p == '\\') *p = '/';
1698 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1699 _putenv (strdup (buf));
1701 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1703 /* FIXME: should use substring of get_emacs_configuration ().
1704 But I don't think the Windows build supports alpha, mips etc
1705 anymore, so have taken the easy option for now. */
1706 else if (p && xstrcasecmp (p, "\\i386") == 0)
1708 *p = 0;
1709 p = strrchr (modname, '\\');
1710 if (p != NULL)
1712 *p = 0;
1713 p = strrchr (modname, '\\');
1714 if (p && xstrcasecmp (p, "\\src") == 0)
1716 char buf[SET_ENV_BUF_SIZE];
1718 *p = 0;
1719 for (p = modname; *p; p++)
1720 if (*p == '\\') *p = '/';
1722 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1723 _putenv (strdup (buf));
1729 for (i = 0; i < N_ENV_VARS; i++)
1731 if (!getenv (env_vars[i].name))
1733 int dont_free = 0;
1735 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1736 /* Also ignore empty environment variables. */
1737 || *lpval == 0)
1739 xfree (lpval);
1740 lpval = env_vars[i].def_value;
1741 dwType = REG_EXPAND_SZ;
1742 dont_free = 1;
1743 if (!strcmp (env_vars[i].name, "HOME") && !appdata)
1745 Lisp_Object warning[2];
1746 warning[0] = intern ("initialization");
1747 warning[1] = build_string ("Setting HOME to C:\\ by default is deprecated");
1748 Vdelayed_warnings_list = Fcons (Flist (2, warning),
1749 Vdelayed_warnings_list);
1753 if (lpval)
1755 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1757 if (dwType == REG_EXPAND_SZ)
1758 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
1759 else if (dwType == REG_SZ)
1760 strcpy (buf1, lpval);
1761 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1763 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
1764 buf1);
1765 _putenv (strdup (buf2));
1768 if (!dont_free)
1769 xfree (lpval);
1775 /* Rebuild system configuration to reflect invoking system. */
1776 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1778 /* Another special case: on NT, the PATH variable is actually named
1779 "Path" although cmd.exe (perhaps NT itself) arranges for
1780 environment variable lookup and setting to be case insensitive.
1781 However, Emacs assumes a fully case sensitive environment, so we
1782 need to change "Path" to "PATH" to match the expectations of
1783 various elisp packages. We do this by the sneaky method of
1784 modifying the string in the C runtime environ entry.
1786 The same applies to COMSPEC. */
1788 char ** envp;
1790 for (envp = environ; *envp; envp++)
1791 if (_strnicmp (*envp, "PATH=", 5) == 0)
1792 memcpy (*envp, "PATH=", 5);
1793 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1794 memcpy (*envp, "COMSPEC=", 8);
1797 /* Remember the initial working directory for getwd, then make the
1798 real wd be the location of emacs.exe to avoid conflicts when
1799 renaming or deleting directories. (We also don't call chdir when
1800 running subprocesses for the same reason.) */
1801 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1802 abort ();
1805 char *p;
1806 static char modname[MAX_PATH];
1808 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1809 abort ();
1810 if ((p = strrchr (modname, '\\')) == NULL)
1811 abort ();
1812 *p = 0;
1814 SetCurrentDirectory (modname);
1816 /* Ensure argv[0] has the full path to Emacs. */
1817 *p = '\\';
1818 argv[0] = modname;
1821 /* Determine if there is a middle mouse button, to allow parse_button
1822 to decide whether right mouse events should be mouse-2 or
1823 mouse-3. */
1824 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1826 init_user_info ();
1829 char *
1830 emacs_root_dir (void)
1832 static char root_dir[FILENAME_MAX];
1833 const char *p;
1835 p = getenv ("emacs_dir");
1836 if (p == NULL)
1837 abort ();
1838 strcpy (root_dir, p);
1839 root_dir[parse_root (root_dir, NULL)] = '\0';
1840 dostounix_filename (root_dir);
1841 return root_dir;
1844 /* We don't have scripts to automatically determine the system configuration
1845 for Emacs before it's compiled, and we don't want to have to make the
1846 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1847 routine. */
1849 char *
1850 get_emacs_configuration (void)
1852 char *arch, *oem, *os;
1853 int build_num;
1854 static char configuration_buffer[32];
1856 /* Determine the processor type. */
1857 switch (get_processor_type ())
1860 #ifdef PROCESSOR_INTEL_386
1861 case PROCESSOR_INTEL_386:
1862 case PROCESSOR_INTEL_486:
1863 case PROCESSOR_INTEL_PENTIUM:
1864 arch = "i386";
1865 break;
1866 #endif
1868 #ifdef PROCESSOR_MIPS_R2000
1869 case PROCESSOR_MIPS_R2000:
1870 case PROCESSOR_MIPS_R3000:
1871 case PROCESSOR_MIPS_R4000:
1872 arch = "mips";
1873 break;
1874 #endif
1876 #ifdef PROCESSOR_ALPHA_21064
1877 case PROCESSOR_ALPHA_21064:
1878 arch = "alpha";
1879 break;
1880 #endif
1882 default:
1883 arch = "unknown";
1884 break;
1887 /* Use the OEM field to reflect the compiler/library combination. */
1888 #ifdef _MSC_VER
1889 #define COMPILER_NAME "msvc"
1890 #else
1891 #ifdef __GNUC__
1892 #define COMPILER_NAME "mingw"
1893 #else
1894 #define COMPILER_NAME "unknown"
1895 #endif
1896 #endif
1897 oem = COMPILER_NAME;
1899 switch (osinfo_cache.dwPlatformId) {
1900 case VER_PLATFORM_WIN32_NT:
1901 os = "nt";
1902 build_num = osinfo_cache.dwBuildNumber;
1903 break;
1904 case VER_PLATFORM_WIN32_WINDOWS:
1905 if (osinfo_cache.dwMinorVersion == 0) {
1906 os = "windows95";
1907 } else {
1908 os = "windows98";
1910 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1911 break;
1912 case VER_PLATFORM_WIN32s:
1913 /* Not supported, should not happen. */
1914 os = "windows32s";
1915 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1916 break;
1917 default:
1918 os = "unknown";
1919 build_num = 0;
1920 break;
1923 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1924 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1925 get_w32_major_version (), get_w32_minor_version (), build_num);
1926 } else {
1927 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1930 return configuration_buffer;
1933 char *
1934 get_emacs_configuration_options (void)
1936 static char *options_buffer;
1937 char cv[32]; /* Enough for COMPILER_VERSION. */
1938 char *options[] = {
1939 cv, /* To be filled later. */
1940 #ifdef EMACSDEBUG
1941 " --no-opt",
1942 #endif
1943 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1944 with a starting space to save work here. */
1945 #ifdef USER_CFLAGS
1946 " --cflags", USER_CFLAGS,
1947 #endif
1948 #ifdef USER_LDFLAGS
1949 " --ldflags", USER_LDFLAGS,
1950 #endif
1951 NULL
1953 size_t size = 0;
1954 int i;
1956 /* Work out the effective configure options for this build. */
1957 #ifdef _MSC_VER
1958 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1959 #else
1960 #ifdef __GNUC__
1961 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1962 #else
1963 #define COMPILER_VERSION ""
1964 #endif
1965 #endif
1967 if (_snprintf (cv, sizeof (cv) - 1, COMPILER_VERSION) < 0)
1968 return "Error: not enough space for compiler version";
1969 cv[sizeof (cv) - 1] = '\0';
1971 for (i = 0; options[i]; i++)
1972 size += strlen (options[i]);
1974 options_buffer = xmalloc (size + 1);
1975 options_buffer[0] = '\0';
1977 for (i = 0; options[i]; i++)
1978 strcat (options_buffer, options[i]);
1980 return options_buffer;
1984 #include <sys/timeb.h>
1986 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1987 void
1988 gettimeofday (struct timeval *tv, struct timezone *tz)
1990 struct _timeb tb;
1991 _ftime (&tb);
1993 tv->tv_sec = tb.time;
1994 tv->tv_usec = tb.millitm * 1000L;
1995 /* Implementation note: _ftime sometimes doesn't update the dstflag
1996 according to the new timezone when the system timezone is
1997 changed. We could fix that by using GetSystemTime and
1998 GetTimeZoneInformation, but that doesn't seem necessary, since
1999 Emacs always calls gettimeofday with the 2nd argument NULL (see
2000 EMACS_GET_TIME). */
2001 if (tz)
2003 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2004 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2008 /* ------------------------------------------------------------------------- */
2009 /* IO support and wrapper functions for W32 API. */
2010 /* ------------------------------------------------------------------------- */
2012 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2013 on network directories, so we handle that case here.
2014 (Ulrich Leodolter, 1/11/95). */
2015 char *
2016 sys_ctime (const time_t *t)
2018 char *str = (char *) ctime (t);
2019 return (str ? str : "Sun Jan 01 00:00:00 1970");
2022 /* Emulate sleep...we could have done this with a define, but that
2023 would necessitate including windows.h in the files that used it.
2024 This is much easier. */
2025 void
2026 sys_sleep (int seconds)
2028 Sleep (seconds * 1000);
2031 /* Internal MSVC functions for low-level descriptor munging */
2032 extern int __cdecl _set_osfhnd (int fd, long h);
2033 extern int __cdecl _free_osfhnd (int fd);
2035 /* parallel array of private info on file handles */
2036 filedesc fd_info [ MAXDESC ];
2038 typedef struct volume_info_data {
2039 struct volume_info_data * next;
2041 /* time when info was obtained */
2042 DWORD timestamp;
2044 /* actual volume info */
2045 char * root_dir;
2046 DWORD serialnum;
2047 DWORD maxcomp;
2048 DWORD flags;
2049 char * name;
2050 char * type;
2051 } volume_info_data;
2053 /* Global referenced by various functions. */
2054 static volume_info_data volume_info;
2056 /* Vector to indicate which drives are local and fixed (for which cached
2057 data never expires). */
2058 static BOOL fixed_drives[26];
2060 /* Consider cached volume information to be stale if older than 10s,
2061 at least for non-local drives. Info for fixed drives is never stale. */
2062 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2063 #define VOLINFO_STILL_VALID( root_dir, info ) \
2064 ( ( isalpha (root_dir[0]) && \
2065 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2066 || GetTickCount () - info->timestamp < 10000 )
2068 /* Cache support functions. */
2070 /* Simple linked list with linear search is sufficient. */
2071 static volume_info_data *volume_cache = NULL;
2073 static volume_info_data *
2074 lookup_volume_info (char * root_dir)
2076 volume_info_data * info;
2078 for (info = volume_cache; info; info = info->next)
2079 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2080 break;
2081 return info;
2084 static void
2085 add_volume_info (char * root_dir, volume_info_data * info)
2087 info->root_dir = xstrdup (root_dir);
2088 info->next = volume_cache;
2089 volume_cache = info;
2093 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2094 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2095 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2096 static volume_info_data *
2097 GetCachedVolumeInformation (char * root_dir)
2099 volume_info_data * info;
2100 char default_root[ MAX_PATH ];
2102 /* NULL for root_dir means use root from current directory. */
2103 if (root_dir == NULL)
2105 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
2106 return NULL;
2107 parse_root (default_root, &root_dir);
2108 *root_dir = 0;
2109 root_dir = default_root;
2112 /* Local fixed drives can be cached permanently. Removable drives
2113 cannot be cached permanently, since the volume name and serial
2114 number (if nothing else) can change. Remote drives should be
2115 treated as if they are removable, since there is no sure way to
2116 tell whether they are or not. Also, the UNC association of drive
2117 letters mapped to remote volumes can be changed at any time (even
2118 by other processes) without notice.
2120 As a compromise, so we can benefit from caching info for remote
2121 volumes, we use a simple expiry mechanism to invalidate cache
2122 entries that are more than ten seconds old. */
2124 #if 0
2125 /* No point doing this, because WNetGetConnection is even slower than
2126 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2127 GetDriveType is about the only call of this type which does not
2128 involve network access, and so is extremely quick). */
2130 /* Map drive letter to UNC if remote. */
2131 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2133 char remote_name[ 256 ];
2134 char drive[3] = { root_dir[0], ':' };
2136 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2137 == NO_ERROR)
2138 /* do something */ ;
2140 #endif
2142 info = lookup_volume_info (root_dir);
2144 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2146 char name[ 256 ];
2147 DWORD serialnum;
2148 DWORD maxcomp;
2149 DWORD flags;
2150 char type[ 256 ];
2152 /* Info is not cached, or is stale. */
2153 if (!GetVolumeInformation (root_dir,
2154 name, sizeof (name),
2155 &serialnum,
2156 &maxcomp,
2157 &flags,
2158 type, sizeof (type)))
2159 return NULL;
2161 /* Cache the volume information for future use, overwriting existing
2162 entry if present. */
2163 if (info == NULL)
2165 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
2166 add_volume_info (root_dir, info);
2168 else
2170 xfree (info->name);
2171 xfree (info->type);
2174 info->name = xstrdup (name);
2175 info->serialnum = serialnum;
2176 info->maxcomp = maxcomp;
2177 info->flags = flags;
2178 info->type = xstrdup (type);
2179 info->timestamp = GetTickCount ();
2182 return info;
2185 /* Get information on the volume where name is held; set path pointer to
2186 start of pathname in name (past UNC header\volume header if present). */
2187 static int
2188 get_volume_info (const char * name, const char ** pPath)
2190 char temp[MAX_PATH];
2191 char *rootname = NULL; /* default to current volume */
2192 volume_info_data * info;
2194 if (name == NULL)
2195 return FALSE;
2197 /* find the root name of the volume if given */
2198 if (isalpha (name[0]) && name[1] == ':')
2200 rootname = temp;
2201 temp[0] = *name++;
2202 temp[1] = *name++;
2203 temp[2] = '\\';
2204 temp[3] = 0;
2206 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2208 char *str = temp;
2209 int slashes = 4;
2210 rootname = temp;
2213 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2214 break;
2215 *str++ = *name++;
2217 while ( *name );
2219 *str++ = '\\';
2220 *str = 0;
2223 if (pPath)
2224 *pPath = name;
2226 info = GetCachedVolumeInformation (rootname);
2227 if (info != NULL)
2229 /* Set global referenced by other functions. */
2230 volume_info = *info;
2231 return TRUE;
2233 return FALSE;
2236 /* Determine if volume is FAT format (ie. only supports short 8.3
2237 names); also set path pointer to start of pathname in name. */
2238 static int
2239 is_fat_volume (const char * name, const char ** pPath)
2241 if (get_volume_info (name, pPath))
2242 return (volume_info.maxcomp == 12);
2243 return FALSE;
2246 /* Map filename to a valid 8.3 name if necessary. */
2247 const char *
2248 map_w32_filename (const char * name, const char ** pPath)
2250 static char shortname[MAX_PATH];
2251 char * str = shortname;
2252 char c;
2253 char * path;
2254 const char * save_name = name;
2256 if (strlen (name) >= MAX_PATH)
2258 /* Return a filename which will cause callers to fail. */
2259 strcpy (shortname, "?");
2260 return shortname;
2263 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2265 register int left = 8; /* maximum number of chars in part */
2266 register int extn = 0; /* extension added? */
2267 register int dots = 2; /* maximum number of dots allowed */
2269 while (name < path)
2270 *str++ = *name++; /* skip past UNC header */
2272 while ((c = *name++))
2274 switch ( c )
2276 case '\\':
2277 case '/':
2278 *str++ = '\\';
2279 extn = 0; /* reset extension flags */
2280 dots = 2; /* max 2 dots */
2281 left = 8; /* max length 8 for main part */
2282 break;
2283 case ':':
2284 *str++ = ':';
2285 extn = 0; /* reset extension flags */
2286 dots = 2; /* max 2 dots */
2287 left = 8; /* max length 8 for main part */
2288 break;
2289 case '.':
2290 if ( dots )
2292 /* Convert path components of the form .xxx to _xxx,
2293 but leave . and .. as they are. This allows .emacs
2294 to be read as _emacs, for example. */
2296 if (! *name ||
2297 *name == '.' ||
2298 IS_DIRECTORY_SEP (*name))
2300 *str++ = '.';
2301 dots--;
2303 else
2305 *str++ = '_';
2306 left--;
2307 dots = 0;
2310 else if ( !extn )
2312 *str++ = '.';
2313 extn = 1; /* we've got an extension */
2314 left = 3; /* 3 chars in extension */
2316 else
2318 /* any embedded dots after the first are converted to _ */
2319 *str++ = '_';
2321 break;
2322 case '~':
2323 case '#': /* don't lose these, they're important */
2324 if ( ! left )
2325 str[-1] = c; /* replace last character of part */
2326 /* FALLTHRU */
2327 default:
2328 if ( left )
2330 *str++ = tolower (c); /* map to lower case (looks nicer) */
2331 left--;
2332 dots = 0; /* started a path component */
2334 break;
2337 *str = '\0';
2339 else
2341 strcpy (shortname, name);
2342 unixtodos_filename (shortname);
2345 if (pPath)
2346 *pPath = shortname + (path - save_name);
2348 return shortname;
2351 static int
2352 is_exec (const char * name)
2354 char * p = strrchr (name, '.');
2355 return
2356 (p != NULL
2357 && (xstrcasecmp (p, ".exe") == 0 ||
2358 xstrcasecmp (p, ".com") == 0 ||
2359 xstrcasecmp (p, ".bat") == 0 ||
2360 xstrcasecmp (p, ".cmd") == 0));
2363 /* Emulate the Unix directory procedures opendir, closedir,
2364 and readdir. We can't use the procedures supplied in sysdep.c,
2365 so we provide them here. */
2367 struct direct dir_static; /* simulated directory contents */
2368 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2369 static int dir_is_fat;
2370 static char dir_pathname[MAXPATHLEN+1];
2371 static WIN32_FIND_DATA dir_find_data;
2373 /* Support shares on a network resource as subdirectories of a read-only
2374 root directory. */
2375 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2376 static HANDLE open_unc_volume (const char *);
2377 static char *read_unc_volume (HANDLE, char *, int);
2378 static void close_unc_volume (HANDLE);
2380 DIR *
2381 opendir (char *filename)
2383 DIR *dirp;
2385 /* Opening is done by FindFirstFile. However, a read is inherent to
2386 this operation, so we defer the open until read time. */
2388 if (dir_find_handle != INVALID_HANDLE_VALUE)
2389 return NULL;
2390 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2391 return NULL;
2393 if (is_unc_volume (filename))
2395 wnet_enum_handle = open_unc_volume (filename);
2396 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2397 return NULL;
2400 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2401 return NULL;
2403 dirp->dd_fd = 0;
2404 dirp->dd_loc = 0;
2405 dirp->dd_size = 0;
2407 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2408 dir_pathname[MAXPATHLEN] = '\0';
2409 dir_is_fat = is_fat_volume (filename, NULL);
2411 return dirp;
2414 void
2415 closedir (DIR *dirp)
2417 /* If we have a find-handle open, close it. */
2418 if (dir_find_handle != INVALID_HANDLE_VALUE)
2420 FindClose (dir_find_handle);
2421 dir_find_handle = INVALID_HANDLE_VALUE;
2423 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2425 close_unc_volume (wnet_enum_handle);
2426 wnet_enum_handle = INVALID_HANDLE_VALUE;
2428 xfree ((char *) dirp);
2431 struct direct *
2432 readdir (DIR *dirp)
2434 int downcase = !NILP (Vw32_downcase_file_names);
2436 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2438 if (!read_unc_volume (wnet_enum_handle,
2439 dir_find_data.cFileName,
2440 MAX_PATH))
2441 return NULL;
2443 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2444 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2446 char filename[MAXNAMLEN + 3];
2447 int ln;
2449 strcpy (filename, dir_pathname);
2450 ln = strlen (filename) - 1;
2451 if (!IS_DIRECTORY_SEP (filename[ln]))
2452 strcat (filename, "\\");
2453 strcat (filename, "*");
2455 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2457 if (dir_find_handle == INVALID_HANDLE_VALUE)
2458 return NULL;
2460 else
2462 if (!FindNextFile (dir_find_handle, &dir_find_data))
2463 return NULL;
2466 /* Emacs never uses this value, so don't bother making it match
2467 value returned by stat(). */
2468 dir_static.d_ino = 1;
2470 strcpy (dir_static.d_name, dir_find_data.cFileName);
2472 /* If the file name in cFileName[] includes `?' characters, it means
2473 the original file name used characters that cannot be represented
2474 by the current ANSI codepage. To avoid total lossage, retrieve
2475 the short 8+3 alias of the long file name. */
2476 if (_mbspbrk (dir_static.d_name, "?"))
2478 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2479 downcase = 1; /* 8+3 aliases are returned in all caps */
2481 dir_static.d_namlen = strlen (dir_static.d_name);
2482 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
2483 dir_static.d_namlen - dir_static.d_namlen % 4;
2485 /* If the file name in cFileName[] includes `?' characters, it means
2486 the original file name used characters that cannot be represented
2487 by the current ANSI codepage. To avoid total lossage, retrieve
2488 the short 8+3 alias of the long file name. */
2489 if (_mbspbrk (dir_find_data.cFileName, "?"))
2491 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2492 /* 8+3 aliases are returned in all caps, which could break
2493 various alists that look at filenames' extensions. */
2494 downcase = 1;
2496 else
2497 strcpy (dir_static.d_name, dir_find_data.cFileName);
2498 dir_static.d_namlen = strlen (dir_static.d_name);
2499 if (dir_is_fat)
2500 _strlwr (dir_static.d_name);
2501 else if (downcase)
2503 register char *p;
2504 for (p = dir_static.d_name; *p; p++)
2505 if (*p >= 'a' && *p <= 'z')
2506 break;
2507 if (!*p)
2508 _strlwr (dir_static.d_name);
2511 return &dir_static;
2514 static HANDLE
2515 open_unc_volume (const char *path)
2517 NETRESOURCE nr;
2518 HANDLE henum;
2519 int result;
2521 nr.dwScope = RESOURCE_GLOBALNET;
2522 nr.dwType = RESOURCETYPE_DISK;
2523 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2524 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2525 nr.lpLocalName = NULL;
2526 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
2527 nr.lpComment = NULL;
2528 nr.lpProvider = NULL;
2530 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2531 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2533 if (result == NO_ERROR)
2534 return henum;
2535 else
2536 return INVALID_HANDLE_VALUE;
2539 static char *
2540 read_unc_volume (HANDLE henum, char *readbuf, int size)
2542 DWORD count;
2543 int result;
2544 DWORD bufsize = 512;
2545 char *buffer;
2546 char *ptr;
2548 count = 1;
2549 buffer = alloca (bufsize);
2550 result = WNetEnumResource (henum, &count, buffer, &bufsize);
2551 if (result != NO_ERROR)
2552 return NULL;
2554 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2555 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2556 ptr += 2;
2557 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2558 ptr++;
2560 strncpy (readbuf, ptr, size);
2561 return readbuf;
2564 static void
2565 close_unc_volume (HANDLE henum)
2567 if (henum != INVALID_HANDLE_VALUE)
2568 WNetCloseEnum (henum);
2571 static DWORD
2572 unc_volume_file_attributes (const char *path)
2574 HANDLE henum;
2575 DWORD attrs;
2577 henum = open_unc_volume (path);
2578 if (henum == INVALID_HANDLE_VALUE)
2579 return -1;
2581 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2583 close_unc_volume (henum);
2585 return attrs;
2588 /* Ensure a network connection is authenticated. */
2589 static void
2590 logon_network_drive (const char *path)
2592 NETRESOURCE resource;
2593 char share[MAX_PATH];
2594 int i, n_slashes;
2595 char drive[4];
2596 UINT drvtype;
2598 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
2599 drvtype = DRIVE_REMOTE;
2600 else if (path[0] == '\0' || path[1] != ':')
2601 drvtype = GetDriveType (NULL);
2602 else
2604 drive[0] = path[0];
2605 drive[1] = ':';
2606 drive[2] = '\\';
2607 drive[3] = '\0';
2608 drvtype = GetDriveType (drive);
2611 /* Only logon to networked drives. */
2612 if (drvtype != DRIVE_REMOTE)
2613 return;
2615 n_slashes = 2;
2616 strncpy (share, path, MAX_PATH);
2617 /* Truncate to just server and share name. */
2618 for (i = 2; i < MAX_PATH; i++)
2620 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2622 share[i] = '\0';
2623 break;
2627 resource.dwType = RESOURCETYPE_DISK;
2628 resource.lpLocalName = NULL;
2629 resource.lpRemoteName = share;
2630 resource.lpProvider = NULL;
2632 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2635 /* Shadow some MSVC runtime functions to map requests for long filenames
2636 to reasonable short names if necessary. This was originally added to
2637 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2638 long file names. */
2641 sys_access (const char * path, int mode)
2643 DWORD attributes;
2645 /* MSVC implementation doesn't recognize D_OK. */
2646 path = map_w32_filename (path, NULL);
2647 if (is_unc_volume (path))
2649 attributes = unc_volume_file_attributes (path);
2650 if (attributes == -1) {
2651 errno = EACCES;
2652 return -1;
2655 else if ((attributes = GetFileAttributes (path)) == -1)
2657 /* Should try mapping GetLastError to errno; for now just indicate
2658 that path doesn't exist. */
2659 errno = EACCES;
2660 return -1;
2662 if ((mode & X_OK) != 0 && !is_exec (path))
2664 errno = EACCES;
2665 return -1;
2667 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2669 errno = EACCES;
2670 return -1;
2672 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2674 errno = EACCES;
2675 return -1;
2677 return 0;
2681 sys_chdir (const char * path)
2683 return _chdir (map_w32_filename (path, NULL));
2687 sys_chmod (const char * path, int mode)
2689 return _chmod (map_w32_filename (path, NULL), mode);
2693 sys_chown (const char *path, uid_t owner, gid_t group)
2695 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2696 return -1;
2697 return 0;
2701 sys_creat (const char * path, int mode)
2703 return _creat (map_w32_filename (path, NULL), mode);
2706 FILE *
2707 sys_fopen (const char * path, const char * mode)
2709 int fd;
2710 int oflag;
2711 const char * mode_save = mode;
2713 /* Force all file handles to be non-inheritable. This is necessary to
2714 ensure child processes don't unwittingly inherit handles that might
2715 prevent future file access. */
2717 if (mode[0] == 'r')
2718 oflag = O_RDONLY;
2719 else if (mode[0] == 'w' || mode[0] == 'a')
2720 oflag = O_WRONLY | O_CREAT | O_TRUNC;
2721 else
2722 return NULL;
2724 /* Only do simplistic option parsing. */
2725 while (*++mode)
2726 if (mode[0] == '+')
2728 oflag &= ~(O_RDONLY | O_WRONLY);
2729 oflag |= O_RDWR;
2731 else if (mode[0] == 'b')
2733 oflag &= ~O_TEXT;
2734 oflag |= O_BINARY;
2736 else if (mode[0] == 't')
2738 oflag &= ~O_BINARY;
2739 oflag |= O_TEXT;
2741 else break;
2743 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2744 if (fd < 0)
2745 return NULL;
2747 return _fdopen (fd, mode_save);
2750 /* This only works on NTFS volumes, but is useful to have. */
2752 sys_link (const char * old, const char * new)
2754 HANDLE fileh;
2755 int result = -1;
2756 char oldname[MAX_PATH], newname[MAX_PATH];
2758 if (old == NULL || new == NULL)
2760 errno = ENOENT;
2761 return -1;
2764 strcpy (oldname, map_w32_filename (old, NULL));
2765 strcpy (newname, map_w32_filename (new, NULL));
2767 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2768 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2769 if (fileh != INVALID_HANDLE_VALUE)
2771 int wlen;
2773 /* Confusingly, the "alternate" stream name field does not apply
2774 when restoring a hard link, and instead contains the actual
2775 stream data for the link (ie. the name of the link to create).
2776 The WIN32_STREAM_ID structure before the cStreamName field is
2777 the stream header, which is then immediately followed by the
2778 stream data. */
2780 struct {
2781 WIN32_STREAM_ID wid;
2782 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2783 } data;
2785 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2786 data.wid.cStreamName, MAX_PATH);
2787 if (wlen > 0)
2789 LPVOID context = NULL;
2790 DWORD wbytes = 0;
2792 data.wid.dwStreamId = BACKUP_LINK;
2793 data.wid.dwStreamAttributes = 0;
2794 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
2795 data.wid.Size.HighPart = 0;
2796 data.wid.dwStreamNameSize = 0;
2798 if (BackupWrite (fileh, (LPBYTE)&data,
2799 offsetof (WIN32_STREAM_ID, cStreamName)
2800 + data.wid.Size.LowPart,
2801 &wbytes, FALSE, FALSE, &context)
2802 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2804 /* succeeded */
2805 result = 0;
2807 else
2809 /* Should try mapping GetLastError to errno; for now just
2810 indicate a general error (eg. links not supported). */
2811 errno = EINVAL; // perhaps EMLINK?
2815 CloseHandle (fileh);
2817 else
2818 errno = ENOENT;
2820 return result;
2824 sys_mkdir (const char * path)
2826 return _mkdir (map_w32_filename (path, NULL));
2829 /* Because of long name mapping issues, we need to implement this
2830 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2831 a unique name, instead of setting the input template to an empty
2832 string.
2834 Standard algorithm seems to be use pid or tid with a letter on the
2835 front (in place of the 6 X's) and cycle through the letters to find a
2836 unique name. We extend that to allow any reasonable character as the
2837 first of the 6 X's. */
2838 char *
2839 sys_mktemp (char * template)
2841 char * p;
2842 int i;
2843 unsigned uid = GetCurrentThreadId ();
2844 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2846 if (template == NULL)
2847 return NULL;
2848 p = template + strlen (template);
2849 i = 5;
2850 /* replace up to the last 5 X's with uid in decimal */
2851 while (--p >= template && p[0] == 'X' && --i >= 0)
2853 p[0] = '0' + uid % 10;
2854 uid /= 10;
2857 if (i < 0 && p[0] == 'X')
2859 i = 0;
2862 int save_errno = errno;
2863 p[0] = first_char[i];
2864 if (sys_access (template, 0) < 0)
2866 errno = save_errno;
2867 return template;
2870 while (++i < sizeof (first_char));
2873 /* Template is badly formed or else we can't generate a unique name,
2874 so return empty string */
2875 template[0] = 0;
2876 return template;
2880 sys_open (const char * path, int oflag, int mode)
2882 const char* mpath = map_w32_filename (path, NULL);
2883 /* Try to open file without _O_CREAT, to be able to write to hidden
2884 and system files. Force all file handles to be
2885 non-inheritable. */
2886 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2887 if (res >= 0)
2888 return res;
2889 return _open (mpath, oflag | _O_NOINHERIT, mode);
2893 sys_rename (const char * oldname, const char * newname)
2895 BOOL result;
2896 char temp[MAX_PATH];
2897 int newname_dev;
2898 int oldname_dev;
2900 /* MoveFile on Windows 95 doesn't correctly change the short file name
2901 alias in a number of circumstances (it is not easy to predict when
2902 just by looking at oldname and newname, unfortunately). In these
2903 cases, renaming through a temporary name avoids the problem.
2905 A second problem on Windows 95 is that renaming through a temp name when
2906 newname is uppercase fails (the final long name ends up in
2907 lowercase, although the short alias might be uppercase) UNLESS the
2908 long temp name is not 8.3.
2910 So, on Windows 95 we always rename through a temp name, and we make sure
2911 the temp name has a long extension to ensure correct renaming. */
2913 strcpy (temp, map_w32_filename (oldname, NULL));
2915 /* volume_info is set indirectly by map_w32_filename. */
2916 oldname_dev = volume_info.serialnum;
2918 if (os_subtype == OS_WIN95)
2920 char * o;
2921 char * p;
2922 int i = 0;
2924 oldname = map_w32_filename (oldname, NULL);
2925 if ((o = strrchr (oldname, '\\')))
2926 o++;
2927 else
2928 o = (char *) oldname;
2930 if ((p = strrchr (temp, '\\')))
2931 p++;
2932 else
2933 p = temp;
2937 /* Force temp name to require a manufactured 8.3 alias - this
2938 seems to make the second rename work properly. */
2939 sprintf (p, "_.%s.%u", o, i);
2940 i++;
2941 result = rename (oldname, temp);
2943 /* This loop must surely terminate! */
2944 while (result < 0 && errno == EEXIST);
2945 if (result < 0)
2946 return -1;
2949 /* Emulate Unix behavior - newname is deleted if it already exists
2950 (at least if it is a file; don't do this for directories).
2952 Since we mustn't do this if we are just changing the case of the
2953 file name (we would end up deleting the file we are trying to
2954 rename!), we let rename detect if the destination file already
2955 exists - that way we avoid the possible pitfalls of trying to
2956 determine ourselves whether two names really refer to the same
2957 file, which is not always possible in the general case. (Consider
2958 all the permutations of shared or subst'd drives, etc.) */
2960 newname = map_w32_filename (newname, NULL);
2962 /* volume_info is set indirectly by map_w32_filename. */
2963 newname_dev = volume_info.serialnum;
2965 result = rename (temp, newname);
2967 if (result < 0)
2970 if (errno == EACCES
2971 && newname_dev != oldname_dev)
2973 /* The implementation of `rename' on Windows does not return
2974 errno = EXDEV when you are moving a directory to a
2975 different storage device (ex. logical disk). It returns
2976 EACCES instead. So here we handle such situations and
2977 return EXDEV. */
2978 DWORD attributes;
2980 if ((attributes = GetFileAttributes (temp)) != -1
2981 && attributes & FILE_ATTRIBUTE_DIRECTORY)
2982 errno = EXDEV;
2984 else if (errno == EEXIST)
2986 if (_chmod (newname, 0666) != 0)
2987 return result;
2988 if (_unlink (newname) != 0)
2989 return result;
2990 result = rename (temp, newname);
2994 return result;
2998 sys_rmdir (const char * path)
3000 return _rmdir (map_w32_filename (path, NULL));
3004 sys_unlink (const char * path)
3006 path = map_w32_filename (path, NULL);
3008 /* On Unix, unlink works without write permission. */
3009 _chmod (path, 0666);
3010 return _unlink (path);
3013 static FILETIME utc_base_ft;
3014 static ULONGLONG utc_base; /* In 100ns units */
3015 static int init = 0;
3017 #define FILETIME_TO_U64(result, ft) \
3018 do { \
3019 ULARGE_INTEGER uiTemp; \
3020 uiTemp.LowPart = (ft).dwLowDateTime; \
3021 uiTemp.HighPart = (ft).dwHighDateTime; \
3022 result = uiTemp.QuadPart; \
3023 } while (0)
3025 static void
3026 initialize_utc_base (void)
3028 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3029 SYSTEMTIME st;
3031 st.wYear = 1970;
3032 st.wMonth = 1;
3033 st.wDay = 1;
3034 st.wHour = 0;
3035 st.wMinute = 0;
3036 st.wSecond = 0;
3037 st.wMilliseconds = 0;
3039 SystemTimeToFileTime (&st, &utc_base_ft);
3040 FILETIME_TO_U64 (utc_base, utc_base_ft);
3043 static time_t
3044 convert_time (FILETIME ft)
3046 ULONGLONG tmp;
3048 if (!init)
3050 initialize_utc_base ();
3051 init = 1;
3054 if (CompareFileTime (&ft, &utc_base_ft) < 0)
3055 return 0;
3057 FILETIME_TO_U64 (tmp, ft);
3058 return (time_t) ((tmp - utc_base) / 10000000L);
3061 static void
3062 convert_from_time_t (time_t time, FILETIME * pft)
3064 ULARGE_INTEGER tmp;
3066 if (!init)
3068 initialize_utc_base ();
3069 init = 1;
3072 /* time in 100ns units since 1-Jan-1601 */
3073 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
3074 pft->dwHighDateTime = tmp.HighPart;
3075 pft->dwLowDateTime = tmp.LowPart;
3078 #if 0
3079 /* No reason to keep this; faking inode values either by hashing or even
3080 using the file index from GetInformationByHandle, is not perfect and
3081 so by default Emacs doesn't use the inode values on Windows.
3082 Instead, we now determine file-truename correctly (except for
3083 possible drive aliasing etc). */
3085 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3086 static unsigned
3087 hashval (const unsigned char * str)
3089 unsigned h = 0;
3090 while (*str)
3092 h = (h << 4) + *str++;
3093 h ^= (h >> 28);
3095 return h;
3098 /* Return the hash value of the canonical pathname, excluding the
3099 drive/UNC header, to get a hopefully unique inode number. */
3100 static DWORD
3101 generate_inode_val (const char * name)
3103 char fullname[ MAX_PATH ];
3104 char * p;
3105 unsigned hash;
3107 /* Get the truly canonical filename, if it exists. (Note: this
3108 doesn't resolve aliasing due to subst commands, or recognize hard
3109 links. */
3110 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3111 abort ();
3113 parse_root (fullname, &p);
3114 /* Normal W32 filesystems are still case insensitive. */
3115 _strlwr (p);
3116 return hashval (p);
3119 #endif
3121 static PSECURITY_DESCRIPTOR
3122 get_file_security_desc (const char *fname)
3124 PSECURITY_DESCRIPTOR psd = NULL;
3125 DWORD sd_len, err;
3126 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3127 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3129 if (!get_file_security (fname, si, psd, 0, &sd_len))
3131 err = GetLastError ();
3132 if (err != ERROR_INSUFFICIENT_BUFFER)
3133 return NULL;
3136 psd = xmalloc (sd_len);
3137 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3139 xfree (psd);
3140 return NULL;
3143 return psd;
3146 static DWORD
3147 get_rid (PSID sid)
3149 unsigned n_subauthorities;
3151 /* Use the last sub-authority value of the RID, the relative
3152 portion of the SID, as user/group ID. */
3153 n_subauthorities = *get_sid_sub_authority_count (sid);
3154 if (n_subauthorities < 1)
3155 return 0; /* the "World" RID */
3156 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3159 /* Caching SID and account values for faster lokup. */
3161 #ifdef __GNUC__
3162 # define FLEXIBLE_ARRAY_MEMBER
3163 #else
3164 # define FLEXIBLE_ARRAY_MEMBER 1
3165 #endif
3167 struct w32_id {
3168 unsigned rid;
3169 struct w32_id *next;
3170 char name[GNLEN+1];
3171 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3174 static struct w32_id *w32_idlist;
3176 static int
3177 w32_cached_id (PSID sid, unsigned *id, char *name)
3179 struct w32_id *tail, *found;
3181 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3183 if (equal_sid ((PSID)tail->sid, sid))
3185 found = tail;
3186 break;
3189 if (found)
3191 *id = found->rid;
3192 strcpy (name, found->name);
3193 return 1;
3195 else
3196 return 0;
3199 static void
3200 w32_add_to_cache (PSID sid, unsigned id, char *name)
3202 DWORD sid_len;
3203 struct w32_id *new_entry;
3205 /* We don't want to leave behind stale cache from when Emacs was
3206 dumped. */
3207 if (initialized)
3209 sid_len = get_length_sid (sid);
3210 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3211 if (new_entry)
3213 new_entry->rid = id;
3214 strcpy (new_entry->name, name);
3215 copy_sid (sid_len, (PSID)new_entry->sid, sid);
3216 new_entry->next = w32_idlist;
3217 w32_idlist = new_entry;
3222 #define UID 1
3223 #define GID 2
3225 static int
3226 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
3227 unsigned *id, char *nm, int what)
3229 PSID sid = NULL;
3230 char machine[MAX_COMPUTERNAME_LENGTH+1];
3231 BOOL dflt;
3232 SID_NAME_USE ignore;
3233 char name[UNLEN+1];
3234 DWORD name_len = sizeof (name);
3235 char domain[1024];
3236 DWORD domain_len = sizeof (domain);
3237 char *mp = NULL;
3238 int use_dflt = 0;
3239 int result;
3241 if (what == UID)
3242 result = get_security_descriptor_owner (psd, &sid, &dflt);
3243 else if (what == GID)
3244 result = get_security_descriptor_group (psd, &sid, &dflt);
3245 else
3246 result = 0;
3248 if (!result || !is_valid_sid (sid))
3249 use_dflt = 1;
3250 else if (!w32_cached_id (sid, id, nm))
3252 /* If FNAME is a UNC, we need to lookup account on the
3253 specified machine. */
3254 if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
3255 && fname[2] != '\0')
3257 const char *s;
3258 char *p;
3260 for (s = fname + 2, p = machine;
3261 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
3262 *p = *s;
3263 *p = '\0';
3264 mp = machine;
3267 if (!lookup_account_sid (mp, sid, name, &name_len,
3268 domain, &domain_len, &ignore)
3269 || name_len > UNLEN+1)
3270 use_dflt = 1;
3271 else
3273 *id = get_rid (sid);
3274 strcpy (nm, name);
3275 w32_add_to_cache (sid, *id, name);
3278 return use_dflt;
3281 static void
3282 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd,
3283 const char *fname,
3284 struct stat *st)
3286 int dflt_usr = 0, dflt_grp = 0;
3288 if (!psd)
3290 dflt_usr = 1;
3291 dflt_grp = 1;
3293 else
3295 if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
3296 dflt_usr = 1;
3297 if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
3298 dflt_grp = 1;
3300 /* Consider files to belong to current user/group, if we cannot get
3301 more accurate information. */
3302 if (dflt_usr)
3304 st->st_uid = dflt_passwd.pw_uid;
3305 strcpy (st->st_uname, dflt_passwd.pw_name);
3307 if (dflt_grp)
3309 st->st_gid = dflt_passwd.pw_gid;
3310 strcpy (st->st_gname, dflt_group.gr_name);
3314 /* Return non-zero if NAME is a potentially slow filesystem. */
3316 is_slow_fs (const char *name)
3318 char drive_root[4];
3319 UINT devtype;
3321 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
3322 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
3323 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
3324 devtype = GetDriveType (NULL); /* use root of current drive */
3325 else
3327 /* GetDriveType needs the root directory of the drive. */
3328 strncpy (drive_root, name, 2);
3329 drive_root[2] = '\\';
3330 drive_root[3] = '\0';
3331 devtype = GetDriveType (drive_root);
3333 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
3336 /* MSVC stat function can't cope with UNC names and has other bugs, so
3337 replace it with our own. This also allows us to calculate consistent
3338 inode values without hacks in the main Emacs code. */
3340 stat (const char * path, struct stat * buf)
3342 char *name, *r;
3343 WIN32_FIND_DATA wfd;
3344 HANDLE fh;
3345 unsigned __int64 fake_inode;
3346 int permission;
3347 int len;
3348 int rootdir = FALSE;
3349 PSECURITY_DESCRIPTOR psd = NULL;
3351 if (path == NULL || buf == NULL)
3353 errno = EFAULT;
3354 return -1;
3357 name = (char *) map_w32_filename (path, &path);
3358 /* Must be valid filename, no wild cards or other invalid
3359 characters. We use _mbspbrk to support multibyte strings that
3360 might look to strpbrk as if they included literal *, ?, and other
3361 characters mentioned below that are disallowed by Windows
3362 filesystems. */
3363 if (_mbspbrk (name, "*?|<>\""))
3365 errno = ENOENT;
3366 return -1;
3369 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3370 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3371 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3373 r[1] = r[2] = '\0';
3376 /* Remove trailing directory separator, unless name is the root
3377 directory of a drive or UNC volume in which case ensure there
3378 is a trailing separator. */
3379 len = strlen (name);
3380 rootdir = (path >= name + len - 1
3381 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3382 name = strcpy (alloca (len + 2), name);
3384 if (is_unc_volume (name))
3386 DWORD attrs = unc_volume_file_attributes (name);
3388 if (attrs == -1)
3389 return -1;
3391 memset (&wfd, 0, sizeof (wfd));
3392 wfd.dwFileAttributes = attrs;
3393 wfd.ftCreationTime = utc_base_ft;
3394 wfd.ftLastAccessTime = utc_base_ft;
3395 wfd.ftLastWriteTime = utc_base_ft;
3396 strcpy (wfd.cFileName, name);
3398 else if (rootdir)
3400 if (!IS_DIRECTORY_SEP (name[len-1]))
3401 strcat (name, "\\");
3402 if (GetDriveType (name) < 2)
3404 errno = ENOENT;
3405 return -1;
3407 memset (&wfd, 0, sizeof (wfd));
3408 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
3409 wfd.ftCreationTime = utc_base_ft;
3410 wfd.ftLastAccessTime = utc_base_ft;
3411 wfd.ftLastWriteTime = utc_base_ft;
3412 strcpy (wfd.cFileName, name);
3414 else
3416 if (IS_DIRECTORY_SEP (name[len-1]))
3417 name[len - 1] = 0;
3419 /* (This is hacky, but helps when doing file completions on
3420 network drives.) Optimize by using information available from
3421 active readdir if possible. */
3422 len = strlen (dir_pathname);
3423 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3424 len--;
3425 if (dir_find_handle != INVALID_HANDLE_VALUE
3426 && strnicmp (name, dir_pathname, len) == 0
3427 && IS_DIRECTORY_SEP (name[len])
3428 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3430 /* This was the last entry returned by readdir. */
3431 wfd = dir_find_data;
3433 else
3435 logon_network_drive (name);
3437 fh = FindFirstFile (name, &wfd);
3438 if (fh == INVALID_HANDLE_VALUE)
3440 errno = ENOENT;
3441 return -1;
3443 FindClose (fh);
3447 if (!(NILP (Vw32_get_true_file_attributes)
3448 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
3449 /* No access rights required to get info. */
3450 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
3451 FILE_FLAG_BACKUP_SEMANTICS, NULL))
3452 != INVALID_HANDLE_VALUE)
3454 /* This is more accurate in terms of getting the correct number
3455 of links, but is quite slow (it is noticeable when Emacs is
3456 making a list of file name completions). */
3457 BY_HANDLE_FILE_INFORMATION info;
3459 if (GetFileInformationByHandle (fh, &info))
3461 buf->st_nlink = info.nNumberOfLinks;
3462 /* Might as well use file index to fake inode values, but this
3463 is not guaranteed to be unique unless we keep a handle open
3464 all the time (even then there are situations where it is
3465 not unique). Reputedly, there are at most 48 bits of info
3466 (on NTFS, presumably less on FAT). */
3467 fake_inode = info.nFileIndexHigh;
3468 fake_inode <<= 32;
3469 fake_inode += info.nFileIndexLow;
3471 else
3473 buf->st_nlink = 1;
3474 fake_inode = 0;
3477 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3479 buf->st_mode = S_IFDIR;
3481 else
3483 switch (GetFileType (fh))
3485 case FILE_TYPE_DISK:
3486 buf->st_mode = S_IFREG;
3487 break;
3488 case FILE_TYPE_PIPE:
3489 buf->st_mode = S_IFIFO;
3490 break;
3491 case FILE_TYPE_CHAR:
3492 case FILE_TYPE_UNKNOWN:
3493 default:
3494 buf->st_mode = S_IFCHR;
3497 CloseHandle (fh);
3498 psd = get_file_security_desc (name);
3499 get_file_owner_and_group (psd, name, buf);
3501 else
3503 /* Don't bother to make this information more accurate. */
3504 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
3505 S_IFDIR : S_IFREG;
3506 buf->st_nlink = 1;
3507 fake_inode = 0;
3509 get_file_owner_and_group (NULL, name, buf);
3511 xfree (psd);
3513 #if 0
3514 /* Not sure if there is any point in this. */
3515 if (!NILP (Vw32_generate_fake_inodes))
3516 fake_inode = generate_inode_val (name);
3517 else if (fake_inode == 0)
3519 /* For want of something better, try to make everything unique. */
3520 static DWORD gen_num = 0;
3521 fake_inode = ++gen_num;
3523 #endif
3525 /* MSVC defines _ino_t to be short; other libc's might not. */
3526 if (sizeof (buf->st_ino) == 2)
3527 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3528 else
3529 buf->st_ino = fake_inode;
3531 /* volume_info is set indirectly by map_w32_filename */
3532 buf->st_dev = volume_info.serialnum;
3533 buf->st_rdev = volume_info.serialnum;
3535 buf->st_size = wfd.nFileSizeHigh;
3536 buf->st_size <<= 32;
3537 buf->st_size += wfd.nFileSizeLow;
3539 /* Convert timestamps to Unix format. */
3540 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
3541 buf->st_atime = convert_time (wfd.ftLastAccessTime);
3542 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3543 buf->st_ctime = convert_time (wfd.ftCreationTime);
3544 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3546 /* determine rwx permissions */
3547 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3548 permission = S_IREAD;
3549 else
3550 permission = S_IREAD | S_IWRITE;
3552 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3553 permission |= S_IEXEC;
3554 else if (is_exec (name))
3555 permission |= S_IEXEC;
3557 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3559 return 0;
3562 /* Provide fstat and utime as well as stat for consistent handling of
3563 file timestamps. */
3565 fstat (int desc, struct stat * buf)
3567 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3568 BY_HANDLE_FILE_INFORMATION info;
3569 unsigned __int64 fake_inode;
3570 int permission;
3572 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3574 case FILE_TYPE_DISK:
3575 buf->st_mode = S_IFREG;
3576 if (!GetFileInformationByHandle (fh, &info))
3578 errno = EACCES;
3579 return -1;
3581 break;
3582 case FILE_TYPE_PIPE:
3583 buf->st_mode = S_IFIFO;
3584 goto non_disk;
3585 case FILE_TYPE_CHAR:
3586 case FILE_TYPE_UNKNOWN:
3587 default:
3588 buf->st_mode = S_IFCHR;
3589 non_disk:
3590 memset (&info, 0, sizeof (info));
3591 info.dwFileAttributes = 0;
3592 info.ftCreationTime = utc_base_ft;
3593 info.ftLastAccessTime = utc_base_ft;
3594 info.ftLastWriteTime = utc_base_ft;
3597 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3598 buf->st_mode = S_IFDIR;
3600 buf->st_nlink = info.nNumberOfLinks;
3601 /* Might as well use file index to fake inode values, but this
3602 is not guaranteed to be unique unless we keep a handle open
3603 all the time (even then there are situations where it is
3604 not unique). Reputedly, there are at most 48 bits of info
3605 (on NTFS, presumably less on FAT). */
3606 fake_inode = info.nFileIndexHigh;
3607 fake_inode <<= 32;
3608 fake_inode += info.nFileIndexLow;
3610 /* MSVC defines _ino_t to be short; other libc's might not. */
3611 if (sizeof (buf->st_ino) == 2)
3612 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3613 else
3614 buf->st_ino = fake_inode;
3616 /* Consider files to belong to current user.
3617 FIXME: this should use GetSecurityInfo API, but it is only
3618 available for _WIN32_WINNT >= 0x501. */
3619 buf->st_uid = dflt_passwd.pw_uid;
3620 buf->st_gid = dflt_passwd.pw_gid;
3621 strcpy (buf->st_uname, dflt_passwd.pw_name);
3622 strcpy (buf->st_gname, dflt_group.gr_name);
3624 buf->st_dev = info.dwVolumeSerialNumber;
3625 buf->st_rdev = info.dwVolumeSerialNumber;
3627 buf->st_size = info.nFileSizeHigh;
3628 buf->st_size <<= 32;
3629 buf->st_size += info.nFileSizeLow;
3631 /* Convert timestamps to Unix format. */
3632 buf->st_mtime = convert_time (info.ftLastWriteTime);
3633 buf->st_atime = convert_time (info.ftLastAccessTime);
3634 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3635 buf->st_ctime = convert_time (info.ftCreationTime);
3636 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3638 /* determine rwx permissions */
3639 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3640 permission = S_IREAD;
3641 else
3642 permission = S_IREAD | S_IWRITE;
3644 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3645 permission |= S_IEXEC;
3646 else
3648 #if 0 /* no way of knowing the filename */
3649 char * p = strrchr (name, '.');
3650 if (p != NULL &&
3651 (xstrcasecmp (p, ".exe") == 0 ||
3652 xstrcasecmp (p, ".com") == 0 ||
3653 xstrcasecmp (p, ".bat") == 0 ||
3654 xstrcasecmp (p, ".cmd") == 0))
3655 permission |= S_IEXEC;
3656 #endif
3659 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3661 return 0;
3665 utime (const char *name, struct utimbuf *times)
3667 struct utimbuf deftime;
3668 HANDLE fh;
3669 FILETIME mtime;
3670 FILETIME atime;
3672 if (times == NULL)
3674 deftime.modtime = deftime.actime = time (NULL);
3675 times = &deftime;
3678 /* Need write access to set times. */
3679 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
3680 0, OPEN_EXISTING, 0, NULL);
3681 if (fh)
3683 convert_from_time_t (times->actime, &atime);
3684 convert_from_time_t (times->modtime, &mtime);
3685 if (!SetFileTime (fh, NULL, &atime, &mtime))
3687 CloseHandle (fh);
3688 errno = EACCES;
3689 return -1;
3691 CloseHandle (fh);
3693 else
3695 errno = EINVAL;
3696 return -1;
3698 return 0;
3702 /* Symlink-related functions that always fail. Used in fileio.c and in
3703 sysdep.c to avoid #ifdef's. */
3705 symlink (char const *dummy1, char const *dummy2)
3707 errno = ENOSYS;
3708 return -1;
3711 ssize_t
3712 readlink (const char *name, char *dummy1, size_t dummy2)
3714 /* `access' is much faster than `stat' on MS-Windows. */
3715 if (sys_access (name, 0) == 0)
3716 errno = EINVAL;
3717 return -1;
3720 char *
3721 careadlinkat (int fd, char const *filename,
3722 char *buffer, size_t buffer_size,
3723 struct allocator const *alloc,
3724 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
3726 errno = ENOSYS;
3727 return NULL;
3730 ssize_t
3731 careadlinkatcwd (int fd, char const *filename, char *buffer,
3732 size_t buffer_size)
3734 (void) fd;
3735 return readlink (filename, buffer, buffer_size);
3739 /* Support for browsing other processes and their attributes. See
3740 process.c for the Lisp bindings. */
3742 /* Helper wrapper functions. */
3744 static HANDLE WINAPI
3745 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
3747 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
3749 if (g_b_init_create_toolhelp32_snapshot == 0)
3751 g_b_init_create_toolhelp32_snapshot = 1;
3752 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
3753 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3754 "CreateToolhelp32Snapshot");
3756 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
3758 return INVALID_HANDLE_VALUE;
3760 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
3763 static BOOL WINAPI
3764 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
3766 static Process32First_Proc s_pfn_Process32_First = NULL;
3768 if (g_b_init_process32_first == 0)
3770 g_b_init_process32_first = 1;
3771 s_pfn_Process32_First = (Process32First_Proc)
3772 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3773 "Process32First");
3775 if (s_pfn_Process32_First == NULL)
3777 return FALSE;
3779 return (s_pfn_Process32_First (hSnapshot, lppe));
3782 static BOOL WINAPI
3783 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
3785 static Process32Next_Proc s_pfn_Process32_Next = NULL;
3787 if (g_b_init_process32_next == 0)
3789 g_b_init_process32_next = 1;
3790 s_pfn_Process32_Next = (Process32Next_Proc)
3791 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3792 "Process32Next");
3794 if (s_pfn_Process32_Next == NULL)
3796 return FALSE;
3798 return (s_pfn_Process32_Next (hSnapshot, lppe));
3801 static BOOL WINAPI
3802 open_thread_token (HANDLE ThreadHandle,
3803 DWORD DesiredAccess,
3804 BOOL OpenAsSelf,
3805 PHANDLE TokenHandle)
3807 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
3808 HMODULE hm_advapi32 = NULL;
3809 if (is_windows_9x () == TRUE)
3811 SetLastError (ERROR_NOT_SUPPORTED);
3812 return FALSE;
3814 if (g_b_init_open_thread_token == 0)
3816 g_b_init_open_thread_token = 1;
3817 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3818 s_pfn_Open_Thread_Token =
3819 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
3821 if (s_pfn_Open_Thread_Token == NULL)
3823 SetLastError (ERROR_NOT_SUPPORTED);
3824 return FALSE;
3826 return (
3827 s_pfn_Open_Thread_Token (
3828 ThreadHandle,
3829 DesiredAccess,
3830 OpenAsSelf,
3831 TokenHandle)
3835 static BOOL WINAPI
3836 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
3838 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
3839 HMODULE hm_advapi32 = NULL;
3840 if (is_windows_9x () == TRUE)
3842 return FALSE;
3844 if (g_b_init_impersonate_self == 0)
3846 g_b_init_impersonate_self = 1;
3847 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3848 s_pfn_Impersonate_Self =
3849 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
3851 if (s_pfn_Impersonate_Self == NULL)
3853 return FALSE;
3855 return s_pfn_Impersonate_Self (ImpersonationLevel);
3858 static BOOL WINAPI
3859 revert_to_self (void)
3861 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
3862 HMODULE hm_advapi32 = NULL;
3863 if (is_windows_9x () == TRUE)
3865 return FALSE;
3867 if (g_b_init_revert_to_self == 0)
3869 g_b_init_revert_to_self = 1;
3870 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3871 s_pfn_Revert_To_Self =
3872 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
3874 if (s_pfn_Revert_To_Self == NULL)
3876 return FALSE;
3878 return s_pfn_Revert_To_Self ();
3881 static BOOL WINAPI
3882 get_process_memory_info (HANDLE h_proc,
3883 PPROCESS_MEMORY_COUNTERS mem_counters,
3884 DWORD bufsize)
3886 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
3887 HMODULE hm_psapi = NULL;
3888 if (is_windows_9x () == TRUE)
3890 return FALSE;
3892 if (g_b_init_get_process_memory_info == 0)
3894 g_b_init_get_process_memory_info = 1;
3895 hm_psapi = LoadLibrary ("Psapi.dll");
3896 if (hm_psapi)
3897 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
3898 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
3900 if (s_pfn_Get_Process_Memory_Info == NULL)
3902 return FALSE;
3904 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
3907 static BOOL WINAPI
3908 get_process_working_set_size (HANDLE h_proc,
3909 DWORD *minrss,
3910 DWORD *maxrss)
3912 static GetProcessWorkingSetSize_Proc
3913 s_pfn_Get_Process_Working_Set_Size = NULL;
3915 if (is_windows_9x () == TRUE)
3917 return FALSE;
3919 if (g_b_init_get_process_working_set_size == 0)
3921 g_b_init_get_process_working_set_size = 1;
3922 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
3923 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3924 "GetProcessWorkingSetSize");
3926 if (s_pfn_Get_Process_Working_Set_Size == NULL)
3928 return FALSE;
3930 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
3933 static BOOL WINAPI
3934 global_memory_status (MEMORYSTATUS *buf)
3936 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
3938 if (is_windows_9x () == TRUE)
3940 return FALSE;
3942 if (g_b_init_global_memory_status == 0)
3944 g_b_init_global_memory_status = 1;
3945 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
3946 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3947 "GlobalMemoryStatus");
3949 if (s_pfn_Global_Memory_Status == NULL)
3951 return FALSE;
3953 return s_pfn_Global_Memory_Status (buf);
3956 static BOOL WINAPI
3957 global_memory_status_ex (MEMORY_STATUS_EX *buf)
3959 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
3961 if (is_windows_9x () == TRUE)
3963 return FALSE;
3965 if (g_b_init_global_memory_status_ex == 0)
3967 g_b_init_global_memory_status_ex = 1;
3968 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
3969 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3970 "GlobalMemoryStatusEx");
3972 if (s_pfn_Global_Memory_Status_Ex == NULL)
3974 return FALSE;
3976 return s_pfn_Global_Memory_Status_Ex (buf);
3979 Lisp_Object
3980 list_system_processes (void)
3982 struct gcpro gcpro1;
3983 Lisp_Object proclist = Qnil;
3984 HANDLE h_snapshot;
3986 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
3988 if (h_snapshot != INVALID_HANDLE_VALUE)
3990 PROCESSENTRY32 proc_entry;
3991 DWORD proc_id;
3992 BOOL res;
3994 GCPRO1 (proclist);
3996 proc_entry.dwSize = sizeof (PROCESSENTRY32);
3997 for (res = process32_first (h_snapshot, &proc_entry); res;
3998 res = process32_next (h_snapshot, &proc_entry))
4000 proc_id = proc_entry.th32ProcessID;
4001 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
4004 CloseHandle (h_snapshot);
4005 UNGCPRO;
4006 proclist = Fnreverse (proclist);
4009 return proclist;
4012 static int
4013 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
4015 TOKEN_PRIVILEGES priv;
4016 DWORD priv_size = sizeof (priv);
4017 DWORD opriv_size = sizeof (*old_priv);
4018 HANDLE h_token = NULL;
4019 HANDLE h_thread = GetCurrentThread ();
4020 int ret_val = 0;
4021 BOOL res;
4023 res = open_thread_token (h_thread,
4024 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4025 FALSE, &h_token);
4026 if (!res && GetLastError () == ERROR_NO_TOKEN)
4028 if (impersonate_self (SecurityImpersonation))
4029 res = open_thread_token (h_thread,
4030 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4031 FALSE, &h_token);
4033 if (res)
4035 priv.PrivilegeCount = 1;
4036 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
4037 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
4038 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
4039 old_priv, &opriv_size)
4040 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
4041 ret_val = 1;
4043 if (h_token)
4044 CloseHandle (h_token);
4046 return ret_val;
4049 static int
4050 restore_privilege (TOKEN_PRIVILEGES *priv)
4052 DWORD priv_size = sizeof (*priv);
4053 HANDLE h_token = NULL;
4054 int ret_val = 0;
4056 if (open_thread_token (GetCurrentThread (),
4057 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4058 FALSE, &h_token))
4060 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
4061 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
4062 ret_val = 1;
4064 if (h_token)
4065 CloseHandle (h_token);
4067 return ret_val;
4070 static Lisp_Object
4071 ltime (long time_sec, long time_usec)
4073 return list3 (make_number ((time_sec >> 16) & 0xffff),
4074 make_number (time_sec & 0xffff),
4075 make_number (time_usec));
4078 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
4080 static int
4081 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
4082 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
4083 double *pcpu)
4085 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
4086 ULONGLONG tem1, tem2, tem3, tem;
4088 if (!h_proc
4089 || !get_process_times_fn
4090 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
4091 &ft_kernel, &ft_user))
4092 return 0;
4094 GetSystemTimeAsFileTime (&ft_current);
4096 FILETIME_TO_U64 (tem1, ft_kernel);
4097 tem1 /= 10L;
4098 *stime = U64_TO_LISP_TIME (tem1);
4100 FILETIME_TO_U64 (tem2, ft_user);
4101 tem2 /= 10L;
4102 *utime = U64_TO_LISP_TIME (tem2);
4104 tem3 = tem1 + tem2;
4105 *ttime = U64_TO_LISP_TIME (tem3);
4107 FILETIME_TO_U64 (tem, ft_creation);
4108 /* Process no 4 (System) returns zero creation time. */
4109 if (tem)
4110 tem = (tem - utc_base) / 10L;
4111 *ctime = U64_TO_LISP_TIME (tem);
4113 if (tem)
4115 FILETIME_TO_U64 (tem3, ft_current);
4116 tem = (tem3 - utc_base) / 10L - tem;
4118 *etime = U64_TO_LISP_TIME (tem);
4120 if (tem)
4122 *pcpu = 100.0 * (tem1 + tem2) / tem;
4123 if (*pcpu > 100)
4124 *pcpu = 100.0;
4126 else
4127 *pcpu = 0;
4129 return 1;
4132 Lisp_Object
4133 system_process_attributes (Lisp_Object pid)
4135 struct gcpro gcpro1, gcpro2, gcpro3;
4136 Lisp_Object attrs = Qnil;
4137 Lisp_Object cmd_str, decoded_cmd, tem;
4138 HANDLE h_snapshot, h_proc;
4139 DWORD proc_id;
4140 int found_proc = 0;
4141 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
4142 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
4143 DWORD glength = sizeof (gname);
4144 HANDLE token = NULL;
4145 SID_NAME_USE user_type;
4146 unsigned char *buf = NULL;
4147 DWORD blen = 0;
4148 TOKEN_USER user_token;
4149 TOKEN_PRIMARY_GROUP group_token;
4150 unsigned euid;
4151 unsigned egid;
4152 PROCESS_MEMORY_COUNTERS mem;
4153 PROCESS_MEMORY_COUNTERS_EX mem_ex;
4154 DWORD minrss, maxrss;
4155 MEMORYSTATUS memst;
4156 MEMORY_STATUS_EX memstex;
4157 double totphys = 0.0;
4158 Lisp_Object ctime, stime, utime, etime, ttime;
4159 double pcpu;
4160 BOOL result = FALSE;
4162 CHECK_NUMBER_OR_FLOAT (pid);
4163 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
4165 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4167 GCPRO3 (attrs, decoded_cmd, tem);
4169 if (h_snapshot != INVALID_HANDLE_VALUE)
4171 PROCESSENTRY32 pe;
4172 BOOL res;
4174 pe.dwSize = sizeof (PROCESSENTRY32);
4175 for (res = process32_first (h_snapshot, &pe); res;
4176 res = process32_next (h_snapshot, &pe))
4178 if (proc_id == pe.th32ProcessID)
4180 if (proc_id == 0)
4181 decoded_cmd = build_string ("Idle");
4182 else
4184 /* Decode the command name from locale-specific
4185 encoding. */
4186 cmd_str = make_unibyte_string (pe.szExeFile,
4187 strlen (pe.szExeFile));
4188 decoded_cmd =
4189 code_convert_string_norecord (cmd_str,
4190 Vlocale_coding_system, 0);
4192 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
4193 attrs = Fcons (Fcons (Qppid,
4194 make_fixnum_or_float (pe.th32ParentProcessID)),
4195 attrs);
4196 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
4197 attrs);
4198 attrs = Fcons (Fcons (Qthcount,
4199 make_fixnum_or_float (pe.cntThreads)),
4200 attrs);
4201 found_proc = 1;
4202 break;
4206 CloseHandle (h_snapshot);
4209 if (!found_proc)
4211 UNGCPRO;
4212 return Qnil;
4215 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4216 FALSE, proc_id);
4217 /* If we were denied a handle to the process, try again after
4218 enabling the SeDebugPrivilege in our process. */
4219 if (!h_proc)
4221 TOKEN_PRIVILEGES priv_current;
4223 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
4225 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4226 FALSE, proc_id);
4227 restore_privilege (&priv_current);
4228 revert_to_self ();
4231 if (h_proc)
4233 result = open_process_token (h_proc, TOKEN_QUERY, &token);
4234 if (result)
4236 result = get_token_information (token, TokenUser, NULL, 0, &blen);
4237 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4239 buf = xmalloc (blen);
4240 result = get_token_information (token, TokenUser,
4241 (LPVOID)buf, blen, &needed);
4242 if (result)
4244 memcpy (&user_token, buf, sizeof (user_token));
4245 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
4247 euid = get_rid (user_token.User.Sid);
4248 result = lookup_account_sid (NULL, user_token.User.Sid,
4249 uname, &ulength,
4250 domain, &dlength,
4251 &user_type);
4252 if (result)
4253 w32_add_to_cache (user_token.User.Sid, euid, uname);
4254 else
4256 strcpy (uname, "unknown");
4257 result = TRUE;
4260 ulength = strlen (uname);
4264 if (result)
4266 /* Determine a reasonable euid and gid values. */
4267 if (xstrcasecmp ("administrator", uname) == 0)
4269 euid = 500; /* well-known Administrator uid */
4270 egid = 513; /* well-known None gid */
4272 else
4274 /* Get group id and name. */
4275 result = get_token_information (token, TokenPrimaryGroup,
4276 (LPVOID)buf, blen, &needed);
4277 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4279 buf = xrealloc (buf, blen = needed);
4280 result = get_token_information (token, TokenPrimaryGroup,
4281 (LPVOID)buf, blen, &needed);
4283 if (result)
4285 memcpy (&group_token, buf, sizeof (group_token));
4286 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
4288 egid = get_rid (group_token.PrimaryGroup);
4289 dlength = sizeof (domain);
4290 result =
4291 lookup_account_sid (NULL, group_token.PrimaryGroup,
4292 gname, &glength, NULL, &dlength,
4293 &user_type);
4294 if (result)
4295 w32_add_to_cache (group_token.PrimaryGroup,
4296 egid, gname);
4297 else
4299 strcpy (gname, "None");
4300 result = TRUE;
4303 glength = strlen (gname);
4307 xfree (buf);
4309 if (!result)
4311 if (!is_windows_9x ())
4313 /* We couldn't open the process token, presumably because of
4314 insufficient access rights. Assume this process is run
4315 by the system. */
4316 strcpy (uname, "SYSTEM");
4317 strcpy (gname, "None");
4318 euid = 18; /* SYSTEM */
4319 egid = 513; /* None */
4320 glength = strlen (gname);
4321 ulength = strlen (uname);
4323 /* If we are running under Windows 9X, where security calls are
4324 not supported, we assume all processes are run by the current
4325 user. */
4326 else if (GetUserName (uname, &ulength))
4328 if (xstrcasecmp ("administrator", uname) == 0)
4329 euid = 0;
4330 else
4331 euid = 123;
4332 egid = euid;
4333 strcpy (gname, "None");
4334 glength = strlen (gname);
4335 ulength = strlen (uname);
4337 else
4339 euid = 123;
4340 egid = 123;
4341 strcpy (uname, "administrator");
4342 ulength = strlen (uname);
4343 strcpy (gname, "None");
4344 glength = strlen (gname);
4346 if (token)
4347 CloseHandle (token);
4350 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
4351 tem = make_unibyte_string (uname, ulength);
4352 attrs = Fcons (Fcons (Quser,
4353 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4354 attrs);
4355 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
4356 tem = make_unibyte_string (gname, glength);
4357 attrs = Fcons (Fcons (Qgroup,
4358 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4359 attrs);
4361 if (global_memory_status_ex (&memstex))
4362 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4363 totphys = memstex.ullTotalPhys / 1024.0;
4364 #else
4365 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4366 double, so we need to do this for it... */
4368 DWORD tot_hi = memstex.ullTotalPhys >> 32;
4369 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
4370 DWORD tot_lo = memstex.ullTotalPhys % 1024;
4372 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
4374 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4375 else if (global_memory_status (&memst))
4376 totphys = memst.dwTotalPhys / 1024.0;
4378 if (h_proc
4379 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
4380 sizeof (mem_ex)))
4382 DWORD rss = mem_ex.WorkingSetSize / 1024;
4384 attrs = Fcons (Fcons (Qmajflt,
4385 make_fixnum_or_float (mem_ex.PageFaultCount)),
4386 attrs);
4387 attrs = Fcons (Fcons (Qvsize,
4388 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
4389 attrs);
4390 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4391 if (totphys)
4392 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4394 else if (h_proc
4395 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
4397 DWORD rss = mem_ex.WorkingSetSize / 1024;
4399 attrs = Fcons (Fcons (Qmajflt,
4400 make_fixnum_or_float (mem.PageFaultCount)),
4401 attrs);
4402 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4403 if (totphys)
4404 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4406 else if (h_proc
4407 && get_process_working_set_size (h_proc, &minrss, &maxrss))
4409 DWORD rss = maxrss / 1024;
4411 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
4412 if (totphys)
4413 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4416 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
4418 attrs = Fcons (Fcons (Qutime, utime), attrs);
4419 attrs = Fcons (Fcons (Qstime, stime), attrs);
4420 attrs = Fcons (Fcons (Qtime, ttime), attrs);
4421 attrs = Fcons (Fcons (Qstart, ctime), attrs);
4422 attrs = Fcons (Fcons (Qetime, etime), attrs);
4423 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
4426 /* FIXME: Retrieve command line by walking the PEB of the process. */
4428 if (h_proc)
4429 CloseHandle (h_proc);
4430 UNGCPRO;
4431 return attrs;
4435 /* Wrappers for winsock functions to map between our file descriptors
4436 and winsock's handles; also set h_errno for convenience.
4438 To allow Emacs to run on systems which don't have winsock support
4439 installed, we dynamically link to winsock on startup if present, and
4440 otherwise provide the minimum necessary functionality
4441 (eg. gethostname). */
4443 /* function pointers for relevant socket functions */
4444 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
4445 void (PASCAL *pfn_WSASetLastError) (int iError);
4446 int (PASCAL *pfn_WSAGetLastError) (void);
4447 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
4448 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
4449 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
4450 int (PASCAL *pfn_socket) (int af, int type, int protocol);
4451 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
4452 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
4453 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
4454 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
4455 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
4456 int (PASCAL *pfn_closesocket) (SOCKET s);
4457 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
4458 int (PASCAL *pfn_WSACleanup) (void);
4460 u_short (PASCAL *pfn_htons) (u_short hostshort);
4461 u_short (PASCAL *pfn_ntohs) (u_short netshort);
4462 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
4463 int (PASCAL *pfn_gethostname) (char * name, int namelen);
4464 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
4465 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
4466 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
4467 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
4468 const char * optval, int optlen);
4469 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
4470 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
4471 int * namelen);
4472 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
4473 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
4474 struct sockaddr * from, int * fromlen);
4475 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
4476 const struct sockaddr * to, int tolen);
4478 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4479 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
4480 #ifndef HANDLE_FLAG_INHERIT
4481 #define HANDLE_FLAG_INHERIT 1
4482 #endif
4484 HANDLE winsock_lib;
4485 static int winsock_inuse;
4487 BOOL
4488 term_winsock (void)
4490 if (winsock_lib != NULL && winsock_inuse == 0)
4492 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4493 after WSAStartup returns successfully, but it seems reasonable
4494 to allow unloading winsock anyway in that case. */
4495 if (pfn_WSACleanup () == 0 ||
4496 pfn_WSAGetLastError () == WSAENETDOWN)
4498 if (FreeLibrary (winsock_lib))
4499 winsock_lib = NULL;
4500 return TRUE;
4503 return FALSE;
4506 BOOL
4507 init_winsock (int load_now)
4509 WSADATA winsockData;
4511 if (winsock_lib != NULL)
4512 return TRUE;
4514 pfn_SetHandleInformation
4515 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4516 "SetHandleInformation");
4518 winsock_lib = LoadLibrary ("Ws2_32.dll");
4520 if (winsock_lib != NULL)
4522 /* dynamically link to socket functions */
4524 #define LOAD_PROC(fn) \
4525 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4526 goto fail;
4528 LOAD_PROC (WSAStartup);
4529 LOAD_PROC (WSASetLastError);
4530 LOAD_PROC (WSAGetLastError);
4531 LOAD_PROC (WSAEventSelect);
4532 LOAD_PROC (WSACreateEvent);
4533 LOAD_PROC (WSACloseEvent);
4534 LOAD_PROC (socket);
4535 LOAD_PROC (bind);
4536 LOAD_PROC (connect);
4537 LOAD_PROC (ioctlsocket);
4538 LOAD_PROC (recv);
4539 LOAD_PROC (send);
4540 LOAD_PROC (closesocket);
4541 LOAD_PROC (shutdown);
4542 LOAD_PROC (htons);
4543 LOAD_PROC (ntohs);
4544 LOAD_PROC (inet_addr);
4545 LOAD_PROC (gethostname);
4546 LOAD_PROC (gethostbyname);
4547 LOAD_PROC (getservbyname);
4548 LOAD_PROC (getpeername);
4549 LOAD_PROC (WSACleanup);
4550 LOAD_PROC (setsockopt);
4551 LOAD_PROC (listen);
4552 LOAD_PROC (getsockname);
4553 LOAD_PROC (accept);
4554 LOAD_PROC (recvfrom);
4555 LOAD_PROC (sendto);
4556 #undef LOAD_PROC
4558 /* specify version 1.1 of winsock */
4559 if (pfn_WSAStartup (0x101, &winsockData) == 0)
4561 if (winsockData.wVersion != 0x101)
4562 goto fail;
4564 if (!load_now)
4566 /* Report that winsock exists and is usable, but leave
4567 socket functions disabled. I am assuming that calling
4568 WSAStartup does not require any network interaction,
4569 and in particular does not cause or require a dial-up
4570 connection to be established. */
4572 pfn_WSACleanup ();
4573 FreeLibrary (winsock_lib);
4574 winsock_lib = NULL;
4576 winsock_inuse = 0;
4577 return TRUE;
4580 fail:
4581 FreeLibrary (winsock_lib);
4582 winsock_lib = NULL;
4585 return FALSE;
4589 int h_errno = 0;
4591 /* function to set h_errno for compatibility; map winsock error codes to
4592 normal system codes where they overlap (non-overlapping definitions
4593 are already in <sys/socket.h> */
4594 static void
4595 set_errno (void)
4597 if (winsock_lib == NULL)
4598 h_errno = EINVAL;
4599 else
4600 h_errno = pfn_WSAGetLastError ();
4602 switch (h_errno)
4604 case WSAEACCES: h_errno = EACCES; break;
4605 case WSAEBADF: h_errno = EBADF; break;
4606 case WSAEFAULT: h_errno = EFAULT; break;
4607 case WSAEINTR: h_errno = EINTR; break;
4608 case WSAEINVAL: h_errno = EINVAL; break;
4609 case WSAEMFILE: h_errno = EMFILE; break;
4610 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
4611 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
4613 errno = h_errno;
4616 static void
4617 check_errno (void)
4619 if (h_errno == 0 && winsock_lib != NULL)
4620 pfn_WSASetLastError (0);
4623 /* Extend strerror to handle the winsock-specific error codes. */
4624 struct {
4625 int errnum;
4626 char * msg;
4627 } _wsa_errlist[] = {
4628 {WSAEINTR , "Interrupted function call"},
4629 {WSAEBADF , "Bad file descriptor"},
4630 {WSAEACCES , "Permission denied"},
4631 {WSAEFAULT , "Bad address"},
4632 {WSAEINVAL , "Invalid argument"},
4633 {WSAEMFILE , "Too many open files"},
4635 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
4636 {WSAEINPROGRESS , "Operation now in progress"},
4637 {WSAEALREADY , "Operation already in progress"},
4638 {WSAENOTSOCK , "Socket operation on non-socket"},
4639 {WSAEDESTADDRREQ , "Destination address required"},
4640 {WSAEMSGSIZE , "Message too long"},
4641 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
4642 {WSAENOPROTOOPT , "Bad protocol option"},
4643 {WSAEPROTONOSUPPORT , "Protocol not supported"},
4644 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
4645 {WSAEOPNOTSUPP , "Operation not supported"},
4646 {WSAEPFNOSUPPORT , "Protocol family not supported"},
4647 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
4648 {WSAEADDRINUSE , "Address already in use"},
4649 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
4650 {WSAENETDOWN , "Network is down"},
4651 {WSAENETUNREACH , "Network is unreachable"},
4652 {WSAENETRESET , "Network dropped connection on reset"},
4653 {WSAECONNABORTED , "Software caused connection abort"},
4654 {WSAECONNRESET , "Connection reset by peer"},
4655 {WSAENOBUFS , "No buffer space available"},
4656 {WSAEISCONN , "Socket is already connected"},
4657 {WSAENOTCONN , "Socket is not connected"},
4658 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
4659 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
4660 {WSAETIMEDOUT , "Connection timed out"},
4661 {WSAECONNREFUSED , "Connection refused"},
4662 {WSAELOOP , "Network loop"}, /* not sure */
4663 {WSAENAMETOOLONG , "Name is too long"},
4664 {WSAEHOSTDOWN , "Host is down"},
4665 {WSAEHOSTUNREACH , "No route to host"},
4666 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
4667 {WSAEPROCLIM , "Too many processes"},
4668 {WSAEUSERS , "Too many users"}, /* not sure */
4669 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
4670 {WSAESTALE , "Data is stale"}, /* not sure */
4671 {WSAEREMOTE , "Remote error"}, /* not sure */
4673 {WSASYSNOTREADY , "Network subsystem is unavailable"},
4674 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
4675 {WSANOTINITIALISED , "Winsock not initialized successfully"},
4676 {WSAEDISCON , "Graceful shutdown in progress"},
4677 #ifdef WSAENOMORE
4678 {WSAENOMORE , "No more operations allowed"}, /* not sure */
4679 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
4680 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
4681 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
4682 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
4683 {WSASYSCALLFAILURE , "System call failure"},
4684 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
4685 {WSATYPE_NOT_FOUND , "Class type not found"},
4686 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
4687 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
4688 {WSAEREFUSED , "Operation refused"}, /* not sure */
4689 #endif
4691 {WSAHOST_NOT_FOUND , "Host not found"},
4692 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
4693 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
4694 {WSANO_DATA , "Valid name, no data record of requested type"},
4696 {-1, NULL}
4699 char *
4700 sys_strerror (int error_no)
4702 int i;
4703 static char unknown_msg[40];
4705 if (error_no >= 0 && error_no < sys_nerr)
4706 return sys_errlist[error_no];
4708 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
4709 if (_wsa_errlist[i].errnum == error_no)
4710 return _wsa_errlist[i].msg;
4712 sprintf (unknown_msg, "Unidentified error: %d", error_no);
4713 return unknown_msg;
4716 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4717 but I believe the method of keeping the socket handle separate (and
4718 insuring it is not inheritable) is the correct one. */
4720 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4722 static int socket_to_fd (SOCKET s);
4725 sys_socket (int af, int type, int protocol)
4727 SOCKET s;
4729 if (winsock_lib == NULL)
4731 h_errno = ENETDOWN;
4732 return INVALID_SOCKET;
4735 check_errno ();
4737 /* call the real socket function */
4738 s = pfn_socket (af, type, protocol);
4740 if (s != INVALID_SOCKET)
4741 return socket_to_fd (s);
4743 set_errno ();
4744 return -1;
4747 /* Convert a SOCKET to a file descriptor. */
4748 static int
4749 socket_to_fd (SOCKET s)
4751 int fd;
4752 child_process * cp;
4754 /* Although under NT 3.5 _open_osfhandle will accept a socket
4755 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4756 that does not work under NT 3.1. However, we can get the same
4757 effect by using a backdoor function to replace an existing
4758 descriptor handle with the one we want. */
4760 /* allocate a file descriptor (with appropriate flags) */
4761 fd = _open ("NUL:", _O_RDWR);
4762 if (fd >= 0)
4764 /* Make a non-inheritable copy of the socket handle. Note
4765 that it is possible that sockets aren't actually kernel
4766 handles, which appears to be the case on Windows 9x when
4767 the MS Proxy winsock client is installed. */
4769 /* Apparently there is a bug in NT 3.51 with some service
4770 packs, which prevents using DuplicateHandle to make a
4771 socket handle non-inheritable (causes WSACleanup to
4772 hang). The work-around is to use SetHandleInformation
4773 instead if it is available and implemented. */
4774 if (pfn_SetHandleInformation)
4776 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
4778 else
4780 HANDLE parent = GetCurrentProcess ();
4781 HANDLE new_s = INVALID_HANDLE_VALUE;
4783 if (DuplicateHandle (parent,
4784 (HANDLE) s,
4785 parent,
4786 &new_s,
4788 FALSE,
4789 DUPLICATE_SAME_ACCESS))
4791 /* It is possible that DuplicateHandle succeeds even
4792 though the socket wasn't really a kernel handle,
4793 because a real handle has the same value. So
4794 test whether the new handle really is a socket. */
4795 long nonblocking = 0;
4796 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
4798 pfn_closesocket (s);
4799 s = (SOCKET) new_s;
4801 else
4803 CloseHandle (new_s);
4808 fd_info[fd].hnd = (HANDLE) s;
4810 /* set our own internal flags */
4811 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
4813 cp = new_child ();
4814 if (cp)
4816 cp->fd = fd;
4817 cp->status = STATUS_READ_ACKNOWLEDGED;
4819 /* attach child_process to fd_info */
4820 if (fd_info[ fd ].cp != NULL)
4822 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
4823 abort ();
4826 fd_info[ fd ].cp = cp;
4828 /* success! */
4829 winsock_inuse++; /* count open sockets */
4830 return fd;
4833 /* clean up */
4834 _close (fd);
4836 pfn_closesocket (s);
4837 h_errno = EMFILE;
4838 return -1;
4842 sys_bind (int s, const struct sockaddr * addr, int namelen)
4844 if (winsock_lib == NULL)
4846 h_errno = ENOTSOCK;
4847 return SOCKET_ERROR;
4850 check_errno ();
4851 if (fd_info[s].flags & FILE_SOCKET)
4853 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
4854 if (rc == SOCKET_ERROR)
4855 set_errno ();
4856 return rc;
4858 h_errno = ENOTSOCK;
4859 return SOCKET_ERROR;
4863 sys_connect (int s, const struct sockaddr * name, int namelen)
4865 if (winsock_lib == NULL)
4867 h_errno = ENOTSOCK;
4868 return SOCKET_ERROR;
4871 check_errno ();
4872 if (fd_info[s].flags & FILE_SOCKET)
4874 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
4875 if (rc == SOCKET_ERROR)
4876 set_errno ();
4877 return rc;
4879 h_errno = ENOTSOCK;
4880 return SOCKET_ERROR;
4883 u_short
4884 sys_htons (u_short hostshort)
4886 return (winsock_lib != NULL) ?
4887 pfn_htons (hostshort) : hostshort;
4890 u_short
4891 sys_ntohs (u_short netshort)
4893 return (winsock_lib != NULL) ?
4894 pfn_ntohs (netshort) : netshort;
4897 unsigned long
4898 sys_inet_addr (const char * cp)
4900 return (winsock_lib != NULL) ?
4901 pfn_inet_addr (cp) : INADDR_NONE;
4905 sys_gethostname (char * name, int namelen)
4907 if (winsock_lib != NULL)
4908 return pfn_gethostname (name, namelen);
4910 if (namelen > MAX_COMPUTERNAME_LENGTH)
4911 return !GetComputerName (name, (DWORD *)&namelen);
4913 h_errno = EFAULT;
4914 return SOCKET_ERROR;
4917 struct hostent *
4918 sys_gethostbyname (const char * name)
4920 struct hostent * host;
4922 if (winsock_lib == NULL)
4924 h_errno = ENETDOWN;
4925 return NULL;
4928 check_errno ();
4929 host = pfn_gethostbyname (name);
4930 if (!host)
4931 set_errno ();
4932 return host;
4935 struct servent *
4936 sys_getservbyname (const char * name, const char * proto)
4938 struct servent * serv;
4940 if (winsock_lib == NULL)
4942 h_errno = ENETDOWN;
4943 return NULL;
4946 check_errno ();
4947 serv = pfn_getservbyname (name, proto);
4948 if (!serv)
4949 set_errno ();
4950 return serv;
4954 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
4956 if (winsock_lib == NULL)
4958 h_errno = ENETDOWN;
4959 return SOCKET_ERROR;
4962 check_errno ();
4963 if (fd_info[s].flags & FILE_SOCKET)
4965 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
4966 if (rc == SOCKET_ERROR)
4967 set_errno ();
4968 return rc;
4970 h_errno = ENOTSOCK;
4971 return SOCKET_ERROR;
4975 sys_shutdown (int s, int how)
4977 if (winsock_lib == NULL)
4979 h_errno = ENETDOWN;
4980 return SOCKET_ERROR;
4983 check_errno ();
4984 if (fd_info[s].flags & FILE_SOCKET)
4986 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
4987 if (rc == SOCKET_ERROR)
4988 set_errno ();
4989 return rc;
4991 h_errno = ENOTSOCK;
4992 return SOCKET_ERROR;
4996 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
4998 if (winsock_lib == NULL)
5000 h_errno = ENETDOWN;
5001 return SOCKET_ERROR;
5004 check_errno ();
5005 if (fd_info[s].flags & FILE_SOCKET)
5007 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
5008 (const char *)optval, optlen);
5009 if (rc == SOCKET_ERROR)
5010 set_errno ();
5011 return rc;
5013 h_errno = ENOTSOCK;
5014 return SOCKET_ERROR;
5018 sys_listen (int s, int backlog)
5020 if (winsock_lib == NULL)
5022 h_errno = ENETDOWN;
5023 return SOCKET_ERROR;
5026 check_errno ();
5027 if (fd_info[s].flags & FILE_SOCKET)
5029 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
5030 if (rc == SOCKET_ERROR)
5031 set_errno ();
5032 else
5033 fd_info[s].flags |= FILE_LISTEN;
5034 return rc;
5036 h_errno = ENOTSOCK;
5037 return SOCKET_ERROR;
5041 sys_getsockname (int s, struct sockaddr * name, int * namelen)
5043 if (winsock_lib == NULL)
5045 h_errno = ENETDOWN;
5046 return SOCKET_ERROR;
5049 check_errno ();
5050 if (fd_info[s].flags & FILE_SOCKET)
5052 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
5053 if (rc == SOCKET_ERROR)
5054 set_errno ();
5055 return rc;
5057 h_errno = ENOTSOCK;
5058 return SOCKET_ERROR;
5062 sys_accept (int s, struct sockaddr * addr, int * addrlen)
5064 if (winsock_lib == NULL)
5066 h_errno = ENETDOWN;
5067 return -1;
5070 check_errno ();
5071 if (fd_info[s].flags & FILE_LISTEN)
5073 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
5074 int fd = -1;
5075 if (t == INVALID_SOCKET)
5076 set_errno ();
5077 else
5078 fd = socket_to_fd (t);
5080 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
5081 ResetEvent (fd_info[s].cp->char_avail);
5082 return fd;
5084 h_errno = ENOTSOCK;
5085 return -1;
5089 sys_recvfrom (int s, char * buf, int len, int flags,
5090 struct sockaddr * from, int * fromlen)
5092 if (winsock_lib == NULL)
5094 h_errno = ENETDOWN;
5095 return SOCKET_ERROR;
5098 check_errno ();
5099 if (fd_info[s].flags & FILE_SOCKET)
5101 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
5102 if (rc == SOCKET_ERROR)
5103 set_errno ();
5104 return rc;
5106 h_errno = ENOTSOCK;
5107 return SOCKET_ERROR;
5111 sys_sendto (int s, const char * buf, int len, int flags,
5112 const struct sockaddr * to, int tolen)
5114 if (winsock_lib == NULL)
5116 h_errno = ENETDOWN;
5117 return SOCKET_ERROR;
5120 check_errno ();
5121 if (fd_info[s].flags & FILE_SOCKET)
5123 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
5124 if (rc == SOCKET_ERROR)
5125 set_errno ();
5126 return rc;
5128 h_errno = ENOTSOCK;
5129 return SOCKET_ERROR;
5132 /* Windows does not have an fcntl function. Provide an implementation
5133 solely for making sockets non-blocking. */
5135 fcntl (int s, int cmd, int options)
5137 if (winsock_lib == NULL)
5139 h_errno = ENETDOWN;
5140 return -1;
5143 check_errno ();
5144 if (fd_info[s].flags & FILE_SOCKET)
5146 if (cmd == F_SETFL && options == O_NDELAY)
5148 unsigned long nblock = 1;
5149 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
5150 if (rc == SOCKET_ERROR)
5151 set_errno ();
5152 /* Keep track of the fact that we set this to non-blocking. */
5153 fd_info[s].flags |= FILE_NDELAY;
5154 return rc;
5156 else
5158 h_errno = EINVAL;
5159 return SOCKET_ERROR;
5162 h_errno = ENOTSOCK;
5163 return SOCKET_ERROR;
5167 /* Shadow main io functions: we need to handle pipes and sockets more
5168 intelligently, and implement non-blocking mode as well. */
5171 sys_close (int fd)
5173 int rc;
5175 if (fd < 0)
5177 errno = EBADF;
5178 return -1;
5181 if (fd < MAXDESC && fd_info[fd].cp)
5183 child_process * cp = fd_info[fd].cp;
5185 fd_info[fd].cp = NULL;
5187 if (CHILD_ACTIVE (cp))
5189 /* if last descriptor to active child_process then cleanup */
5190 int i;
5191 for (i = 0; i < MAXDESC; i++)
5193 if (i == fd)
5194 continue;
5195 if (fd_info[i].cp == cp)
5196 break;
5198 if (i == MAXDESC)
5200 if (fd_info[fd].flags & FILE_SOCKET)
5202 if (winsock_lib == NULL) abort ();
5204 pfn_shutdown (SOCK_HANDLE (fd), 2);
5205 rc = pfn_closesocket (SOCK_HANDLE (fd));
5207 winsock_inuse--; /* count open sockets */
5209 delete_child (cp);
5214 /* Note that sockets do not need special treatment here (at least on
5215 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5216 closesocket is equivalent to CloseHandle, which is to be expected
5217 because socket handles are fully fledged kernel handles. */
5218 rc = _close (fd);
5220 if (rc == 0 && fd < MAXDESC)
5221 fd_info[fd].flags = 0;
5223 return rc;
5227 sys_dup (int fd)
5229 int new_fd;
5231 new_fd = _dup (fd);
5232 if (new_fd >= 0 && new_fd < MAXDESC)
5234 /* duplicate our internal info as well */
5235 fd_info[new_fd] = fd_info[fd];
5237 return new_fd;
5241 sys_dup2 (int src, int dst)
5243 int rc;
5245 if (dst < 0 || dst >= MAXDESC)
5247 errno = EBADF;
5248 return -1;
5251 /* make sure we close the destination first if it's a pipe or socket */
5252 if (src != dst && fd_info[dst].flags != 0)
5253 sys_close (dst);
5255 rc = _dup2 (src, dst);
5256 if (rc == 0)
5258 /* duplicate our internal info as well */
5259 fd_info[dst] = fd_info[src];
5261 return rc;
5264 /* Unix pipe() has only one arg */
5266 sys_pipe (int * phandles)
5268 int rc;
5269 unsigned flags;
5271 /* make pipe handles non-inheritable; when we spawn a child, we
5272 replace the relevant handle with an inheritable one. Also put
5273 pipes into binary mode; we will do text mode translation ourselves
5274 if required. */
5275 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
5277 if (rc == 0)
5279 /* Protect against overflow, since Windows can open more handles than
5280 our fd_info array has room for. */
5281 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
5283 _close (phandles[0]);
5284 _close (phandles[1]);
5285 rc = -1;
5287 else
5289 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
5290 fd_info[phandles[0]].flags = flags;
5292 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
5293 fd_info[phandles[1]].flags = flags;
5297 return rc;
5300 /* Function to do blocking read of one byte, needed to implement
5301 select. It is only allowed on sockets and pipes. */
5303 _sys_read_ahead (int fd)
5305 child_process * cp;
5306 int rc;
5308 if (fd < 0 || fd >= MAXDESC)
5309 return STATUS_READ_ERROR;
5311 cp = fd_info[fd].cp;
5313 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5314 return STATUS_READ_ERROR;
5316 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
5317 || (fd_info[fd].flags & FILE_READ) == 0)
5319 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
5320 abort ();
5323 cp->status = STATUS_READ_IN_PROGRESS;
5325 if (fd_info[fd].flags & FILE_PIPE)
5327 rc = _read (fd, &cp->chr, sizeof (char));
5329 /* Give subprocess time to buffer some more output for us before
5330 reporting that input is available; we need this because Windows 95
5331 connects DOS programs to pipes by making the pipe appear to be
5332 the normal console stdout - as a result most DOS programs will
5333 write to stdout without buffering, ie. one character at a
5334 time. Even some W32 programs do this - "dir" in a command
5335 shell on NT is very slow if we don't do this. */
5336 if (rc > 0)
5338 int wait = w32_pipe_read_delay;
5340 if (wait > 0)
5341 Sleep (wait);
5342 else if (wait < 0)
5343 while (++wait <= 0)
5344 /* Yield remainder of our time slice, effectively giving a
5345 temporary priority boost to the child process. */
5346 Sleep (0);
5349 else if (fd_info[fd].flags & FILE_SERIAL)
5351 HANDLE hnd = fd_info[fd].hnd;
5352 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5353 COMMTIMEOUTS ct;
5355 /* Configure timeouts for blocking read. */
5356 if (!GetCommTimeouts (hnd, &ct))
5357 return STATUS_READ_ERROR;
5358 ct.ReadIntervalTimeout = 0;
5359 ct.ReadTotalTimeoutMultiplier = 0;
5360 ct.ReadTotalTimeoutConstant = 0;
5361 if (!SetCommTimeouts (hnd, &ct))
5362 return STATUS_READ_ERROR;
5364 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
5366 if (GetLastError () != ERROR_IO_PENDING)
5367 return STATUS_READ_ERROR;
5368 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5369 return STATUS_READ_ERROR;
5372 else if (fd_info[fd].flags & FILE_SOCKET)
5374 unsigned long nblock = 0;
5375 /* We always want this to block, so temporarily disable NDELAY. */
5376 if (fd_info[fd].flags & FILE_NDELAY)
5377 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5379 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
5381 if (fd_info[fd].flags & FILE_NDELAY)
5383 nblock = 1;
5384 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5388 if (rc == sizeof (char))
5389 cp->status = STATUS_READ_SUCCEEDED;
5390 else
5391 cp->status = STATUS_READ_FAILED;
5393 return cp->status;
5397 _sys_wait_accept (int fd)
5399 HANDLE hEv;
5400 child_process * cp;
5401 int rc;
5403 if (fd < 0 || fd >= MAXDESC)
5404 return STATUS_READ_ERROR;
5406 cp = fd_info[fd].cp;
5408 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5409 return STATUS_READ_ERROR;
5411 cp->status = STATUS_READ_FAILED;
5413 hEv = pfn_WSACreateEvent ();
5414 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
5415 if (rc != SOCKET_ERROR)
5417 rc = WaitForSingleObject (hEv, INFINITE);
5418 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
5419 if (rc == WAIT_OBJECT_0)
5420 cp->status = STATUS_READ_SUCCEEDED;
5422 pfn_WSACloseEvent (hEv);
5424 return cp->status;
5428 sys_read (int fd, char * buffer, unsigned int count)
5430 int nchars;
5431 int to_read;
5432 DWORD waiting;
5433 char * orig_buffer = buffer;
5435 if (fd < 0)
5437 errno = EBADF;
5438 return -1;
5441 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5443 child_process *cp = fd_info[fd].cp;
5445 if ((fd_info[fd].flags & FILE_READ) == 0)
5447 errno = EBADF;
5448 return -1;
5451 nchars = 0;
5453 /* re-read CR carried over from last read */
5454 if (fd_info[fd].flags & FILE_LAST_CR)
5456 if (fd_info[fd].flags & FILE_BINARY) abort ();
5457 *buffer++ = 0x0d;
5458 count--;
5459 nchars++;
5460 fd_info[fd].flags &= ~FILE_LAST_CR;
5463 /* presence of a child_process structure means we are operating in
5464 non-blocking mode - otherwise we just call _read directly.
5465 Note that the child_process structure might be missing because
5466 reap_subprocess has been called; in this case the pipe is
5467 already broken, so calling _read on it is okay. */
5468 if (cp)
5470 int current_status = cp->status;
5472 switch (current_status)
5474 case STATUS_READ_FAILED:
5475 case STATUS_READ_ERROR:
5476 /* report normal EOF if nothing in buffer */
5477 if (nchars <= 0)
5478 fd_info[fd].flags |= FILE_AT_EOF;
5479 return nchars;
5481 case STATUS_READ_READY:
5482 case STATUS_READ_IN_PROGRESS:
5483 DebPrint (("sys_read called when read is in progress\n"));
5484 errno = EWOULDBLOCK;
5485 return -1;
5487 case STATUS_READ_SUCCEEDED:
5488 /* consume read-ahead char */
5489 *buffer++ = cp->chr;
5490 count--;
5491 nchars++;
5492 cp->status = STATUS_READ_ACKNOWLEDGED;
5493 ResetEvent (cp->char_avail);
5495 case STATUS_READ_ACKNOWLEDGED:
5496 break;
5498 default:
5499 DebPrint (("sys_read: bad status %d\n", current_status));
5500 errno = EBADF;
5501 return -1;
5504 if (fd_info[fd].flags & FILE_PIPE)
5506 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
5507 to_read = min (waiting, (DWORD) count);
5509 if (to_read > 0)
5510 nchars += _read (fd, buffer, to_read);
5512 else if (fd_info[fd].flags & FILE_SERIAL)
5514 HANDLE hnd = fd_info[fd].hnd;
5515 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5516 int rc = 0;
5517 COMMTIMEOUTS ct;
5519 if (count > 0)
5521 /* Configure timeouts for non-blocking read. */
5522 if (!GetCommTimeouts (hnd, &ct))
5524 errno = EIO;
5525 return -1;
5527 ct.ReadIntervalTimeout = MAXDWORD;
5528 ct.ReadTotalTimeoutMultiplier = 0;
5529 ct.ReadTotalTimeoutConstant = 0;
5530 if (!SetCommTimeouts (hnd, &ct))
5532 errno = EIO;
5533 return -1;
5536 if (!ResetEvent (ovl->hEvent))
5538 errno = EIO;
5539 return -1;
5541 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
5543 if (GetLastError () != ERROR_IO_PENDING)
5545 errno = EIO;
5546 return -1;
5548 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5550 errno = EIO;
5551 return -1;
5554 nchars += rc;
5557 else /* FILE_SOCKET */
5559 if (winsock_lib == NULL) abort ();
5561 /* do the equivalent of a non-blocking read */
5562 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
5563 if (waiting == 0 && nchars == 0)
5565 h_errno = errno = EWOULDBLOCK;
5566 return -1;
5569 if (waiting)
5571 /* always use binary mode for sockets */
5572 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
5573 if (res == SOCKET_ERROR)
5575 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5576 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5577 set_errno ();
5578 return -1;
5580 nchars += res;
5584 else
5586 int nread = _read (fd, buffer, count);
5587 if (nread >= 0)
5588 nchars += nread;
5589 else if (nchars == 0)
5590 nchars = nread;
5593 if (nchars <= 0)
5594 fd_info[fd].flags |= FILE_AT_EOF;
5595 /* Perform text mode translation if required. */
5596 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
5598 nchars = crlf_to_lf (nchars, orig_buffer);
5599 /* If buffer contains only CR, return that. To be absolutely
5600 sure we should attempt to read the next char, but in
5601 practice a CR to be followed by LF would not appear by
5602 itself in the buffer. */
5603 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
5605 fd_info[fd].flags |= FILE_LAST_CR;
5606 nchars--;
5610 else
5611 nchars = _read (fd, buffer, count);
5613 return nchars;
5616 /* From w32xfns.c */
5617 extern HANDLE interrupt_handle;
5619 /* For now, don't bother with a non-blocking mode */
5621 sys_write (int fd, const void * buffer, unsigned int count)
5623 int nchars;
5625 if (fd < 0)
5627 errno = EBADF;
5628 return -1;
5631 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5633 if ((fd_info[fd].flags & FILE_WRITE) == 0)
5635 errno = EBADF;
5636 return -1;
5639 /* Perform text mode translation if required. */
5640 if ((fd_info[fd].flags & FILE_BINARY) == 0)
5642 char * tmpbuf = alloca (count * 2);
5643 unsigned char * src = (void *)buffer;
5644 unsigned char * dst = tmpbuf;
5645 int nbytes = count;
5647 while (1)
5649 unsigned char *next;
5650 /* copy next line or remaining bytes */
5651 next = _memccpy (dst, src, '\n', nbytes);
5652 if (next)
5654 /* copied one line ending with '\n' */
5655 int copied = next - dst;
5656 nbytes -= copied;
5657 src += copied;
5658 /* insert '\r' before '\n' */
5659 next[-1] = '\r';
5660 next[0] = '\n';
5661 dst = next + 1;
5662 count++;
5664 else
5665 /* copied remaining partial line -> now finished */
5666 break;
5668 buffer = tmpbuf;
5672 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
5674 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
5675 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
5676 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
5677 DWORD active = 0;
5679 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
5681 if (GetLastError () != ERROR_IO_PENDING)
5683 errno = EIO;
5684 return -1;
5686 if (detect_input_pending ())
5687 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
5688 QS_ALLINPUT);
5689 else
5690 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
5691 if (active == WAIT_OBJECT_0)
5692 { /* User pressed C-g, cancel write, then leave. Don't bother
5693 cleaning up as we may only get stuck in buggy drivers. */
5694 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
5695 CancelIo (hnd);
5696 errno = EIO;
5697 return -1;
5699 if (active == WAIT_OBJECT_0 + 1
5700 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
5702 errno = EIO;
5703 return -1;
5707 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
5709 unsigned long nblock = 0;
5710 if (winsock_lib == NULL) abort ();
5712 /* TODO: implement select() properly so non-blocking I/O works. */
5713 /* For now, make sure the write blocks. */
5714 if (fd_info[fd].flags & FILE_NDELAY)
5715 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5717 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
5719 /* Set the socket back to non-blocking if it was before,
5720 for other operations that support it. */
5721 if (fd_info[fd].flags & FILE_NDELAY)
5723 nblock = 1;
5724 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5727 if (nchars == SOCKET_ERROR)
5729 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5730 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5731 set_errno ();
5734 else
5736 /* Some networked filesystems don't like too large writes, so
5737 break them into smaller chunks. See the Comments section of
5738 the MSDN documentation of WriteFile for details behind the
5739 choice of the value of CHUNK below. See also the thread
5740 http://thread.gmane.org/gmane.comp.version-control.git/145294
5741 in the git mailing list. */
5742 const unsigned char *p = buffer;
5743 const unsigned chunk = 30 * 1024 * 1024;
5745 nchars = 0;
5746 while (count > 0)
5748 unsigned this_chunk = count < chunk ? count : chunk;
5749 int n = _write (fd, p, this_chunk);
5751 nchars += n;
5752 if (n < 0)
5754 nchars = n;
5755 break;
5757 else if (n < this_chunk)
5758 break;
5759 count -= n;
5760 p += n;
5764 return nchars;
5767 /* The Windows CRT functions are "optimized for speed", so they don't
5768 check for timezone and DST changes if they were last called less
5769 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
5770 all Emacs features that repeatedly call time functions (e.g.,
5771 display-time) are in real danger of missing timezone and DST
5772 changes. Calling tzset before each localtime call fixes that. */
5773 struct tm *
5774 sys_localtime (const time_t *t)
5776 tzset ();
5777 return localtime (t);
5782 /* Delayed loading of libraries. */
5784 Lisp_Object Vlibrary_cache;
5786 /* The argument LIBRARIES is an alist that associates a symbol
5787 LIBRARY_ID, identifying an external DLL library known to Emacs, to
5788 a list of filenames under which the library is usually found. In
5789 most cases, the argument passed as LIBRARIES is the variable
5790 `dynamic-library-alist', which is initialized to a list of common
5791 library names. If the function loads the library successfully, it
5792 returns the handle of the DLL, and records the filename in the
5793 property :loaded-from of LIBRARY_ID; it returns NULL if the library
5794 could not be found, or when it was already loaded (because the
5795 handle is not recorded anywhere, and so is lost after use). It
5796 would be trivial to save the handle too in :loaded-from, but
5797 currently there's no use case for it. */
5798 HMODULE
5799 w32_delayed_load (Lisp_Object libraries, Lisp_Object library_id)
5801 HMODULE library_dll = NULL;
5803 CHECK_SYMBOL (library_id);
5805 if (CONSP (libraries) && NILP (Fassq (library_id, Vlibrary_cache)))
5807 Lisp_Object found = Qnil;
5808 Lisp_Object dlls = Fassq (library_id, libraries);
5810 if (CONSP (dlls))
5811 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
5813 CHECK_STRING_CAR (dlls);
5814 if ((library_dll = LoadLibrary (SDATA (XCAR (dlls)))))
5816 found = XCAR (dlls);
5817 break;
5821 Fput (library_id, QCloaded_from, found);
5824 return library_dll;
5828 static void
5829 check_windows_init_file (void)
5831 /* A common indication that Emacs is not installed properly is when
5832 it cannot find the Windows installation file. If this file does
5833 not exist in the expected place, tell the user. */
5835 if (!noninteractive && !inhibit_window_system
5836 /* Vload_path is not yet initialized when we are loading
5837 loadup.el. */
5838 && NILP (Vpurify_flag))
5840 Lisp_Object objs[2];
5841 Lisp_Object full_load_path;
5842 Lisp_Object init_file;
5843 int fd;
5845 objs[0] = Vload_path;
5846 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5847 full_load_path = Fappend (2, objs);
5848 init_file = build_string ("term/w32-win");
5849 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
5850 if (fd < 0)
5852 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
5853 char *init_file_name = SDATA (init_file);
5854 char *load_path = SDATA (load_path_print);
5855 char *buffer = alloca (1024
5856 + strlen (init_file_name)
5857 + strlen (load_path));
5859 sprintf (buffer,
5860 "The Emacs Windows initialization file \"%s.el\" "
5861 "could not be found in your Emacs installation. "
5862 "Emacs checked the following directories for this file:\n"
5863 "\n%s\n\n"
5864 "When Emacs cannot find this file, it usually means that it "
5865 "was not installed properly, or its distribution file was "
5866 "not unpacked properly.\nSee the README.W32 file in the "
5867 "top-level Emacs directory for more information.",
5868 init_file_name, load_path);
5869 MessageBox (NULL,
5870 buffer,
5871 "Emacs Abort Dialog",
5872 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
5873 /* Use the low-level Emacs abort. */
5874 #undef abort
5875 abort ();
5877 else
5879 _close (fd);
5884 void
5885 term_ntproc (void)
5887 /* shutdown the socket interface if necessary */
5888 term_winsock ();
5890 term_w32select ();
5893 void
5894 init_ntproc (void)
5896 /* Initialize the socket interface now if available and requested by
5897 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5898 delayed until open-network-stream is called (w32-has-winsock can
5899 also be used to dynamically load or reload winsock).
5901 Conveniently, init_environment is called before us, so
5902 PRELOAD_WINSOCK can be set in the registry. */
5904 /* Always initialize this correctly. */
5905 winsock_lib = NULL;
5907 if (getenv ("PRELOAD_WINSOCK") != NULL)
5908 init_winsock (TRUE);
5910 /* Initial preparation for subprocess support: replace our standard
5911 handles with non-inheritable versions. */
5913 HANDLE parent;
5914 HANDLE stdin_save = INVALID_HANDLE_VALUE;
5915 HANDLE stdout_save = INVALID_HANDLE_VALUE;
5916 HANDLE stderr_save = INVALID_HANDLE_VALUE;
5918 parent = GetCurrentProcess ();
5920 /* ignore errors when duplicating and closing; typically the
5921 handles will be invalid when running as a gui program. */
5922 DuplicateHandle (parent,
5923 GetStdHandle (STD_INPUT_HANDLE),
5924 parent,
5925 &stdin_save,
5927 FALSE,
5928 DUPLICATE_SAME_ACCESS);
5930 DuplicateHandle (parent,
5931 GetStdHandle (STD_OUTPUT_HANDLE),
5932 parent,
5933 &stdout_save,
5935 FALSE,
5936 DUPLICATE_SAME_ACCESS);
5938 DuplicateHandle (parent,
5939 GetStdHandle (STD_ERROR_HANDLE),
5940 parent,
5941 &stderr_save,
5943 FALSE,
5944 DUPLICATE_SAME_ACCESS);
5946 fclose (stdin);
5947 fclose (stdout);
5948 fclose (stderr);
5950 if (stdin_save != INVALID_HANDLE_VALUE)
5951 _open_osfhandle ((long) stdin_save, O_TEXT);
5952 else
5953 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
5954 _fdopen (0, "r");
5956 if (stdout_save != INVALID_HANDLE_VALUE)
5957 _open_osfhandle ((long) stdout_save, O_TEXT);
5958 else
5959 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5960 _fdopen (1, "w");
5962 if (stderr_save != INVALID_HANDLE_VALUE)
5963 _open_osfhandle ((long) stderr_save, O_TEXT);
5964 else
5965 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5966 _fdopen (2, "w");
5969 /* unfortunately, atexit depends on implementation of malloc */
5970 /* atexit (term_ntproc); */
5971 signal (SIGABRT, term_ntproc);
5973 /* determine which drives are fixed, for GetCachedVolumeInformation */
5975 /* GetDriveType must have trailing backslash. */
5976 char drive[] = "A:\\";
5978 /* Loop over all possible drive letters */
5979 while (*drive <= 'Z')
5981 /* Record if this drive letter refers to a fixed drive. */
5982 fixed_drives[DRIVE_INDEX (*drive)] =
5983 (GetDriveType (drive) == DRIVE_FIXED);
5985 (*drive)++;
5988 /* Reset the volume info cache. */
5989 volume_cache = NULL;
5992 /* Check to see if Emacs has been installed correctly. */
5993 check_windows_init_file ();
5997 shutdown_handler ensures that buffers' autosave files are
5998 up to date when the user logs off, or the system shuts down.
6000 static BOOL WINAPI
6001 shutdown_handler (DWORD type)
6003 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
6004 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
6005 || type == CTRL_LOGOFF_EVENT /* User logs off. */
6006 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
6008 /* Shut down cleanly, making sure autosave files are up to date. */
6009 shut_down_emacs (0, 0, Qnil);
6012 /* Allow other handlers to handle this signal. */
6013 return FALSE;
6017 globals_of_w32 is used to initialize those global variables that
6018 must always be initialized on startup even when the global variable
6019 initialized is non zero (see the function main in emacs.c).
6021 void
6022 globals_of_w32 (void)
6024 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
6026 get_process_times_fn = (GetProcessTimes_Proc)
6027 GetProcAddress (kernel32, "GetProcessTimes");
6029 DEFSYM (QCloaded_from, ":loaded-from");
6031 Vlibrary_cache = Qnil;
6032 staticpro (&Vlibrary_cache);
6034 g_b_init_is_windows_9x = 0;
6035 g_b_init_open_process_token = 0;
6036 g_b_init_get_token_information = 0;
6037 g_b_init_lookup_account_sid = 0;
6038 g_b_init_get_sid_sub_authority = 0;
6039 g_b_init_get_sid_sub_authority_count = 0;
6040 g_b_init_get_file_security = 0;
6041 g_b_init_get_security_descriptor_owner = 0;
6042 g_b_init_get_security_descriptor_group = 0;
6043 g_b_init_is_valid_sid = 0;
6044 g_b_init_create_toolhelp32_snapshot = 0;
6045 g_b_init_process32_first = 0;
6046 g_b_init_process32_next = 0;
6047 g_b_init_open_thread_token = 0;
6048 g_b_init_impersonate_self = 0;
6049 g_b_init_revert_to_self = 0;
6050 g_b_init_get_process_memory_info = 0;
6051 g_b_init_get_process_working_set_size = 0;
6052 g_b_init_global_memory_status = 0;
6053 g_b_init_global_memory_status_ex = 0;
6054 g_b_init_equal_sid = 0;
6055 g_b_init_copy_sid = 0;
6056 g_b_init_get_length_sid = 0;
6057 g_b_init_get_native_system_info = 0;
6058 g_b_init_get_system_times = 0;
6059 num_of_processors = 0;
6060 /* The following sets a handler for shutdown notifications for
6061 console apps. This actually applies to Emacs in both console and
6062 GUI modes, since we had to fool windows into thinking emacs is a
6063 console application to get console mode to work. */
6064 SetConsoleCtrlHandler (shutdown_handler, TRUE);
6066 /* "None" is the default group name on standalone workstations. */
6067 strcpy (dflt_group_name, "None");
6070 /* For make-serial-process */
6072 serial_open (char *port)
6074 HANDLE hnd;
6075 child_process *cp;
6076 int fd = -1;
6078 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
6079 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
6080 if (hnd == INVALID_HANDLE_VALUE)
6081 error ("Could not open %s", port);
6082 fd = (int) _open_osfhandle ((int) hnd, 0);
6083 if (fd == -1)
6084 error ("Could not open %s", port);
6086 cp = new_child ();
6087 if (!cp)
6088 error ("Could not create child process");
6089 cp->fd = fd;
6090 cp->status = STATUS_READ_ACKNOWLEDGED;
6091 fd_info[ fd ].hnd = hnd;
6092 fd_info[ fd ].flags |=
6093 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
6094 if (fd_info[ fd ].cp != NULL)
6096 error ("fd_info[fd = %d] is already in use", fd);
6098 fd_info[ fd ].cp = cp;
6099 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
6100 if (cp->ovl_read.hEvent == NULL)
6101 error ("Could not create read event");
6102 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
6103 if (cp->ovl_write.hEvent == NULL)
6104 error ("Could not create write event");
6106 return fd;
6109 /* For serial-process-configure */
6110 void
6111 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
6113 Lisp_Object childp2 = Qnil;
6114 Lisp_Object tem = Qnil;
6115 HANDLE hnd;
6116 DCB dcb;
6117 COMMTIMEOUTS ct;
6118 char summary[4] = "???"; /* This usually becomes "8N1". */
6120 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
6121 error ("Not a serial process");
6122 hnd = fd_info[ p->outfd ].hnd;
6124 childp2 = Fcopy_sequence (p->childp);
6126 /* Initialize timeouts for blocking read and blocking write. */
6127 if (!GetCommTimeouts (hnd, &ct))
6128 error ("GetCommTimeouts() failed");
6129 ct.ReadIntervalTimeout = 0;
6130 ct.ReadTotalTimeoutMultiplier = 0;
6131 ct.ReadTotalTimeoutConstant = 0;
6132 ct.WriteTotalTimeoutMultiplier = 0;
6133 ct.WriteTotalTimeoutConstant = 0;
6134 if (!SetCommTimeouts (hnd, &ct))
6135 error ("SetCommTimeouts() failed");
6136 /* Read port attributes and prepare default configuration. */
6137 memset (&dcb, 0, sizeof (dcb));
6138 dcb.DCBlength = sizeof (DCB);
6139 if (!GetCommState (hnd, &dcb))
6140 error ("GetCommState() failed");
6141 dcb.fBinary = TRUE;
6142 dcb.fNull = FALSE;
6143 dcb.fAbortOnError = FALSE;
6144 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6145 dcb.ErrorChar = 0;
6146 dcb.EofChar = 0;
6147 dcb.EvtChar = 0;
6149 /* Configure speed. */
6150 if (!NILP (Fplist_member (contact, QCspeed)))
6151 tem = Fplist_get (contact, QCspeed);
6152 else
6153 tem = Fplist_get (p->childp, QCspeed);
6154 CHECK_NUMBER (tem);
6155 dcb.BaudRate = XINT (tem);
6156 childp2 = Fplist_put (childp2, QCspeed, tem);
6158 /* Configure bytesize. */
6159 if (!NILP (Fplist_member (contact, QCbytesize)))
6160 tem = Fplist_get (contact, QCbytesize);
6161 else
6162 tem = Fplist_get (p->childp, QCbytesize);
6163 if (NILP (tem))
6164 tem = make_number (8);
6165 CHECK_NUMBER (tem);
6166 if (XINT (tem) != 7 && XINT (tem) != 8)
6167 error (":bytesize must be nil (8), 7, or 8");
6168 dcb.ByteSize = XINT (tem);
6169 summary[0] = XINT (tem) + '0';
6170 childp2 = Fplist_put (childp2, QCbytesize, tem);
6172 /* Configure parity. */
6173 if (!NILP (Fplist_member (contact, QCparity)))
6174 tem = Fplist_get (contact, QCparity);
6175 else
6176 tem = Fplist_get (p->childp, QCparity);
6177 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
6178 error (":parity must be nil (no parity), `even', or `odd'");
6179 dcb.fParity = FALSE;
6180 dcb.Parity = NOPARITY;
6181 dcb.fErrorChar = FALSE;
6182 if (NILP (tem))
6184 summary[1] = 'N';
6186 else if (EQ (tem, Qeven))
6188 summary[1] = 'E';
6189 dcb.fParity = TRUE;
6190 dcb.Parity = EVENPARITY;
6191 dcb.fErrorChar = TRUE;
6193 else if (EQ (tem, Qodd))
6195 summary[1] = 'O';
6196 dcb.fParity = TRUE;
6197 dcb.Parity = ODDPARITY;
6198 dcb.fErrorChar = TRUE;
6200 childp2 = Fplist_put (childp2, QCparity, tem);
6202 /* Configure stopbits. */
6203 if (!NILP (Fplist_member (contact, QCstopbits)))
6204 tem = Fplist_get (contact, QCstopbits);
6205 else
6206 tem = Fplist_get (p->childp, QCstopbits);
6207 if (NILP (tem))
6208 tem = make_number (1);
6209 CHECK_NUMBER (tem);
6210 if (XINT (tem) != 1 && XINT (tem) != 2)
6211 error (":stopbits must be nil (1 stopbit), 1, or 2");
6212 summary[2] = XINT (tem) + '0';
6213 if (XINT (tem) == 1)
6214 dcb.StopBits = ONESTOPBIT;
6215 else if (XINT (tem) == 2)
6216 dcb.StopBits = TWOSTOPBITS;
6217 childp2 = Fplist_put (childp2, QCstopbits, tem);
6219 /* Configure flowcontrol. */
6220 if (!NILP (Fplist_member (contact, QCflowcontrol)))
6221 tem = Fplist_get (contact, QCflowcontrol);
6222 else
6223 tem = Fplist_get (p->childp, QCflowcontrol);
6224 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
6225 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6226 dcb.fOutxCtsFlow = FALSE;
6227 dcb.fOutxDsrFlow = FALSE;
6228 dcb.fDtrControl = DTR_CONTROL_DISABLE;
6229 dcb.fDsrSensitivity = FALSE;
6230 dcb.fTXContinueOnXoff = FALSE;
6231 dcb.fOutX = FALSE;
6232 dcb.fInX = FALSE;
6233 dcb.fRtsControl = RTS_CONTROL_DISABLE;
6234 dcb.XonChar = 17; /* Control-Q */
6235 dcb.XoffChar = 19; /* Control-S */
6236 if (NILP (tem))
6238 /* Already configured. */
6240 else if (EQ (tem, Qhw))
6242 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
6243 dcb.fOutxCtsFlow = TRUE;
6245 else if (EQ (tem, Qsw))
6247 dcb.fOutX = TRUE;
6248 dcb.fInX = TRUE;
6250 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
6252 /* Activate configuration. */
6253 if (!SetCommState (hnd, &dcb))
6254 error ("SetCommState() failed");
6256 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
6257 p->childp = childp2;
6260 #ifdef HAVE_GNUTLS
6262 ssize_t
6263 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
6265 int n, sc, err;
6266 SELECT_TYPE fdset;
6267 EMACS_TIME timeout;
6268 struct Lisp_Process *process = (struct Lisp_Process *)p;
6269 int fd = process->infd;
6271 for (;;)
6273 n = sys_read (fd, (char*)buf, sz);
6275 if (n >= 0)
6276 return n;
6278 err = errno;
6280 if (err == EWOULDBLOCK)
6282 /* Set a small timeout. */
6283 EMACS_SET_SECS_USECS (timeout, 1, 0);
6284 FD_ZERO (&fdset);
6285 FD_SET ((int)fd, &fdset);
6287 /* Use select with the timeout to poll the selector. */
6288 sc = select (fd + 1, &fdset, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
6289 &timeout);
6291 if (sc > 0)
6292 continue; /* Try again. */
6294 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
6295 Also accept select return 0 as an indicator to EAGAIN. */
6296 if (sc == 0 || errno == EWOULDBLOCK)
6297 err = EAGAIN;
6298 else
6299 err = errno; /* Other errors are just passed on. */
6302 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
6304 return -1;
6308 ssize_t
6309 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
6311 struct Lisp_Process *process = (struct Lisp_Process *)p;
6312 int fd = process->outfd;
6313 ssize_t n = sys_write (fd, buf, sz);
6315 /* 0 or more bytes written means everything went fine. */
6316 if (n >= 0)
6317 return n;
6319 /* Negative bytes written means we got an error in errno.
6320 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
6321 emacs_gnutls_transport_set_errno (process->gnutls_state,
6322 errno == EWOULDBLOCK ? EAGAIN : errno);
6324 return -1;
6326 #endif /* HAVE_GNUTLS */
6328 /* end of w32.c */