src/w32.c (init_environment): Warn about defaulting HOME to C:\.
[emacs.git] / src / w32.c
blob230ccc8de1017908a1d8d9ab8d25a709995d9c4a
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994-1995, 2000-2011 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 #include <w32api.h>
98 #if !defined(__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
99 /* This either is not in psapi.h or guarded by higher value of
100 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
101 defines it in psapi.h */
102 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
103 DWORD cb;
104 DWORD PageFaultCount;
105 DWORD PeakWorkingSetSize;
106 DWORD WorkingSetSize;
107 DWORD QuotaPeakPagedPoolUsage;
108 DWORD QuotaPagedPoolUsage;
109 DWORD QuotaPeakNonPagedPoolUsage;
110 DWORD QuotaNonPagedPoolUsage;
111 DWORD PagefileUsage;
112 DWORD PeakPagefileUsage;
113 DWORD PrivateUsage;
114 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
115 #endif
117 /* TCP connection support. */
118 #include <sys/socket.h>
119 #undef socket
120 #undef bind
121 #undef connect
122 #undef htons
123 #undef ntohs
124 #undef inet_addr
125 #undef gethostname
126 #undef gethostbyname
127 #undef getservbyname
128 #undef getpeername
129 #undef shutdown
130 #undef setsockopt
131 #undef listen
132 #undef getsockname
133 #undef accept
134 #undef recvfrom
135 #undef sendto
137 #include "w32.h"
138 #include "ndir.h"
139 #include "w32heap.h"
140 #include "systime.h"
141 #include "dispextern.h" /* for xstrcasecmp */
142 #include "coding.h" /* for Vlocale_coding_system */
144 #include "careadlinkat.h"
145 #include "allocator.h"
147 /* For serial_configure and serial_open. */
148 #include "process.h"
150 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
151 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
153 void globals_of_w32 (void);
154 static DWORD get_rid (PSID);
157 /* Initialization states.
159 WARNING: If you add any more such variables for additional APIs,
160 you MUST add initialization for them to globals_of_w32
161 below. This is because these variables might get set
162 to non-NULL values during dumping, but the dumped Emacs
163 cannot reuse those values, because it could be run on a
164 different version of the OS, where API addresses are
165 different. */
166 static BOOL g_b_init_is_windows_9x;
167 static BOOL g_b_init_open_process_token;
168 static BOOL g_b_init_get_token_information;
169 static BOOL g_b_init_lookup_account_sid;
170 static BOOL g_b_init_get_sid_sub_authority;
171 static BOOL g_b_init_get_sid_sub_authority_count;
172 static BOOL g_b_init_get_file_security;
173 static BOOL g_b_init_get_security_descriptor_owner;
174 static BOOL g_b_init_get_security_descriptor_group;
175 static BOOL g_b_init_is_valid_sid;
176 static BOOL g_b_init_create_toolhelp32_snapshot;
177 static BOOL g_b_init_process32_first;
178 static BOOL g_b_init_process32_next;
179 static BOOL g_b_init_open_thread_token;
180 static BOOL g_b_init_impersonate_self;
181 static BOOL g_b_init_revert_to_self;
182 static BOOL g_b_init_get_process_memory_info;
183 static BOOL g_b_init_get_process_working_set_size;
184 static BOOL g_b_init_global_memory_status;
185 static BOOL g_b_init_global_memory_status_ex;
186 static BOOL g_b_init_get_length_sid;
187 static BOOL g_b_init_equal_sid;
188 static BOOL g_b_init_copy_sid;
189 static BOOL g_b_init_get_native_system_info;
190 static BOOL g_b_init_get_system_times;
193 BEGIN: Wrapper functions around OpenProcessToken
194 and other functions in advapi32.dll that are only
195 supported in Windows NT / 2k / XP
197 /* ** Function pointer typedefs ** */
198 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
199 HANDLE ProcessHandle,
200 DWORD DesiredAccess,
201 PHANDLE TokenHandle);
202 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
203 HANDLE TokenHandle,
204 TOKEN_INFORMATION_CLASS TokenInformationClass,
205 LPVOID TokenInformation,
206 DWORD TokenInformationLength,
207 PDWORD ReturnLength);
208 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
209 HANDLE process_handle,
210 LPFILETIME creation_time,
211 LPFILETIME exit_time,
212 LPFILETIME kernel_time,
213 LPFILETIME user_time);
215 GetProcessTimes_Proc get_process_times_fn = NULL;
217 #ifdef _UNICODE
218 const char * const LookupAccountSid_Name = "LookupAccountSidW";
219 const char * const GetFileSecurity_Name = "GetFileSecurityW";
220 #else
221 const char * const LookupAccountSid_Name = "LookupAccountSidA";
222 const char * const GetFileSecurity_Name = "GetFileSecurityA";
223 #endif
224 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
225 LPCTSTR lpSystemName,
226 PSID Sid,
227 LPTSTR Name,
228 LPDWORD cbName,
229 LPTSTR DomainName,
230 LPDWORD cbDomainName,
231 PSID_NAME_USE peUse);
232 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
233 PSID pSid,
234 DWORD n);
235 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
236 PSID pSid);
237 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
238 LPCTSTR lpFileName,
239 SECURITY_INFORMATION RequestedInformation,
240 PSECURITY_DESCRIPTOR pSecurityDescriptor,
241 DWORD nLength,
242 LPDWORD lpnLengthNeeded);
243 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
244 PSECURITY_DESCRIPTOR pSecurityDescriptor,
245 PSID *pOwner,
246 LPBOOL lpbOwnerDefaulted);
247 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
248 PSECURITY_DESCRIPTOR pSecurityDescriptor,
249 PSID *pGroup,
250 LPBOOL lpbGroupDefaulted);
251 typedef BOOL (WINAPI * IsValidSid_Proc) (
252 PSID sid);
253 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
254 DWORD dwFlags,
255 DWORD th32ProcessID);
256 typedef BOOL (WINAPI * Process32First_Proc) (
257 HANDLE hSnapshot,
258 LPPROCESSENTRY32 lppe);
259 typedef BOOL (WINAPI * Process32Next_Proc) (
260 HANDLE hSnapshot,
261 LPPROCESSENTRY32 lppe);
262 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
263 HANDLE ThreadHandle,
264 DWORD DesiredAccess,
265 BOOL OpenAsSelf,
266 PHANDLE TokenHandle);
267 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
268 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
269 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
270 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
271 HANDLE Process,
272 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
273 DWORD cb);
274 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
275 HANDLE hProcess,
276 DWORD * lpMinimumWorkingSetSize,
277 DWORD * lpMaximumWorkingSetSize);
278 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
279 LPMEMORYSTATUS lpBuffer);
280 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
281 LPMEMORY_STATUS_EX lpBuffer);
282 typedef BOOL (WINAPI * CopySid_Proc) (
283 DWORD nDestinationSidLength,
284 PSID pDestinationSid,
285 PSID pSourceSid);
286 typedef BOOL (WINAPI * EqualSid_Proc) (
287 PSID pSid1,
288 PSID pSid2);
289 typedef DWORD (WINAPI * GetLengthSid_Proc) (
290 PSID pSid);
291 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
292 LPSYSTEM_INFO lpSystemInfo);
293 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
294 LPFILETIME lpIdleTime,
295 LPFILETIME lpKernelTime,
296 LPFILETIME lpUserTime);
298 /* ** A utility function ** */
299 static BOOL
300 is_windows_9x (void)
302 static BOOL s_b_ret = 0;
303 OSVERSIONINFO os_ver;
304 if (g_b_init_is_windows_9x == 0)
306 g_b_init_is_windows_9x = 1;
307 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
308 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
309 if (GetVersionEx (&os_ver))
311 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
314 return s_b_ret;
317 /* Get total user and system times for get-internal-run-time.
318 Returns a list of three integers if the times are provided by the OS
319 (NT derivatives), otherwise it returns the result of current-time. */
320 Lisp_Object
321 w32_get_internal_run_time (void)
323 if (get_process_times_fn)
325 FILETIME create, exit, kernel, user;
326 HANDLE proc = GetCurrentProcess ();
327 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
329 LARGE_INTEGER user_int, kernel_int, total;
330 int microseconds;
331 user_int.LowPart = user.dwLowDateTime;
332 user_int.HighPart = user.dwHighDateTime;
333 kernel_int.LowPart = kernel.dwLowDateTime;
334 kernel_int.HighPart = kernel.dwHighDateTime;
335 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
336 /* FILETIME is 100 nanosecond increments, Emacs only wants
337 microsecond resolution. */
338 total.QuadPart /= 10;
339 microseconds = total.QuadPart % 1000000;
340 total.QuadPart /= 1000000;
342 /* Sanity check to make sure we can represent the result. */
343 if (total.HighPart == 0)
345 int secs = total.LowPart;
347 return list3 (make_number ((secs >> 16) & 0xffff),
348 make_number (secs & 0xffff),
349 make_number (microseconds));
354 return Fcurrent_time ();
357 /* ** The wrapper functions ** */
359 static BOOL WINAPI
360 open_process_token (HANDLE ProcessHandle,
361 DWORD DesiredAccess,
362 PHANDLE TokenHandle)
364 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
365 HMODULE hm_advapi32 = NULL;
366 if (is_windows_9x () == TRUE)
368 return FALSE;
370 if (g_b_init_open_process_token == 0)
372 g_b_init_open_process_token = 1;
373 hm_advapi32 = LoadLibrary ("Advapi32.dll");
374 s_pfn_Open_Process_Token =
375 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
377 if (s_pfn_Open_Process_Token == NULL)
379 return FALSE;
381 return (
382 s_pfn_Open_Process_Token (
383 ProcessHandle,
384 DesiredAccess,
385 TokenHandle)
389 static BOOL WINAPI
390 get_token_information (HANDLE TokenHandle,
391 TOKEN_INFORMATION_CLASS TokenInformationClass,
392 LPVOID TokenInformation,
393 DWORD TokenInformationLength,
394 PDWORD ReturnLength)
396 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
397 HMODULE hm_advapi32 = NULL;
398 if (is_windows_9x () == TRUE)
400 return FALSE;
402 if (g_b_init_get_token_information == 0)
404 g_b_init_get_token_information = 1;
405 hm_advapi32 = LoadLibrary ("Advapi32.dll");
406 s_pfn_Get_Token_Information =
407 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
409 if (s_pfn_Get_Token_Information == NULL)
411 return FALSE;
413 return (
414 s_pfn_Get_Token_Information (
415 TokenHandle,
416 TokenInformationClass,
417 TokenInformation,
418 TokenInformationLength,
419 ReturnLength)
423 static BOOL WINAPI
424 lookup_account_sid (LPCTSTR lpSystemName,
425 PSID Sid,
426 LPTSTR Name,
427 LPDWORD cbName,
428 LPTSTR DomainName,
429 LPDWORD cbDomainName,
430 PSID_NAME_USE peUse)
432 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
433 HMODULE hm_advapi32 = NULL;
434 if (is_windows_9x () == TRUE)
436 return FALSE;
438 if (g_b_init_lookup_account_sid == 0)
440 g_b_init_lookup_account_sid = 1;
441 hm_advapi32 = LoadLibrary ("Advapi32.dll");
442 s_pfn_Lookup_Account_Sid =
443 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
445 if (s_pfn_Lookup_Account_Sid == NULL)
447 return FALSE;
449 return (
450 s_pfn_Lookup_Account_Sid (
451 lpSystemName,
452 Sid,
453 Name,
454 cbName,
455 DomainName,
456 cbDomainName,
457 peUse)
461 static PDWORD WINAPI
462 get_sid_sub_authority (PSID pSid, DWORD n)
464 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
465 static DWORD zero = 0U;
466 HMODULE hm_advapi32 = NULL;
467 if (is_windows_9x () == TRUE)
469 return &zero;
471 if (g_b_init_get_sid_sub_authority == 0)
473 g_b_init_get_sid_sub_authority = 1;
474 hm_advapi32 = LoadLibrary ("Advapi32.dll");
475 s_pfn_Get_Sid_Sub_Authority =
476 (GetSidSubAuthority_Proc) GetProcAddress (
477 hm_advapi32, "GetSidSubAuthority");
479 if (s_pfn_Get_Sid_Sub_Authority == NULL)
481 return &zero;
483 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
486 static PUCHAR WINAPI
487 get_sid_sub_authority_count (PSID pSid)
489 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
490 static UCHAR zero = 0U;
491 HMODULE hm_advapi32 = NULL;
492 if (is_windows_9x () == TRUE)
494 return &zero;
496 if (g_b_init_get_sid_sub_authority_count == 0)
498 g_b_init_get_sid_sub_authority_count = 1;
499 hm_advapi32 = LoadLibrary ("Advapi32.dll");
500 s_pfn_Get_Sid_Sub_Authority_Count =
501 (GetSidSubAuthorityCount_Proc) GetProcAddress (
502 hm_advapi32, "GetSidSubAuthorityCount");
504 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
506 return &zero;
508 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
511 static BOOL WINAPI
512 get_file_security (LPCTSTR lpFileName,
513 SECURITY_INFORMATION RequestedInformation,
514 PSECURITY_DESCRIPTOR pSecurityDescriptor,
515 DWORD nLength,
516 LPDWORD lpnLengthNeeded)
518 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
519 HMODULE hm_advapi32 = NULL;
520 if (is_windows_9x () == TRUE)
522 return FALSE;
524 if (g_b_init_get_file_security == 0)
526 g_b_init_get_file_security = 1;
527 hm_advapi32 = LoadLibrary ("Advapi32.dll");
528 s_pfn_Get_File_Security =
529 (GetFileSecurity_Proc) GetProcAddress (
530 hm_advapi32, GetFileSecurity_Name);
532 if (s_pfn_Get_File_Security == NULL)
534 return FALSE;
536 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
537 pSecurityDescriptor, nLength,
538 lpnLengthNeeded));
541 static BOOL WINAPI
542 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
543 PSID *pOwner,
544 LPBOOL lpbOwnerDefaulted)
546 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
547 HMODULE hm_advapi32 = NULL;
548 if (is_windows_9x () == TRUE)
550 return FALSE;
552 if (g_b_init_get_security_descriptor_owner == 0)
554 g_b_init_get_security_descriptor_owner = 1;
555 hm_advapi32 = LoadLibrary ("Advapi32.dll");
556 s_pfn_Get_Security_Descriptor_Owner =
557 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
558 hm_advapi32, "GetSecurityDescriptorOwner");
560 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
562 return FALSE;
564 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
565 lpbOwnerDefaulted));
568 static BOOL WINAPI
569 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
570 PSID *pGroup,
571 LPBOOL lpbGroupDefaulted)
573 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
574 HMODULE hm_advapi32 = NULL;
575 if (is_windows_9x () == TRUE)
577 return FALSE;
579 if (g_b_init_get_security_descriptor_group == 0)
581 g_b_init_get_security_descriptor_group = 1;
582 hm_advapi32 = LoadLibrary ("Advapi32.dll");
583 s_pfn_Get_Security_Descriptor_Group =
584 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
585 hm_advapi32, "GetSecurityDescriptorGroup");
587 if (s_pfn_Get_Security_Descriptor_Group == NULL)
589 return FALSE;
591 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
592 lpbGroupDefaulted));
595 static BOOL WINAPI
596 is_valid_sid (PSID sid)
598 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
599 HMODULE hm_advapi32 = NULL;
600 if (is_windows_9x () == TRUE)
602 return FALSE;
604 if (g_b_init_is_valid_sid == 0)
606 g_b_init_is_valid_sid = 1;
607 hm_advapi32 = LoadLibrary ("Advapi32.dll");
608 s_pfn_Is_Valid_Sid =
609 (IsValidSid_Proc) GetProcAddress (
610 hm_advapi32, "IsValidSid");
612 if (s_pfn_Is_Valid_Sid == NULL)
614 return FALSE;
616 return (s_pfn_Is_Valid_Sid (sid));
619 static BOOL WINAPI
620 equal_sid (PSID sid1, PSID sid2)
622 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
623 HMODULE hm_advapi32 = NULL;
624 if (is_windows_9x () == TRUE)
626 return FALSE;
628 if (g_b_init_equal_sid == 0)
630 g_b_init_equal_sid = 1;
631 hm_advapi32 = LoadLibrary ("Advapi32.dll");
632 s_pfn_Equal_Sid =
633 (EqualSid_Proc) GetProcAddress (
634 hm_advapi32, "EqualSid");
636 if (s_pfn_Equal_Sid == NULL)
638 return FALSE;
640 return (s_pfn_Equal_Sid (sid1, sid2));
643 static DWORD WINAPI
644 get_length_sid (PSID sid)
646 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
647 HMODULE hm_advapi32 = NULL;
648 if (is_windows_9x () == TRUE)
650 return 0;
652 if (g_b_init_get_length_sid == 0)
654 g_b_init_get_length_sid = 1;
655 hm_advapi32 = LoadLibrary ("Advapi32.dll");
656 s_pfn_Get_Length_Sid =
657 (GetLengthSid_Proc) GetProcAddress (
658 hm_advapi32, "GetLengthSid");
660 if (s_pfn_Get_Length_Sid == NULL)
662 return 0;
664 return (s_pfn_Get_Length_Sid (sid));
667 static BOOL WINAPI
668 copy_sid (DWORD destlen, PSID dest, PSID src)
670 static CopySid_Proc s_pfn_Copy_Sid = NULL;
671 HMODULE hm_advapi32 = NULL;
672 if (is_windows_9x () == TRUE)
674 return FALSE;
676 if (g_b_init_copy_sid == 0)
678 g_b_init_copy_sid = 1;
679 hm_advapi32 = LoadLibrary ("Advapi32.dll");
680 s_pfn_Copy_Sid =
681 (CopySid_Proc) GetProcAddress (
682 hm_advapi32, "CopySid");
684 if (s_pfn_Copy_Sid == NULL)
686 return FALSE;
688 return (s_pfn_Copy_Sid (destlen, dest, src));
692 END: Wrapper functions around OpenProcessToken
693 and other functions in advapi32.dll that are only
694 supported in Windows NT / 2k / XP
697 static void WINAPI
698 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
700 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
701 if (is_windows_9x () != TRUE)
703 if (g_b_init_get_native_system_info == 0)
705 g_b_init_get_native_system_info = 1;
706 s_pfn_Get_Native_System_Info =
707 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
708 "GetNativeSystemInfo");
710 if (s_pfn_Get_Native_System_Info != NULL)
711 s_pfn_Get_Native_System_Info (lpSystemInfo);
713 else
714 lpSystemInfo->dwNumberOfProcessors = -1;
717 static BOOL WINAPI
718 get_system_times (LPFILETIME lpIdleTime,
719 LPFILETIME lpKernelTime,
720 LPFILETIME lpUserTime)
722 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
723 if (is_windows_9x () == TRUE)
725 return FALSE;
727 if (g_b_init_get_system_times == 0)
729 g_b_init_get_system_times = 1;
730 s_pfn_Get_System_times =
731 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
732 "GetSystemTimes");
734 if (s_pfn_Get_System_times == NULL)
735 return FALSE;
736 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
739 /* Equivalent of strerror for W32 error codes. */
740 char *
741 w32_strerror (int error_no)
743 static char buf[500];
745 if (error_no == 0)
746 error_no = GetLastError ();
748 buf[0] = '\0';
749 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
750 error_no,
751 0, /* choose most suitable language */
752 buf, sizeof (buf), NULL))
753 sprintf (buf, "w32 error %u", error_no);
754 return buf;
757 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
758 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
760 This is called from alloc.c:valid_pointer_p. */
762 w32_valid_pointer_p (void *p, int size)
764 SIZE_T done;
765 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
767 if (h)
769 unsigned char *buf = alloca (size);
770 int retval = ReadProcessMemory (h, p, buf, size, &done);
772 CloseHandle (h);
773 return retval;
775 else
776 return -1;
779 static char startup_dir[MAXPATHLEN];
781 /* Get the current working directory. */
782 char *
783 getwd (char *dir)
785 #if 0
786 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
787 return dir;
788 return NULL;
789 #else
790 /* Emacs doesn't actually change directory itself, and we want to
791 force our real wd to be where emacs.exe is to avoid unnecessary
792 conflicts when trying to rename or delete directories. */
793 strcpy (dir, startup_dir);
794 return dir;
795 #endif
798 /* Emulate getloadavg. */
800 struct load_sample {
801 time_t sample_time;
802 ULONGLONG idle;
803 ULONGLONG kernel;
804 ULONGLONG user;
807 /* Number of processors on this machine. */
808 static unsigned num_of_processors;
810 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
811 static struct load_sample samples[16*60];
812 static int first_idx = -1, last_idx = -1;
813 static int max_idx = sizeof (samples) / sizeof (samples[0]);
815 static int
816 buf_next (int from)
818 int next_idx = from + 1;
820 if (next_idx >= max_idx)
821 next_idx = 0;
823 return next_idx;
826 static int
827 buf_prev (int from)
829 int prev_idx = from - 1;
831 if (prev_idx < 0)
832 prev_idx = max_idx - 1;
834 return prev_idx;
837 static void
838 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
840 SYSTEM_INFO sysinfo;
841 FILETIME ft_idle, ft_user, ft_kernel;
843 /* Initialize the number of processors on this machine. */
844 if (num_of_processors <= 0)
846 get_native_system_info (&sysinfo);
847 num_of_processors = sysinfo.dwNumberOfProcessors;
848 if (num_of_processors <= 0)
850 GetSystemInfo (&sysinfo);
851 num_of_processors = sysinfo.dwNumberOfProcessors;
853 if (num_of_processors <= 0)
854 num_of_processors = 1;
857 /* TODO: Take into account threads that are ready to run, by
858 sampling the "\System\Processor Queue Length" performance
859 counter. The code below accounts only for threads that are
860 actually running. */
862 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
864 ULARGE_INTEGER uidle, ukernel, uuser;
866 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
867 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
868 memcpy (&uuser, &ft_user, sizeof (ft_user));
869 *idle = uidle.QuadPart;
870 *kernel = ukernel.QuadPart;
871 *user = uuser.QuadPart;
873 else
875 *idle = 0;
876 *kernel = 0;
877 *user = 0;
881 /* Produce the load average for a given time interval, using the
882 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
883 1-minute, 5-minute, or 15-minute average, respectively. */
884 static double
885 getavg (int which)
887 double retval = -1.0;
888 double tdiff;
889 int idx;
890 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
891 time_t now = samples[last_idx].sample_time;
893 if (first_idx != last_idx)
895 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
897 tdiff = difftime (now, samples[idx].sample_time);
898 if (tdiff >= span - 2*DBL_EPSILON*now)
900 long double sys =
901 samples[last_idx].kernel + samples[last_idx].user
902 - (samples[idx].kernel + samples[idx].user);
903 long double idl = samples[last_idx].idle - samples[idx].idle;
905 retval = (1.0 - idl / sys) * num_of_processors;
906 break;
908 if (idx == first_idx)
909 break;
913 return retval;
917 getloadavg (double loadavg[], int nelem)
919 int elem;
920 ULONGLONG idle, kernel, user;
921 time_t now = time (NULL);
923 /* Store another sample. We ignore samples that are less than 1 sec
924 apart. */
925 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
927 sample_system_load (&idle, &kernel, &user);
928 last_idx = buf_next (last_idx);
929 samples[last_idx].sample_time = now;
930 samples[last_idx].idle = idle;
931 samples[last_idx].kernel = kernel;
932 samples[last_idx].user = user;
933 /* If the buffer has more that 15 min worth of samples, discard
934 the old ones. */
935 if (first_idx == -1)
936 first_idx = last_idx;
937 while (first_idx != last_idx
938 && (difftime (now, samples[first_idx].sample_time)
939 >= 15.0*60 + 2*DBL_EPSILON*now))
940 first_idx = buf_next (first_idx);
943 for (elem = 0; elem < nelem; elem++)
945 double avg = getavg (elem);
947 if (avg < 0)
948 break;
949 loadavg[elem] = avg;
952 return elem;
955 /* Emulate getpwuid, getpwnam and others. */
957 #define PASSWD_FIELD_SIZE 256
959 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
960 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
961 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
962 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
963 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
965 static struct passwd dflt_passwd =
967 dflt_passwd_name,
968 dflt_passwd_passwd,
972 dflt_passwd_gecos,
973 dflt_passwd_dir,
974 dflt_passwd_shell,
977 static char dflt_group_name[GNLEN+1];
979 static struct group dflt_group =
981 /* When group information is not available, we return this as the
982 group for all files. */
983 dflt_group_name,
987 unsigned
988 getuid (void)
990 return dflt_passwd.pw_uid;
993 unsigned
994 geteuid (void)
996 /* I could imagine arguing for checking to see whether the user is
997 in the Administrators group and returning a UID of 0 for that
998 case, but I don't know how wise that would be in the long run. */
999 return getuid ();
1002 unsigned
1003 getgid (void)
1005 return dflt_passwd.pw_gid;
1008 unsigned
1009 getegid (void)
1011 return getgid ();
1014 struct passwd *
1015 getpwuid (unsigned uid)
1017 if (uid == dflt_passwd.pw_uid)
1018 return &dflt_passwd;
1019 return NULL;
1022 struct group *
1023 getgrgid (gid_t gid)
1025 return &dflt_group;
1028 struct passwd *
1029 getpwnam (char *name)
1031 struct passwd *pw;
1033 pw = getpwuid (getuid ());
1034 if (!pw)
1035 return pw;
1037 if (xstrcasecmp (name, pw->pw_name))
1038 return NULL;
1040 return pw;
1043 static void
1044 init_user_info (void)
1046 /* Find the user's real name by opening the process token and
1047 looking up the name associated with the user-sid in that token.
1049 Use the relative portion of the identifier authority value from
1050 the user-sid as the user id value (same for group id using the
1051 primary group sid from the process token). */
1053 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1054 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1055 DWORD glength = sizeof (gname);
1056 HANDLE token = NULL;
1057 SID_NAME_USE user_type;
1058 unsigned char *buf = NULL;
1059 DWORD blen = 0;
1060 TOKEN_USER user_token;
1061 TOKEN_PRIMARY_GROUP group_token;
1062 BOOL result;
1064 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1065 if (result)
1067 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1068 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1070 buf = xmalloc (blen);
1071 result = get_token_information (token, TokenUser,
1072 (LPVOID)buf, blen, &needed);
1073 if (result)
1075 memcpy (&user_token, buf, sizeof (user_token));
1076 result = lookup_account_sid (NULL, user_token.User.Sid,
1077 uname, &ulength,
1078 domain, &dlength, &user_type);
1081 else
1082 result = FALSE;
1084 if (result)
1086 strcpy (dflt_passwd.pw_name, uname);
1087 /* Determine a reasonable uid value. */
1088 if (xstrcasecmp ("administrator", uname) == 0)
1090 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1091 dflt_passwd.pw_gid = 513; /* well-known None gid */
1093 else
1095 /* Use the last sub-authority value of the RID, the relative
1096 portion of the SID, as user/group ID. */
1097 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1099 /* Get group id and name. */
1100 result = get_token_information (token, TokenPrimaryGroup,
1101 (LPVOID)buf, blen, &needed);
1102 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1104 buf = xrealloc (buf, blen = needed);
1105 result = get_token_information (token, TokenPrimaryGroup,
1106 (LPVOID)buf, blen, &needed);
1108 if (result)
1110 memcpy (&group_token, buf, sizeof (group_token));
1111 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1112 dlength = sizeof (domain);
1113 /* If we can get at the real Primary Group name, use that.
1114 Otherwise, the default group name was already set to
1115 "None" in globals_of_w32. */
1116 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1117 gname, &glength, NULL, &dlength,
1118 &user_type))
1119 strcpy (dflt_group_name, gname);
1121 else
1122 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1125 /* If security calls are not supported (presumably because we
1126 are running under Windows 9X), fallback to this: */
1127 else if (GetUserName (uname, &ulength))
1129 strcpy (dflt_passwd.pw_name, uname);
1130 if (xstrcasecmp ("administrator", uname) == 0)
1131 dflt_passwd.pw_uid = 0;
1132 else
1133 dflt_passwd.pw_uid = 123;
1134 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1136 else
1138 strcpy (dflt_passwd.pw_name, "unknown");
1139 dflt_passwd.pw_uid = 123;
1140 dflt_passwd.pw_gid = 123;
1142 dflt_group.gr_gid = dflt_passwd.pw_gid;
1144 /* Ensure HOME and SHELL are defined. */
1145 if (getenv ("HOME") == NULL)
1146 abort ();
1147 if (getenv ("SHELL") == NULL)
1148 abort ();
1150 /* Set dir and shell from environment variables. */
1151 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1152 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1154 xfree (buf);
1155 if (token)
1156 CloseHandle (token);
1160 random (void)
1162 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1163 return ((rand () << 15) | rand ());
1166 void
1167 srandom (int seed)
1169 srand (seed);
1173 /* Normalize filename by converting all path separators to
1174 the specified separator. Also conditionally convert upper
1175 case path name components to lower case. */
1177 static void
1178 normalize_filename (register char *fp, char path_sep)
1180 char sep;
1181 char *elem;
1183 /* Always lower-case drive letters a-z, even if the filesystem
1184 preserves case in filenames.
1185 This is so filenames can be compared by string comparison
1186 functions that are case-sensitive. Even case-preserving filesystems
1187 do not distinguish case in drive letters. */
1188 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
1190 *fp += 'a' - 'A';
1191 fp += 2;
1194 if (NILP (Vw32_downcase_file_names))
1196 while (*fp)
1198 if (*fp == '/' || *fp == '\\')
1199 *fp = path_sep;
1200 fp++;
1202 return;
1205 sep = path_sep; /* convert to this path separator */
1206 elem = fp; /* start of current path element */
1208 do {
1209 if (*fp >= 'a' && *fp <= 'z')
1210 elem = 0; /* don't convert this element */
1212 if (*fp == 0 || *fp == ':')
1214 sep = *fp; /* restore current separator (or 0) */
1215 *fp = '/'; /* after conversion of this element */
1218 if (*fp == '/' || *fp == '\\')
1220 if (elem && elem != fp)
1222 *fp = 0; /* temporary end of string */
1223 _strlwr (elem); /* while we convert to lower case */
1225 *fp = sep; /* convert (or restore) path separator */
1226 elem = fp + 1; /* next element starts after separator */
1227 sep = path_sep;
1229 } while (*fp++);
1232 /* Destructively turn backslashes into slashes. */
1233 void
1234 dostounix_filename (register char *p)
1236 normalize_filename (p, '/');
1239 /* Destructively turn slashes into backslashes. */
1240 void
1241 unixtodos_filename (register char *p)
1243 normalize_filename (p, '\\');
1246 /* Remove all CR's that are followed by a LF.
1247 (From msdos.c...probably should figure out a way to share it,
1248 although this code isn't going to ever change.) */
1249 static int
1250 crlf_to_lf (register int n, register unsigned char *buf)
1252 unsigned char *np = buf;
1253 unsigned char *startp = buf;
1254 unsigned char *endp = buf + n;
1256 if (n == 0)
1257 return n;
1258 while (buf < endp - 1)
1260 if (*buf == 0x0d)
1262 if (*(++buf) != 0x0a)
1263 *np++ = 0x0d;
1265 else
1266 *np++ = *buf++;
1268 if (buf < endp)
1269 *np++ = *buf++;
1270 return np - startp;
1273 /* Parse the root part of file name, if present. Return length and
1274 optionally store pointer to char after root. */
1275 static int
1276 parse_root (char * name, char ** pPath)
1278 char * start = name;
1280 if (name == NULL)
1281 return 0;
1283 /* find the root name of the volume if given */
1284 if (isalpha (name[0]) && name[1] == ':')
1286 /* skip past drive specifier */
1287 name += 2;
1288 if (IS_DIRECTORY_SEP (name[0]))
1289 name++;
1291 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1293 int slashes = 2;
1294 name += 2;
1297 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1298 break;
1299 name++;
1301 while ( *name );
1302 if (IS_DIRECTORY_SEP (name[0]))
1303 name++;
1306 if (pPath)
1307 *pPath = name;
1309 return name - start;
1312 /* Get long base name for name; name is assumed to be absolute. */
1313 static int
1314 get_long_basename (char * name, char * buf, int size)
1316 WIN32_FIND_DATA find_data;
1317 HANDLE dir_handle;
1318 int len = 0;
1320 /* must be valid filename, no wild cards or other invalid characters */
1321 if (_mbspbrk (name, "*?|<>\""))
1322 return 0;
1324 dir_handle = FindFirstFile (name, &find_data);
1325 if (dir_handle != INVALID_HANDLE_VALUE)
1327 if ((len = strlen (find_data.cFileName)) < size)
1328 memcpy (buf, find_data.cFileName, len + 1);
1329 else
1330 len = 0;
1331 FindClose (dir_handle);
1333 return len;
1336 /* Get long name for file, if possible (assumed to be absolute). */
1337 BOOL
1338 w32_get_long_filename (char * name, char * buf, int size)
1340 char * o = buf;
1341 char * p;
1342 char * q;
1343 char full[ MAX_PATH ];
1344 int len;
1346 len = strlen (name);
1347 if (len >= MAX_PATH)
1348 return FALSE;
1350 /* Use local copy for destructive modification. */
1351 memcpy (full, name, len+1);
1352 unixtodos_filename (full);
1354 /* Copy root part verbatim. */
1355 len = parse_root (full, &p);
1356 memcpy (o, full, len);
1357 o += len;
1358 *o = '\0';
1359 size -= len;
1361 while (p != NULL && *p)
1363 q = p;
1364 p = strchr (q, '\\');
1365 if (p) *p = '\0';
1366 len = get_long_basename (full, o, size);
1367 if (len > 0)
1369 o += len;
1370 size -= len;
1371 if (p != NULL)
1373 *p++ = '\\';
1374 if (size < 2)
1375 return FALSE;
1376 *o++ = '\\';
1377 size--;
1378 *o = '\0';
1381 else
1382 return FALSE;
1385 return TRUE;
1388 static int
1389 is_unc_volume (const char *filename)
1391 const char *ptr = filename;
1393 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1394 return 0;
1396 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1397 return 0;
1399 return 1;
1402 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1405 sigsetmask (int signal_mask)
1407 return 0;
1411 sigmask (int sig)
1413 return 0;
1417 sigblock (int sig)
1419 return 0;
1423 sigunblock (int sig)
1425 return 0;
1429 sigemptyset (sigset_t *set)
1431 return 0;
1435 sigaddset (sigset_t *set, int signo)
1437 return 0;
1441 sigfillset (sigset_t *set)
1443 return 0;
1447 sigprocmask (int how, const sigset_t *set, sigset_t *oset)
1449 return 0;
1453 setpgrp (int pid, int gid)
1455 return 0;
1459 alarm (int seconds)
1461 return 0;
1464 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1466 LPBYTE
1467 w32_get_resource (char *key, LPDWORD lpdwtype)
1469 LPBYTE lpvalue;
1470 HKEY hrootkey = NULL;
1471 DWORD cbData;
1473 /* Check both the current user and the local machine to see if
1474 we have any resources. */
1476 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1478 lpvalue = NULL;
1480 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1481 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1482 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1484 RegCloseKey (hrootkey);
1485 return (lpvalue);
1488 xfree (lpvalue);
1490 RegCloseKey (hrootkey);
1493 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1495 lpvalue = NULL;
1497 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1498 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1499 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1501 RegCloseKey (hrootkey);
1502 return (lpvalue);
1505 xfree (lpvalue);
1507 RegCloseKey (hrootkey);
1510 return (NULL);
1513 char *get_emacs_configuration (void);
1515 void
1516 init_environment (char ** argv)
1518 static const char * const tempdirs[] = {
1519 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1522 int i;
1524 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1526 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1527 temporary files and assume "/tmp" if $TMPDIR is unset, which
1528 will break on DOS/Windows. Refuse to work if we cannot find
1529 a directory, not even "c:/", usable for that purpose. */
1530 for (i = 0; i < imax ; i++)
1532 const char *tmp = tempdirs[i];
1534 if (*tmp == '$')
1535 tmp = getenv (tmp + 1);
1536 /* Note that `access' can lie to us if the directory resides on a
1537 read-only filesystem, like CD-ROM or a write-protected floppy.
1538 The only way to be really sure is to actually create a file and
1539 see if it succeeds. But I think that's too much to ask. */
1540 if (tmp && _access (tmp, D_OK) == 0)
1542 char * var = alloca (strlen (tmp) + 8);
1543 sprintf (var, "TMPDIR=%s", tmp);
1544 _putenv (strdup (var));
1545 break;
1548 if (i >= imax)
1549 cmd_error_internal
1550 (Fcons (Qerror,
1551 Fcons (build_string ("no usable temporary directories found!!"),
1552 Qnil)),
1553 "While setting TMPDIR: ");
1555 /* Check for environment variables and use registry settings if they
1556 don't exist. Fallback on default values where applicable. */
1558 int i;
1559 LPBYTE lpval;
1560 DWORD dwType;
1561 char locale_name[32];
1562 struct stat ignored;
1563 char default_home[MAX_PATH];
1564 int appdata = 0;
1566 static const struct env_entry
1568 char * name;
1569 char * def_value;
1570 } dflt_envvars[] =
1572 {"HOME", "C:/"},
1573 {"PRELOAD_WINSOCK", NULL},
1574 {"emacs_dir", "C:/emacs"},
1575 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1576 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1577 {"EMACSDATA", "%emacs_dir%/etc"},
1578 {"EMACSPATH", "%emacs_dir%/bin"},
1579 /* We no longer set INFOPATH because Info-default-directory-list
1580 is then ignored. */
1581 /* {"INFOPATH", "%emacs_dir%/info"}, */
1582 {"EMACSDOC", "%emacs_dir%/etc"},
1583 {"TERM", "cmd"},
1584 {"LANG", NULL},
1587 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1589 /* We need to copy dflt_envvars[] and work on the copy because we
1590 don't want the dumped Emacs to inherit the values of
1591 environment variables we saw during dumping (which could be on
1592 a different system). The defaults above must be left intact. */
1593 struct env_entry env_vars[N_ENV_VARS];
1595 for (i = 0; i < N_ENV_VARS; i++)
1596 env_vars[i] = dflt_envvars[i];
1598 /* For backwards compatibility, check if a .emacs file exists in C:/
1599 If not, then we can try to default to the appdata directory under the
1600 user's profile, which is more likely to be writable. */
1601 if (stat ("C:/.emacs", &ignored) < 0)
1603 HRESULT profile_result;
1604 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1605 of Windows 95 and NT4 that have not been updated to include
1606 MSIE 5. */
1607 ShGetFolderPath_fn get_folder_path;
1608 get_folder_path = (ShGetFolderPath_fn)
1609 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1611 if (get_folder_path != NULL)
1613 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1614 0, default_home);
1616 /* If we can't get the appdata dir, revert to old behavior. */
1617 if (profile_result == S_OK)
1619 env_vars[0].def_value = default_home;
1620 appdata = 1;
1625 /* Get default locale info and use it for LANG. */
1626 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1627 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1628 locale_name, sizeof (locale_name)))
1630 for (i = 0; i < N_ENV_VARS; i++)
1632 if (strcmp (env_vars[i].name, "LANG") == 0)
1634 env_vars[i].def_value = locale_name;
1635 break;
1640 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1642 /* Treat emacs_dir specially: set it unconditionally based on our
1643 location, if it appears that we are running from the bin subdir
1644 of a standard installation. */
1646 char *p;
1647 char modname[MAX_PATH];
1649 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1650 abort ();
1651 if ((p = strrchr (modname, '\\')) == NULL)
1652 abort ();
1653 *p = 0;
1655 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1657 char buf[SET_ENV_BUF_SIZE];
1659 *p = 0;
1660 for (p = modname; *p; p++)
1661 if (*p == '\\') *p = '/';
1663 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1664 _putenv (strdup (buf));
1666 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1668 /* FIXME: should use substring of get_emacs_configuration ().
1669 But I don't think the Windows build supports alpha, mips etc
1670 anymore, so have taken the easy option for now. */
1671 else if (p && xstrcasecmp (p, "\\i386") == 0)
1673 *p = 0;
1674 p = strrchr (modname, '\\');
1675 if (p != NULL)
1677 *p = 0;
1678 p = strrchr (modname, '\\');
1679 if (p && xstrcasecmp (p, "\\src") == 0)
1681 char buf[SET_ENV_BUF_SIZE];
1683 *p = 0;
1684 for (p = modname; *p; p++)
1685 if (*p == '\\') *p = '/';
1687 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1688 _putenv (strdup (buf));
1694 for (i = 0; i < N_ENV_VARS; i++)
1696 if (!getenv (env_vars[i].name))
1698 int dont_free = 0;
1700 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1701 /* Also ignore empty environment variables. */
1702 || *lpval == 0)
1704 xfree (lpval);
1705 lpval = env_vars[i].def_value;
1706 dwType = REG_EXPAND_SZ;
1707 dont_free = 1;
1708 if (!strcmp (env_vars[i].name, "HOME") && !appdata)
1710 Lisp_Object warning[2];
1711 warning[0] = intern ("initialization");
1712 warning[1] = build_string ("Setting HOME to C:\\ by default is deprecated");
1713 Vdelayed_warnings_list = Fcons (Flist (2, warning),
1714 Vdelayed_warnings_list);
1718 if (lpval)
1720 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1722 if (dwType == REG_EXPAND_SZ)
1723 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
1724 else if (dwType == REG_SZ)
1725 strcpy (buf1, lpval);
1726 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1728 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
1729 buf1);
1730 _putenv (strdup (buf2));
1733 if (!dont_free)
1734 xfree (lpval);
1740 /* Rebuild system configuration to reflect invoking system. */
1741 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1743 /* Another special case: on NT, the PATH variable is actually named
1744 "Path" although cmd.exe (perhaps NT itself) arranges for
1745 environment variable lookup and setting to be case insensitive.
1746 However, Emacs assumes a fully case sensitive environment, so we
1747 need to change "Path" to "PATH" to match the expectations of
1748 various elisp packages. We do this by the sneaky method of
1749 modifying the string in the C runtime environ entry.
1751 The same applies to COMSPEC. */
1753 char ** envp;
1755 for (envp = environ; *envp; envp++)
1756 if (_strnicmp (*envp, "PATH=", 5) == 0)
1757 memcpy (*envp, "PATH=", 5);
1758 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1759 memcpy (*envp, "COMSPEC=", 8);
1762 /* Remember the initial working directory for getwd, then make the
1763 real wd be the location of emacs.exe to avoid conflicts when
1764 renaming or deleting directories. (We also don't call chdir when
1765 running subprocesses for the same reason.) */
1766 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1767 abort ();
1770 char *p;
1771 static char modname[MAX_PATH];
1773 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1774 abort ();
1775 if ((p = strrchr (modname, '\\')) == NULL)
1776 abort ();
1777 *p = 0;
1779 SetCurrentDirectory (modname);
1781 /* Ensure argv[0] has the full path to Emacs. */
1782 *p = '\\';
1783 argv[0] = modname;
1786 /* Determine if there is a middle mouse button, to allow parse_button
1787 to decide whether right mouse events should be mouse-2 or
1788 mouse-3. */
1789 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1791 init_user_info ();
1794 char *
1795 emacs_root_dir (void)
1797 static char root_dir[FILENAME_MAX];
1798 const char *p;
1800 p = getenv ("emacs_dir");
1801 if (p == NULL)
1802 abort ();
1803 strcpy (root_dir, p);
1804 root_dir[parse_root (root_dir, NULL)] = '\0';
1805 dostounix_filename (root_dir);
1806 return root_dir;
1809 /* We don't have scripts to automatically determine the system configuration
1810 for Emacs before it's compiled, and we don't want to have to make the
1811 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1812 routine. */
1814 char *
1815 get_emacs_configuration (void)
1817 char *arch, *oem, *os;
1818 int build_num;
1819 static char configuration_buffer[32];
1821 /* Determine the processor type. */
1822 switch (get_processor_type ())
1825 #ifdef PROCESSOR_INTEL_386
1826 case PROCESSOR_INTEL_386:
1827 case PROCESSOR_INTEL_486:
1828 case PROCESSOR_INTEL_PENTIUM:
1829 arch = "i386";
1830 break;
1831 #endif
1833 #ifdef PROCESSOR_MIPS_R2000
1834 case PROCESSOR_MIPS_R2000:
1835 case PROCESSOR_MIPS_R3000:
1836 case PROCESSOR_MIPS_R4000:
1837 arch = "mips";
1838 break;
1839 #endif
1841 #ifdef PROCESSOR_ALPHA_21064
1842 case PROCESSOR_ALPHA_21064:
1843 arch = "alpha";
1844 break;
1845 #endif
1847 default:
1848 arch = "unknown";
1849 break;
1852 /* Use the OEM field to reflect the compiler/library combination. */
1853 #ifdef _MSC_VER
1854 #define COMPILER_NAME "msvc"
1855 #else
1856 #ifdef __GNUC__
1857 #define COMPILER_NAME "mingw"
1858 #else
1859 #define COMPILER_NAME "unknown"
1860 #endif
1861 #endif
1862 oem = COMPILER_NAME;
1864 switch (osinfo_cache.dwPlatformId) {
1865 case VER_PLATFORM_WIN32_NT:
1866 os = "nt";
1867 build_num = osinfo_cache.dwBuildNumber;
1868 break;
1869 case VER_PLATFORM_WIN32_WINDOWS:
1870 if (osinfo_cache.dwMinorVersion == 0) {
1871 os = "windows95";
1872 } else {
1873 os = "windows98";
1875 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1876 break;
1877 case VER_PLATFORM_WIN32s:
1878 /* Not supported, should not happen. */
1879 os = "windows32s";
1880 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1881 break;
1882 default:
1883 os = "unknown";
1884 build_num = 0;
1885 break;
1888 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1889 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1890 get_w32_major_version (), get_w32_minor_version (), build_num);
1891 } else {
1892 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1895 return configuration_buffer;
1898 char *
1899 get_emacs_configuration_options (void)
1901 static char *options_buffer;
1902 char cv[32]; /* Enough for COMPILER_VERSION. */
1903 char *options[] = {
1904 cv, /* To be filled later. */
1905 #ifdef EMACSDEBUG
1906 " --no-opt",
1907 #endif
1908 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1909 with a starting space to save work here. */
1910 #ifdef USER_CFLAGS
1911 " --cflags", USER_CFLAGS,
1912 #endif
1913 #ifdef USER_LDFLAGS
1914 " --ldflags", USER_LDFLAGS,
1915 #endif
1916 NULL
1918 size_t size = 0;
1919 int i;
1921 /* Work out the effective configure options for this build. */
1922 #ifdef _MSC_VER
1923 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1924 #else
1925 #ifdef __GNUC__
1926 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1927 #else
1928 #define COMPILER_VERSION ""
1929 #endif
1930 #endif
1932 if (_snprintf (cv, sizeof (cv) - 1, COMPILER_VERSION) < 0)
1933 return "Error: not enough space for compiler version";
1934 cv[sizeof (cv) - 1] = '\0';
1936 for (i = 0; options[i]; i++)
1937 size += strlen (options[i]);
1939 options_buffer = xmalloc (size + 1);
1940 options_buffer[0] = '\0';
1942 for (i = 0; options[i]; i++)
1943 strcat (options_buffer, options[i]);
1945 return options_buffer;
1949 #include <sys/timeb.h>
1951 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1952 void
1953 gettimeofday (struct timeval *tv, struct timezone *tz)
1955 struct _timeb tb;
1956 _ftime (&tb);
1958 tv->tv_sec = tb.time;
1959 tv->tv_usec = tb.millitm * 1000L;
1960 /* Implementation note: _ftime sometimes doesn't update the dstflag
1961 according to the new timezone when the system timezone is
1962 changed. We could fix that by using GetSystemTime and
1963 GetTimeZoneInformation, but that doesn't seem necessary, since
1964 Emacs always calls gettimeofday with the 2nd argument NULL (see
1965 EMACS_GET_TIME). */
1966 if (tz)
1968 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
1969 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
1973 /* ------------------------------------------------------------------------- */
1974 /* IO support and wrapper functions for W32 API. */
1975 /* ------------------------------------------------------------------------- */
1977 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1978 on network directories, so we handle that case here.
1979 (Ulrich Leodolter, 1/11/95). */
1980 char *
1981 sys_ctime (const time_t *t)
1983 char *str = (char *) ctime (t);
1984 return (str ? str : "Sun Jan 01 00:00:00 1970");
1987 /* Emulate sleep...we could have done this with a define, but that
1988 would necessitate including windows.h in the files that used it.
1989 This is much easier. */
1990 void
1991 sys_sleep (int seconds)
1993 Sleep (seconds * 1000);
1996 /* Internal MSVC functions for low-level descriptor munging */
1997 extern int __cdecl _set_osfhnd (int fd, long h);
1998 extern int __cdecl _free_osfhnd (int fd);
2000 /* parallel array of private info on file handles */
2001 filedesc fd_info [ MAXDESC ];
2003 typedef struct volume_info_data {
2004 struct volume_info_data * next;
2006 /* time when info was obtained */
2007 DWORD timestamp;
2009 /* actual volume info */
2010 char * root_dir;
2011 DWORD serialnum;
2012 DWORD maxcomp;
2013 DWORD flags;
2014 char * name;
2015 char * type;
2016 } volume_info_data;
2018 /* Global referenced by various functions. */
2019 static volume_info_data volume_info;
2021 /* Vector to indicate which drives are local and fixed (for which cached
2022 data never expires). */
2023 static BOOL fixed_drives[26];
2025 /* Consider cached volume information to be stale if older than 10s,
2026 at least for non-local drives. Info for fixed drives is never stale. */
2027 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2028 #define VOLINFO_STILL_VALID( root_dir, info ) \
2029 ( ( isalpha (root_dir[0]) && \
2030 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2031 || GetTickCount () - info->timestamp < 10000 )
2033 /* Cache support functions. */
2035 /* Simple linked list with linear search is sufficient. */
2036 static volume_info_data *volume_cache = NULL;
2038 static volume_info_data *
2039 lookup_volume_info (char * root_dir)
2041 volume_info_data * info;
2043 for (info = volume_cache; info; info = info->next)
2044 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2045 break;
2046 return info;
2049 static void
2050 add_volume_info (char * root_dir, volume_info_data * info)
2052 info->root_dir = xstrdup (root_dir);
2053 info->next = volume_cache;
2054 volume_cache = info;
2058 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2059 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2060 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2061 static volume_info_data *
2062 GetCachedVolumeInformation (char * root_dir)
2064 volume_info_data * info;
2065 char default_root[ MAX_PATH ];
2067 /* NULL for root_dir means use root from current directory. */
2068 if (root_dir == NULL)
2070 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
2071 return NULL;
2072 parse_root (default_root, &root_dir);
2073 *root_dir = 0;
2074 root_dir = default_root;
2077 /* Local fixed drives can be cached permanently. Removable drives
2078 cannot be cached permanently, since the volume name and serial
2079 number (if nothing else) can change. Remote drives should be
2080 treated as if they are removable, since there is no sure way to
2081 tell whether they are or not. Also, the UNC association of drive
2082 letters mapped to remote volumes can be changed at any time (even
2083 by other processes) without notice.
2085 As a compromise, so we can benefit from caching info for remote
2086 volumes, we use a simple expiry mechanism to invalidate cache
2087 entries that are more than ten seconds old. */
2089 #if 0
2090 /* No point doing this, because WNetGetConnection is even slower than
2091 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2092 GetDriveType is about the only call of this type which does not
2093 involve network access, and so is extremely quick). */
2095 /* Map drive letter to UNC if remote. */
2096 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2098 char remote_name[ 256 ];
2099 char drive[3] = { root_dir[0], ':' };
2101 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2102 == NO_ERROR)
2103 /* do something */ ;
2105 #endif
2107 info = lookup_volume_info (root_dir);
2109 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2111 char name[ 256 ];
2112 DWORD serialnum;
2113 DWORD maxcomp;
2114 DWORD flags;
2115 char type[ 256 ];
2117 /* Info is not cached, or is stale. */
2118 if (!GetVolumeInformation (root_dir,
2119 name, sizeof (name),
2120 &serialnum,
2121 &maxcomp,
2122 &flags,
2123 type, sizeof (type)))
2124 return NULL;
2126 /* Cache the volume information for future use, overwriting existing
2127 entry if present. */
2128 if (info == NULL)
2130 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
2131 add_volume_info (root_dir, info);
2133 else
2135 xfree (info->name);
2136 xfree (info->type);
2139 info->name = xstrdup (name);
2140 info->serialnum = serialnum;
2141 info->maxcomp = maxcomp;
2142 info->flags = flags;
2143 info->type = xstrdup (type);
2144 info->timestamp = GetTickCount ();
2147 return info;
2150 /* Get information on the volume where name is held; set path pointer to
2151 start of pathname in name (past UNC header\volume header if present). */
2152 static int
2153 get_volume_info (const char * name, const char ** pPath)
2155 char temp[MAX_PATH];
2156 char *rootname = NULL; /* default to current volume */
2157 volume_info_data * info;
2159 if (name == NULL)
2160 return FALSE;
2162 /* find the root name of the volume if given */
2163 if (isalpha (name[0]) && name[1] == ':')
2165 rootname = temp;
2166 temp[0] = *name++;
2167 temp[1] = *name++;
2168 temp[2] = '\\';
2169 temp[3] = 0;
2171 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2173 char *str = temp;
2174 int slashes = 4;
2175 rootname = temp;
2178 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2179 break;
2180 *str++ = *name++;
2182 while ( *name );
2184 *str++ = '\\';
2185 *str = 0;
2188 if (pPath)
2189 *pPath = name;
2191 info = GetCachedVolumeInformation (rootname);
2192 if (info != NULL)
2194 /* Set global referenced by other functions. */
2195 volume_info = *info;
2196 return TRUE;
2198 return FALSE;
2201 /* Determine if volume is FAT format (ie. only supports short 8.3
2202 names); also set path pointer to start of pathname in name. */
2203 static int
2204 is_fat_volume (const char * name, const char ** pPath)
2206 if (get_volume_info (name, pPath))
2207 return (volume_info.maxcomp == 12);
2208 return FALSE;
2211 /* Map filename to a valid 8.3 name if necessary. */
2212 const char *
2213 map_w32_filename (const char * name, const char ** pPath)
2215 static char shortname[MAX_PATH];
2216 char * str = shortname;
2217 char c;
2218 char * path;
2219 const char * save_name = name;
2221 if (strlen (name) >= MAX_PATH)
2223 /* Return a filename which will cause callers to fail. */
2224 strcpy (shortname, "?");
2225 return shortname;
2228 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2230 register int left = 8; /* maximum number of chars in part */
2231 register int extn = 0; /* extension added? */
2232 register int dots = 2; /* maximum number of dots allowed */
2234 while (name < path)
2235 *str++ = *name++; /* skip past UNC header */
2237 while ((c = *name++))
2239 switch ( c )
2241 case '\\':
2242 case '/':
2243 *str++ = '\\';
2244 extn = 0; /* reset extension flags */
2245 dots = 2; /* max 2 dots */
2246 left = 8; /* max length 8 for main part */
2247 break;
2248 case ':':
2249 *str++ = ':';
2250 extn = 0; /* reset extension flags */
2251 dots = 2; /* max 2 dots */
2252 left = 8; /* max length 8 for main part */
2253 break;
2254 case '.':
2255 if ( dots )
2257 /* Convert path components of the form .xxx to _xxx,
2258 but leave . and .. as they are. This allows .emacs
2259 to be read as _emacs, for example. */
2261 if (! *name ||
2262 *name == '.' ||
2263 IS_DIRECTORY_SEP (*name))
2265 *str++ = '.';
2266 dots--;
2268 else
2270 *str++ = '_';
2271 left--;
2272 dots = 0;
2275 else if ( !extn )
2277 *str++ = '.';
2278 extn = 1; /* we've got an extension */
2279 left = 3; /* 3 chars in extension */
2281 else
2283 /* any embedded dots after the first are converted to _ */
2284 *str++ = '_';
2286 break;
2287 case '~':
2288 case '#': /* don't lose these, they're important */
2289 if ( ! left )
2290 str[-1] = c; /* replace last character of part */
2291 /* FALLTHRU */
2292 default:
2293 if ( left )
2295 *str++ = tolower (c); /* map to lower case (looks nicer) */
2296 left--;
2297 dots = 0; /* started a path component */
2299 break;
2302 *str = '\0';
2304 else
2306 strcpy (shortname, name);
2307 unixtodos_filename (shortname);
2310 if (pPath)
2311 *pPath = shortname + (path - save_name);
2313 return shortname;
2316 static int
2317 is_exec (const char * name)
2319 char * p = strrchr (name, '.');
2320 return
2321 (p != NULL
2322 && (xstrcasecmp (p, ".exe") == 0 ||
2323 xstrcasecmp (p, ".com") == 0 ||
2324 xstrcasecmp (p, ".bat") == 0 ||
2325 xstrcasecmp (p, ".cmd") == 0));
2328 /* Emulate the Unix directory procedures opendir, closedir,
2329 and readdir. We can't use the procedures supplied in sysdep.c,
2330 so we provide them here. */
2332 struct direct dir_static; /* simulated directory contents */
2333 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2334 static int dir_is_fat;
2335 static char dir_pathname[MAXPATHLEN+1];
2336 static WIN32_FIND_DATA dir_find_data;
2338 /* Support shares on a network resource as subdirectories of a read-only
2339 root directory. */
2340 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2341 static HANDLE open_unc_volume (const char *);
2342 static char *read_unc_volume (HANDLE, char *, int);
2343 static void close_unc_volume (HANDLE);
2345 DIR *
2346 opendir (char *filename)
2348 DIR *dirp;
2350 /* Opening is done by FindFirstFile. However, a read is inherent to
2351 this operation, so we defer the open until read time. */
2353 if (dir_find_handle != INVALID_HANDLE_VALUE)
2354 return NULL;
2355 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2356 return NULL;
2358 if (is_unc_volume (filename))
2360 wnet_enum_handle = open_unc_volume (filename);
2361 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2362 return NULL;
2365 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2366 return NULL;
2368 dirp->dd_fd = 0;
2369 dirp->dd_loc = 0;
2370 dirp->dd_size = 0;
2372 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2373 dir_pathname[MAXPATHLEN] = '\0';
2374 dir_is_fat = is_fat_volume (filename, NULL);
2376 return dirp;
2379 void
2380 closedir (DIR *dirp)
2382 /* If we have a find-handle open, close it. */
2383 if (dir_find_handle != INVALID_HANDLE_VALUE)
2385 FindClose (dir_find_handle);
2386 dir_find_handle = INVALID_HANDLE_VALUE;
2388 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2390 close_unc_volume (wnet_enum_handle);
2391 wnet_enum_handle = INVALID_HANDLE_VALUE;
2393 xfree ((char *) dirp);
2396 struct direct *
2397 readdir (DIR *dirp)
2399 int downcase = !NILP (Vw32_downcase_file_names);
2401 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2403 if (!read_unc_volume (wnet_enum_handle,
2404 dir_find_data.cFileName,
2405 MAX_PATH))
2406 return NULL;
2408 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2409 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2411 char filename[MAXNAMLEN + 3];
2412 int ln;
2414 strcpy (filename, dir_pathname);
2415 ln = strlen (filename) - 1;
2416 if (!IS_DIRECTORY_SEP (filename[ln]))
2417 strcat (filename, "\\");
2418 strcat (filename, "*");
2420 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2422 if (dir_find_handle == INVALID_HANDLE_VALUE)
2423 return NULL;
2425 else
2427 if (!FindNextFile (dir_find_handle, &dir_find_data))
2428 return NULL;
2431 /* Emacs never uses this value, so don't bother making it match
2432 value returned by stat(). */
2433 dir_static.d_ino = 1;
2435 strcpy (dir_static.d_name, dir_find_data.cFileName);
2437 /* If the file name in cFileName[] includes `?' characters, it means
2438 the original file name used characters that cannot be represented
2439 by the current ANSI codepage. To avoid total lossage, retrieve
2440 the short 8+3 alias of the long file name. */
2441 if (_mbspbrk (dir_static.d_name, "?"))
2443 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2444 downcase = 1; /* 8+3 aliases are returned in all caps */
2446 dir_static.d_namlen = strlen (dir_static.d_name);
2447 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
2448 dir_static.d_namlen - dir_static.d_namlen % 4;
2450 /* If the file name in cFileName[] includes `?' characters, it means
2451 the original file name used characters that cannot be represented
2452 by the current ANSI codepage. To avoid total lossage, retrieve
2453 the short 8+3 alias of the long file name. */
2454 if (_mbspbrk (dir_find_data.cFileName, "?"))
2456 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2457 /* 8+3 aliases are returned in all caps, which could break
2458 various alists that look at filenames' extensions. */
2459 downcase = 1;
2461 else
2462 strcpy (dir_static.d_name, dir_find_data.cFileName);
2463 dir_static.d_namlen = strlen (dir_static.d_name);
2464 if (dir_is_fat)
2465 _strlwr (dir_static.d_name);
2466 else if (downcase)
2468 register char *p;
2469 for (p = dir_static.d_name; *p; p++)
2470 if (*p >= 'a' && *p <= 'z')
2471 break;
2472 if (!*p)
2473 _strlwr (dir_static.d_name);
2476 return &dir_static;
2479 static HANDLE
2480 open_unc_volume (const char *path)
2482 NETRESOURCE nr;
2483 HANDLE henum;
2484 int result;
2486 nr.dwScope = RESOURCE_GLOBALNET;
2487 nr.dwType = RESOURCETYPE_DISK;
2488 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2489 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2490 nr.lpLocalName = NULL;
2491 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
2492 nr.lpComment = NULL;
2493 nr.lpProvider = NULL;
2495 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2496 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2498 if (result == NO_ERROR)
2499 return henum;
2500 else
2501 return INVALID_HANDLE_VALUE;
2504 static char *
2505 read_unc_volume (HANDLE henum, char *readbuf, int size)
2507 DWORD count;
2508 int result;
2509 DWORD bufsize = 512;
2510 char *buffer;
2511 char *ptr;
2513 count = 1;
2514 buffer = alloca (bufsize);
2515 result = WNetEnumResource (henum, &count, buffer, &bufsize);
2516 if (result != NO_ERROR)
2517 return NULL;
2519 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2520 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2521 ptr += 2;
2522 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2523 ptr++;
2525 strncpy (readbuf, ptr, size);
2526 return readbuf;
2529 static void
2530 close_unc_volume (HANDLE henum)
2532 if (henum != INVALID_HANDLE_VALUE)
2533 WNetCloseEnum (henum);
2536 static DWORD
2537 unc_volume_file_attributes (const char *path)
2539 HANDLE henum;
2540 DWORD attrs;
2542 henum = open_unc_volume (path);
2543 if (henum == INVALID_HANDLE_VALUE)
2544 return -1;
2546 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2548 close_unc_volume (henum);
2550 return attrs;
2553 /* Ensure a network connection is authenticated. */
2554 static void
2555 logon_network_drive (const char *path)
2557 NETRESOURCE resource;
2558 char share[MAX_PATH];
2559 int i, n_slashes;
2560 char drive[4];
2561 UINT drvtype;
2563 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
2564 drvtype = DRIVE_REMOTE;
2565 else if (path[0] == '\0' || path[1] != ':')
2566 drvtype = GetDriveType (NULL);
2567 else
2569 drive[0] = path[0];
2570 drive[1] = ':';
2571 drive[2] = '\\';
2572 drive[3] = '\0';
2573 drvtype = GetDriveType (drive);
2576 /* Only logon to networked drives. */
2577 if (drvtype != DRIVE_REMOTE)
2578 return;
2580 n_slashes = 2;
2581 strncpy (share, path, MAX_PATH);
2582 /* Truncate to just server and share name. */
2583 for (i = 2; i < MAX_PATH; i++)
2585 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2587 share[i] = '\0';
2588 break;
2592 resource.dwType = RESOURCETYPE_DISK;
2593 resource.lpLocalName = NULL;
2594 resource.lpRemoteName = share;
2595 resource.lpProvider = NULL;
2597 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2600 /* Shadow some MSVC runtime functions to map requests for long filenames
2601 to reasonable short names if necessary. This was originally added to
2602 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2603 long file names. */
2606 sys_access (const char * path, int mode)
2608 DWORD attributes;
2610 /* MSVC implementation doesn't recognize D_OK. */
2611 path = map_w32_filename (path, NULL);
2612 if (is_unc_volume (path))
2614 attributes = unc_volume_file_attributes (path);
2615 if (attributes == -1) {
2616 errno = EACCES;
2617 return -1;
2620 else if ((attributes = GetFileAttributes (path)) == -1)
2622 /* Should try mapping GetLastError to errno; for now just indicate
2623 that path doesn't exist. */
2624 errno = EACCES;
2625 return -1;
2627 if ((mode & X_OK) != 0 && !is_exec (path))
2629 errno = EACCES;
2630 return -1;
2632 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2634 errno = EACCES;
2635 return -1;
2637 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2639 errno = EACCES;
2640 return -1;
2642 return 0;
2646 sys_chdir (const char * path)
2648 return _chdir (map_w32_filename (path, NULL));
2652 sys_chmod (const char * path, int mode)
2654 return _chmod (map_w32_filename (path, NULL), mode);
2658 sys_chown (const char *path, uid_t owner, gid_t group)
2660 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2661 return -1;
2662 return 0;
2666 sys_creat (const char * path, int mode)
2668 return _creat (map_w32_filename (path, NULL), mode);
2671 FILE *
2672 sys_fopen (const char * path, const char * mode)
2674 int fd;
2675 int oflag;
2676 const char * mode_save = mode;
2678 /* Force all file handles to be non-inheritable. This is necessary to
2679 ensure child processes don't unwittingly inherit handles that might
2680 prevent future file access. */
2682 if (mode[0] == 'r')
2683 oflag = O_RDONLY;
2684 else if (mode[0] == 'w' || mode[0] == 'a')
2685 oflag = O_WRONLY | O_CREAT | O_TRUNC;
2686 else
2687 return NULL;
2689 /* Only do simplistic option parsing. */
2690 while (*++mode)
2691 if (mode[0] == '+')
2693 oflag &= ~(O_RDONLY | O_WRONLY);
2694 oflag |= O_RDWR;
2696 else if (mode[0] == 'b')
2698 oflag &= ~O_TEXT;
2699 oflag |= O_BINARY;
2701 else if (mode[0] == 't')
2703 oflag &= ~O_BINARY;
2704 oflag |= O_TEXT;
2706 else break;
2708 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2709 if (fd < 0)
2710 return NULL;
2712 return _fdopen (fd, mode_save);
2715 /* This only works on NTFS volumes, but is useful to have. */
2717 sys_link (const char * old, const char * new)
2719 HANDLE fileh;
2720 int result = -1;
2721 char oldname[MAX_PATH], newname[MAX_PATH];
2723 if (old == NULL || new == NULL)
2725 errno = ENOENT;
2726 return -1;
2729 strcpy (oldname, map_w32_filename (old, NULL));
2730 strcpy (newname, map_w32_filename (new, NULL));
2732 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2733 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2734 if (fileh != INVALID_HANDLE_VALUE)
2736 int wlen;
2738 /* Confusingly, the "alternate" stream name field does not apply
2739 when restoring a hard link, and instead contains the actual
2740 stream data for the link (ie. the name of the link to create).
2741 The WIN32_STREAM_ID structure before the cStreamName field is
2742 the stream header, which is then immediately followed by the
2743 stream data. */
2745 struct {
2746 WIN32_STREAM_ID wid;
2747 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2748 } data;
2750 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2751 data.wid.cStreamName, MAX_PATH);
2752 if (wlen > 0)
2754 LPVOID context = NULL;
2755 DWORD wbytes = 0;
2757 data.wid.dwStreamId = BACKUP_LINK;
2758 data.wid.dwStreamAttributes = 0;
2759 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
2760 data.wid.Size.HighPart = 0;
2761 data.wid.dwStreamNameSize = 0;
2763 if (BackupWrite (fileh, (LPBYTE)&data,
2764 offsetof (WIN32_STREAM_ID, cStreamName)
2765 + data.wid.Size.LowPart,
2766 &wbytes, FALSE, FALSE, &context)
2767 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2769 /* succeeded */
2770 result = 0;
2772 else
2774 /* Should try mapping GetLastError to errno; for now just
2775 indicate a general error (eg. links not supported). */
2776 errno = EINVAL; // perhaps EMLINK?
2780 CloseHandle (fileh);
2782 else
2783 errno = ENOENT;
2785 return result;
2789 sys_mkdir (const char * path)
2791 return _mkdir (map_w32_filename (path, NULL));
2794 /* Because of long name mapping issues, we need to implement this
2795 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2796 a unique name, instead of setting the input template to an empty
2797 string.
2799 Standard algorithm seems to be use pid or tid with a letter on the
2800 front (in place of the 6 X's) and cycle through the letters to find a
2801 unique name. We extend that to allow any reasonable character as the
2802 first of the 6 X's. */
2803 char *
2804 sys_mktemp (char * template)
2806 char * p;
2807 int i;
2808 unsigned uid = GetCurrentThreadId ();
2809 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2811 if (template == NULL)
2812 return NULL;
2813 p = template + strlen (template);
2814 i = 5;
2815 /* replace up to the last 5 X's with uid in decimal */
2816 while (--p >= template && p[0] == 'X' && --i >= 0)
2818 p[0] = '0' + uid % 10;
2819 uid /= 10;
2822 if (i < 0 && p[0] == 'X')
2824 i = 0;
2827 int save_errno = errno;
2828 p[0] = first_char[i];
2829 if (sys_access (template, 0) < 0)
2831 errno = save_errno;
2832 return template;
2835 while (++i < sizeof (first_char));
2838 /* Template is badly formed or else we can't generate a unique name,
2839 so return empty string */
2840 template[0] = 0;
2841 return template;
2845 sys_open (const char * path, int oflag, int mode)
2847 const char* mpath = map_w32_filename (path, NULL);
2848 /* Try to open file without _O_CREAT, to be able to write to hidden
2849 and system files. Force all file handles to be
2850 non-inheritable. */
2851 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2852 if (res >= 0)
2853 return res;
2854 return _open (mpath, oflag | _O_NOINHERIT, mode);
2858 sys_rename (const char * oldname, const char * newname)
2860 BOOL result;
2861 char temp[MAX_PATH];
2863 /* MoveFile on Windows 95 doesn't correctly change the short file name
2864 alias in a number of circumstances (it is not easy to predict when
2865 just by looking at oldname and newname, unfortunately). In these
2866 cases, renaming through a temporary name avoids the problem.
2868 A second problem on Windows 95 is that renaming through a temp name when
2869 newname is uppercase fails (the final long name ends up in
2870 lowercase, although the short alias might be uppercase) UNLESS the
2871 long temp name is not 8.3.
2873 So, on Windows 95 we always rename through a temp name, and we make sure
2874 the temp name has a long extension to ensure correct renaming. */
2876 strcpy (temp, map_w32_filename (oldname, NULL));
2878 if (os_subtype == OS_WIN95)
2880 char * o;
2881 char * p;
2882 int i = 0;
2884 oldname = map_w32_filename (oldname, NULL);
2885 if (o = strrchr (oldname, '\\'))
2886 o++;
2887 else
2888 o = (char *) oldname;
2890 if (p = strrchr (temp, '\\'))
2891 p++;
2892 else
2893 p = temp;
2897 /* Force temp name to require a manufactured 8.3 alias - this
2898 seems to make the second rename work properly. */
2899 sprintf (p, "_.%s.%u", o, i);
2900 i++;
2901 result = rename (oldname, temp);
2903 /* This loop must surely terminate! */
2904 while (result < 0 && errno == EEXIST);
2905 if (result < 0)
2906 return -1;
2909 /* Emulate Unix behavior - newname is deleted if it already exists
2910 (at least if it is a file; don't do this for directories).
2912 Since we mustn't do this if we are just changing the case of the
2913 file name (we would end up deleting the file we are trying to
2914 rename!), we let rename detect if the destination file already
2915 exists - that way we avoid the possible pitfalls of trying to
2916 determine ourselves whether two names really refer to the same
2917 file, which is not always possible in the general case. (Consider
2918 all the permutations of shared or subst'd drives, etc.) */
2920 newname = map_w32_filename (newname, NULL);
2921 result = rename (temp, newname);
2923 if (result < 0
2924 && errno == EEXIST
2925 && _chmod (newname, 0666) == 0
2926 && _unlink (newname) == 0)
2927 result = rename (temp, newname);
2929 return result;
2933 sys_rmdir (const char * path)
2935 return _rmdir (map_w32_filename (path, NULL));
2939 sys_unlink (const char * path)
2941 path = map_w32_filename (path, NULL);
2943 /* On Unix, unlink works without write permission. */
2944 _chmod (path, 0666);
2945 return _unlink (path);
2948 static FILETIME utc_base_ft;
2949 static ULONGLONG utc_base; /* In 100ns units */
2950 static int init = 0;
2952 #define FILETIME_TO_U64(result, ft) \
2953 do { \
2954 ULARGE_INTEGER uiTemp; \
2955 uiTemp.LowPart = (ft).dwLowDateTime; \
2956 uiTemp.HighPart = (ft).dwHighDateTime; \
2957 result = uiTemp.QuadPart; \
2958 } while (0)
2960 static void
2961 initialize_utc_base (void)
2963 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2964 SYSTEMTIME st;
2966 st.wYear = 1970;
2967 st.wMonth = 1;
2968 st.wDay = 1;
2969 st.wHour = 0;
2970 st.wMinute = 0;
2971 st.wSecond = 0;
2972 st.wMilliseconds = 0;
2974 SystemTimeToFileTime (&st, &utc_base_ft);
2975 FILETIME_TO_U64 (utc_base, utc_base_ft);
2978 static time_t
2979 convert_time (FILETIME ft)
2981 ULONGLONG tmp;
2983 if (!init)
2985 initialize_utc_base ();
2986 init = 1;
2989 if (CompareFileTime (&ft, &utc_base_ft) < 0)
2990 return 0;
2992 FILETIME_TO_U64 (tmp, ft);
2993 return (time_t) ((tmp - utc_base) / 10000000L);
2996 static void
2997 convert_from_time_t (time_t time, FILETIME * pft)
2999 ULARGE_INTEGER tmp;
3001 if (!init)
3003 initialize_utc_base ();
3004 init = 1;
3007 /* time in 100ns units since 1-Jan-1601 */
3008 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
3009 pft->dwHighDateTime = tmp.HighPart;
3010 pft->dwLowDateTime = tmp.LowPart;
3013 #if 0
3014 /* No reason to keep this; faking inode values either by hashing or even
3015 using the file index from GetInformationByHandle, is not perfect and
3016 so by default Emacs doesn't use the inode values on Windows.
3017 Instead, we now determine file-truename correctly (except for
3018 possible drive aliasing etc). */
3020 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3021 static unsigned
3022 hashval (const unsigned char * str)
3024 unsigned h = 0;
3025 while (*str)
3027 h = (h << 4) + *str++;
3028 h ^= (h >> 28);
3030 return h;
3033 /* Return the hash value of the canonical pathname, excluding the
3034 drive/UNC header, to get a hopefully unique inode number. */
3035 static DWORD
3036 generate_inode_val (const char * name)
3038 char fullname[ MAX_PATH ];
3039 char * p;
3040 unsigned hash;
3042 /* Get the truly canonical filename, if it exists. (Note: this
3043 doesn't resolve aliasing due to subst commands, or recognise hard
3044 links. */
3045 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3046 abort ();
3048 parse_root (fullname, &p);
3049 /* Normal W32 filesystems are still case insensitive. */
3050 _strlwr (p);
3051 return hashval (p);
3054 #endif
3056 static PSECURITY_DESCRIPTOR
3057 get_file_security_desc (const char *fname)
3059 PSECURITY_DESCRIPTOR psd = NULL;
3060 DWORD sd_len, err;
3061 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3062 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3064 if (!get_file_security (fname, si, psd, 0, &sd_len))
3066 err = GetLastError ();
3067 if (err != ERROR_INSUFFICIENT_BUFFER)
3068 return NULL;
3071 psd = xmalloc (sd_len);
3072 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3074 xfree (psd);
3075 return NULL;
3078 return psd;
3081 static DWORD
3082 get_rid (PSID sid)
3084 unsigned n_subauthorities;
3086 /* Use the last sub-authority value of the RID, the relative
3087 portion of the SID, as user/group ID. */
3088 n_subauthorities = *get_sid_sub_authority_count (sid);
3089 if (n_subauthorities < 1)
3090 return 0; /* the "World" RID */
3091 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3094 /* Caching SID and account values for faster lokup. */
3096 #ifdef __GNUC__
3097 # define FLEXIBLE_ARRAY_MEMBER
3098 #else
3099 # define FLEXIBLE_ARRAY_MEMBER 1
3100 #endif
3102 struct w32_id {
3103 unsigned rid;
3104 struct w32_id *next;
3105 char name[GNLEN+1];
3106 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3109 static struct w32_id *w32_idlist;
3111 static int
3112 w32_cached_id (PSID sid, unsigned *id, char *name)
3114 struct w32_id *tail, *found;
3116 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3118 if (equal_sid ((PSID)tail->sid, sid))
3120 found = tail;
3121 break;
3124 if (found)
3126 *id = found->rid;
3127 strcpy (name, found->name);
3128 return 1;
3130 else
3131 return 0;
3134 static void
3135 w32_add_to_cache (PSID sid, unsigned id, char *name)
3137 DWORD sid_len;
3138 struct w32_id *new_entry;
3140 /* We don't want to leave behind stale cache from when Emacs was
3141 dumped. */
3142 if (initialized)
3144 sid_len = get_length_sid (sid);
3145 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3146 if (new_entry)
3148 new_entry->rid = id;
3149 strcpy (new_entry->name, name);
3150 copy_sid (sid_len, (PSID)new_entry->sid, sid);
3151 new_entry->next = w32_idlist;
3152 w32_idlist = new_entry;
3157 #define UID 1
3158 #define GID 2
3160 static int
3161 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
3162 unsigned *id, char *nm, int what)
3164 PSID sid = NULL;
3165 char machine[MAX_COMPUTERNAME_LENGTH+1];
3166 BOOL dflt;
3167 SID_NAME_USE ignore;
3168 char name[UNLEN+1];
3169 DWORD name_len = sizeof (name);
3170 char domain[1024];
3171 DWORD domain_len = sizeof (domain);
3172 char *mp = NULL;
3173 int use_dflt = 0;
3174 int result;
3176 if (what == UID)
3177 result = get_security_descriptor_owner (psd, &sid, &dflt);
3178 else if (what == GID)
3179 result = get_security_descriptor_group (psd, &sid, &dflt);
3180 else
3181 result = 0;
3183 if (!result || !is_valid_sid (sid))
3184 use_dflt = 1;
3185 else if (!w32_cached_id (sid, id, nm))
3187 /* If FNAME is a UNC, we need to lookup account on the
3188 specified machine. */
3189 if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
3190 && fname[2] != '\0')
3192 const char *s;
3193 char *p;
3195 for (s = fname + 2, p = machine;
3196 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
3197 *p = *s;
3198 *p = '\0';
3199 mp = machine;
3202 if (!lookup_account_sid (mp, sid, name, &name_len,
3203 domain, &domain_len, &ignore)
3204 || name_len > UNLEN+1)
3205 use_dflt = 1;
3206 else
3208 *id = get_rid (sid);
3209 strcpy (nm, name);
3210 w32_add_to_cache (sid, *id, name);
3213 return use_dflt;
3216 static void
3217 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd,
3218 const char *fname,
3219 struct stat *st)
3221 int dflt_usr = 0, dflt_grp = 0;
3223 if (!psd)
3225 dflt_usr = 1;
3226 dflt_grp = 1;
3228 else
3230 if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
3231 dflt_usr = 1;
3232 if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
3233 dflt_grp = 1;
3235 /* Consider files to belong to current user/group, if we cannot get
3236 more accurate information. */
3237 if (dflt_usr)
3239 st->st_uid = dflt_passwd.pw_uid;
3240 strcpy (st->st_uname, dflt_passwd.pw_name);
3242 if (dflt_grp)
3244 st->st_gid = dflt_passwd.pw_gid;
3245 strcpy (st->st_gname, dflt_group.gr_name);
3249 /* Return non-zero if NAME is a potentially slow filesystem. */
3251 is_slow_fs (const char *name)
3253 char drive_root[4];
3254 UINT devtype;
3256 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
3257 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
3258 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
3259 devtype = GetDriveType (NULL); /* use root of current drive */
3260 else
3262 /* GetDriveType needs the root directory of the drive. */
3263 strncpy (drive_root, name, 2);
3264 drive_root[2] = '\\';
3265 drive_root[3] = '\0';
3266 devtype = GetDriveType (drive_root);
3268 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
3271 /* MSVC stat function can't cope with UNC names and has other bugs, so
3272 replace it with our own. This also allows us to calculate consistent
3273 inode values without hacks in the main Emacs code. */
3275 stat (const char * path, struct stat * buf)
3277 char *name, *r;
3278 WIN32_FIND_DATA wfd;
3279 HANDLE fh;
3280 unsigned __int64 fake_inode;
3281 int permission;
3282 int len;
3283 int rootdir = FALSE;
3284 PSECURITY_DESCRIPTOR psd = NULL;
3286 if (path == NULL || buf == NULL)
3288 errno = EFAULT;
3289 return -1;
3292 name = (char *) map_w32_filename (path, &path);
3293 /* Must be valid filename, no wild cards or other invalid
3294 characters. We use _mbspbrk to support multibyte strings that
3295 might look to strpbrk as if they included literal *, ?, and other
3296 characters mentioned below that are disallowed by Windows
3297 filesystems. */
3298 if (_mbspbrk (name, "*?|<>\""))
3300 errno = ENOENT;
3301 return -1;
3304 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3305 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3306 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3308 r[1] = r[2] = '\0';
3311 /* Remove trailing directory separator, unless name is the root
3312 directory of a drive or UNC volume in which case ensure there
3313 is a trailing separator. */
3314 len = strlen (name);
3315 rootdir = (path >= name + len - 1
3316 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3317 name = strcpy (alloca (len + 2), name);
3319 if (is_unc_volume (name))
3321 DWORD attrs = unc_volume_file_attributes (name);
3323 if (attrs == -1)
3324 return -1;
3326 memset (&wfd, 0, sizeof (wfd));
3327 wfd.dwFileAttributes = attrs;
3328 wfd.ftCreationTime = utc_base_ft;
3329 wfd.ftLastAccessTime = utc_base_ft;
3330 wfd.ftLastWriteTime = utc_base_ft;
3331 strcpy (wfd.cFileName, name);
3333 else if (rootdir)
3335 if (!IS_DIRECTORY_SEP (name[len-1]))
3336 strcat (name, "\\");
3337 if (GetDriveType (name) < 2)
3339 errno = ENOENT;
3340 return -1;
3342 memset (&wfd, 0, sizeof (wfd));
3343 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
3344 wfd.ftCreationTime = utc_base_ft;
3345 wfd.ftLastAccessTime = utc_base_ft;
3346 wfd.ftLastWriteTime = utc_base_ft;
3347 strcpy (wfd.cFileName, name);
3349 else
3351 if (IS_DIRECTORY_SEP (name[len-1]))
3352 name[len - 1] = 0;
3354 /* (This is hacky, but helps when doing file completions on
3355 network drives.) Optimize by using information available from
3356 active readdir if possible. */
3357 len = strlen (dir_pathname);
3358 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3359 len--;
3360 if (dir_find_handle != INVALID_HANDLE_VALUE
3361 && strnicmp (name, dir_pathname, len) == 0
3362 && IS_DIRECTORY_SEP (name[len])
3363 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3365 /* This was the last entry returned by readdir. */
3366 wfd = dir_find_data;
3368 else
3370 logon_network_drive (name);
3372 fh = FindFirstFile (name, &wfd);
3373 if (fh == INVALID_HANDLE_VALUE)
3375 errno = ENOENT;
3376 return -1;
3378 FindClose (fh);
3382 if (!(NILP (Vw32_get_true_file_attributes)
3383 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
3384 /* No access rights required to get info. */
3385 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
3386 FILE_FLAG_BACKUP_SEMANTICS, NULL))
3387 != INVALID_HANDLE_VALUE)
3389 /* This is more accurate in terms of gettting the correct number
3390 of links, but is quite slow (it is noticeable when Emacs is
3391 making a list of file name completions). */
3392 BY_HANDLE_FILE_INFORMATION info;
3394 if (GetFileInformationByHandle (fh, &info))
3396 buf->st_nlink = info.nNumberOfLinks;
3397 /* Might as well use file index to fake inode values, but this
3398 is not guaranteed to be unique unless we keep a handle open
3399 all the time (even then there are situations where it is
3400 not unique). Reputedly, there are at most 48 bits of info
3401 (on NTFS, presumably less on FAT). */
3402 fake_inode = info.nFileIndexHigh;
3403 fake_inode <<= 32;
3404 fake_inode += info.nFileIndexLow;
3406 else
3408 buf->st_nlink = 1;
3409 fake_inode = 0;
3412 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3414 buf->st_mode = S_IFDIR;
3416 else
3418 switch (GetFileType (fh))
3420 case FILE_TYPE_DISK:
3421 buf->st_mode = S_IFREG;
3422 break;
3423 case FILE_TYPE_PIPE:
3424 buf->st_mode = S_IFIFO;
3425 break;
3426 case FILE_TYPE_CHAR:
3427 case FILE_TYPE_UNKNOWN:
3428 default:
3429 buf->st_mode = S_IFCHR;
3432 CloseHandle (fh);
3433 psd = get_file_security_desc (name);
3434 get_file_owner_and_group (psd, name, buf);
3436 else
3438 /* Don't bother to make this information more accurate. */
3439 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
3440 S_IFDIR : S_IFREG;
3441 buf->st_nlink = 1;
3442 fake_inode = 0;
3444 get_file_owner_and_group (NULL, name, buf);
3446 xfree (psd);
3448 #if 0
3449 /* Not sure if there is any point in this. */
3450 if (!NILP (Vw32_generate_fake_inodes))
3451 fake_inode = generate_inode_val (name);
3452 else if (fake_inode == 0)
3454 /* For want of something better, try to make everything unique. */
3455 static DWORD gen_num = 0;
3456 fake_inode = ++gen_num;
3458 #endif
3460 /* MSVC defines _ino_t to be short; other libc's might not. */
3461 if (sizeof (buf->st_ino) == 2)
3462 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3463 else
3464 buf->st_ino = fake_inode;
3466 /* volume_info is set indirectly by map_w32_filename */
3467 buf->st_dev = volume_info.serialnum;
3468 buf->st_rdev = volume_info.serialnum;
3470 buf->st_size = wfd.nFileSizeHigh;
3471 buf->st_size <<= 32;
3472 buf->st_size += wfd.nFileSizeLow;
3474 /* Convert timestamps to Unix format. */
3475 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
3476 buf->st_atime = convert_time (wfd.ftLastAccessTime);
3477 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3478 buf->st_ctime = convert_time (wfd.ftCreationTime);
3479 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3481 /* determine rwx permissions */
3482 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3483 permission = S_IREAD;
3484 else
3485 permission = S_IREAD | S_IWRITE;
3487 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3488 permission |= S_IEXEC;
3489 else if (is_exec (name))
3490 permission |= S_IEXEC;
3492 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3494 return 0;
3497 /* Provide fstat and utime as well as stat for consistent handling of
3498 file timestamps. */
3500 fstat (int desc, struct stat * buf)
3502 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3503 BY_HANDLE_FILE_INFORMATION info;
3504 unsigned __int64 fake_inode;
3505 int permission;
3507 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3509 case FILE_TYPE_DISK:
3510 buf->st_mode = S_IFREG;
3511 if (!GetFileInformationByHandle (fh, &info))
3513 errno = EACCES;
3514 return -1;
3516 break;
3517 case FILE_TYPE_PIPE:
3518 buf->st_mode = S_IFIFO;
3519 goto non_disk;
3520 case FILE_TYPE_CHAR:
3521 case FILE_TYPE_UNKNOWN:
3522 default:
3523 buf->st_mode = S_IFCHR;
3524 non_disk:
3525 memset (&info, 0, sizeof (info));
3526 info.dwFileAttributes = 0;
3527 info.ftCreationTime = utc_base_ft;
3528 info.ftLastAccessTime = utc_base_ft;
3529 info.ftLastWriteTime = utc_base_ft;
3532 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3533 buf->st_mode = S_IFDIR;
3535 buf->st_nlink = info.nNumberOfLinks;
3536 /* Might as well use file index to fake inode values, but this
3537 is not guaranteed to be unique unless we keep a handle open
3538 all the time (even then there are situations where it is
3539 not unique). Reputedly, there are at most 48 bits of info
3540 (on NTFS, presumably less on FAT). */
3541 fake_inode = info.nFileIndexHigh;
3542 fake_inode <<= 32;
3543 fake_inode += info.nFileIndexLow;
3545 /* MSVC defines _ino_t to be short; other libc's might not. */
3546 if (sizeof (buf->st_ino) == 2)
3547 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3548 else
3549 buf->st_ino = fake_inode;
3551 /* Consider files to belong to current user.
3552 FIXME: this should use GetSecurityInfo API, but it is only
3553 available for _WIN32_WINNT >= 0x501. */
3554 buf->st_uid = dflt_passwd.pw_uid;
3555 buf->st_gid = dflt_passwd.pw_gid;
3556 strcpy (buf->st_uname, dflt_passwd.pw_name);
3557 strcpy (buf->st_gname, dflt_group.gr_name);
3559 buf->st_dev = info.dwVolumeSerialNumber;
3560 buf->st_rdev = info.dwVolumeSerialNumber;
3562 buf->st_size = info.nFileSizeHigh;
3563 buf->st_size <<= 32;
3564 buf->st_size += info.nFileSizeLow;
3566 /* Convert timestamps to Unix format. */
3567 buf->st_mtime = convert_time (info.ftLastWriteTime);
3568 buf->st_atime = convert_time (info.ftLastAccessTime);
3569 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3570 buf->st_ctime = convert_time (info.ftCreationTime);
3571 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3573 /* determine rwx permissions */
3574 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3575 permission = S_IREAD;
3576 else
3577 permission = S_IREAD | S_IWRITE;
3579 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3580 permission |= S_IEXEC;
3581 else
3583 #if 0 /* no way of knowing the filename */
3584 char * p = strrchr (name, '.');
3585 if (p != NULL &&
3586 (xstrcasecmp (p, ".exe") == 0 ||
3587 xstrcasecmp (p, ".com") == 0 ||
3588 xstrcasecmp (p, ".bat") == 0 ||
3589 xstrcasecmp (p, ".cmd") == 0))
3590 permission |= S_IEXEC;
3591 #endif
3594 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3596 return 0;
3600 utime (const char *name, struct utimbuf *times)
3602 struct utimbuf deftime;
3603 HANDLE fh;
3604 FILETIME mtime;
3605 FILETIME atime;
3607 if (times == NULL)
3609 deftime.modtime = deftime.actime = time (NULL);
3610 times = &deftime;
3613 /* Need write access to set times. */
3614 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
3615 0, OPEN_EXISTING, 0, NULL);
3616 if (fh)
3618 convert_from_time_t (times->actime, &atime);
3619 convert_from_time_t (times->modtime, &mtime);
3620 if (!SetFileTime (fh, NULL, &atime, &mtime))
3622 CloseHandle (fh);
3623 errno = EACCES;
3624 return -1;
3626 CloseHandle (fh);
3628 else
3630 errno = EINVAL;
3631 return -1;
3633 return 0;
3637 /* Symlink-related functions that always fail. Used in fileio.c and in
3638 sysdep.c to avoid #ifdef's. */
3640 symlink (char const *dummy1, char const *dummy2)
3642 errno = ENOSYS;
3643 return -1;
3646 ssize_t
3647 readlink (const char *name, char *dummy1, size_t dummy2)
3649 /* `access' is much faster than `stat' on MS-Windows. */
3650 if (sys_access (name, 0) == 0)
3651 errno = EINVAL;
3652 return -1;
3655 char *
3656 careadlinkat (int fd, char const *filename,
3657 char *buffer, size_t buffer_size,
3658 struct allocator const *alloc,
3659 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
3661 errno = ENOSYS;
3662 return NULL;
3665 ssize_t
3666 careadlinkatcwd (int fd, char const *filename, char *buffer,
3667 size_t buffer_size)
3669 (void) fd;
3670 return readlink (filename, buffer, buffer_size);
3674 /* Support for browsing other processes and their attributes. See
3675 process.c for the Lisp bindings. */
3677 /* Helper wrapper functions. */
3679 static HANDLE WINAPI
3680 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
3682 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
3684 if (g_b_init_create_toolhelp32_snapshot == 0)
3686 g_b_init_create_toolhelp32_snapshot = 1;
3687 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
3688 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3689 "CreateToolhelp32Snapshot");
3691 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
3693 return INVALID_HANDLE_VALUE;
3695 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
3698 static BOOL WINAPI
3699 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
3701 static Process32First_Proc s_pfn_Process32_First = NULL;
3703 if (g_b_init_process32_first == 0)
3705 g_b_init_process32_first = 1;
3706 s_pfn_Process32_First = (Process32First_Proc)
3707 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3708 "Process32First");
3710 if (s_pfn_Process32_First == NULL)
3712 return FALSE;
3714 return (s_pfn_Process32_First (hSnapshot, lppe));
3717 static BOOL WINAPI
3718 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
3720 static Process32Next_Proc s_pfn_Process32_Next = NULL;
3722 if (g_b_init_process32_next == 0)
3724 g_b_init_process32_next = 1;
3725 s_pfn_Process32_Next = (Process32Next_Proc)
3726 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3727 "Process32Next");
3729 if (s_pfn_Process32_Next == NULL)
3731 return FALSE;
3733 return (s_pfn_Process32_Next (hSnapshot, lppe));
3736 static BOOL WINAPI
3737 open_thread_token (HANDLE ThreadHandle,
3738 DWORD DesiredAccess,
3739 BOOL OpenAsSelf,
3740 PHANDLE TokenHandle)
3742 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
3743 HMODULE hm_advapi32 = NULL;
3744 if (is_windows_9x () == TRUE)
3746 SetLastError (ERROR_NOT_SUPPORTED);
3747 return FALSE;
3749 if (g_b_init_open_thread_token == 0)
3751 g_b_init_open_thread_token = 1;
3752 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3753 s_pfn_Open_Thread_Token =
3754 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
3756 if (s_pfn_Open_Thread_Token == NULL)
3758 SetLastError (ERROR_NOT_SUPPORTED);
3759 return FALSE;
3761 return (
3762 s_pfn_Open_Thread_Token (
3763 ThreadHandle,
3764 DesiredAccess,
3765 OpenAsSelf,
3766 TokenHandle)
3770 static BOOL WINAPI
3771 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
3773 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
3774 HMODULE hm_advapi32 = NULL;
3775 if (is_windows_9x () == TRUE)
3777 return FALSE;
3779 if (g_b_init_impersonate_self == 0)
3781 g_b_init_impersonate_self = 1;
3782 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3783 s_pfn_Impersonate_Self =
3784 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
3786 if (s_pfn_Impersonate_Self == NULL)
3788 return FALSE;
3790 return s_pfn_Impersonate_Self (ImpersonationLevel);
3793 static BOOL WINAPI
3794 revert_to_self (void)
3796 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
3797 HMODULE hm_advapi32 = NULL;
3798 if (is_windows_9x () == TRUE)
3800 return FALSE;
3802 if (g_b_init_revert_to_self == 0)
3804 g_b_init_revert_to_self = 1;
3805 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3806 s_pfn_Revert_To_Self =
3807 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
3809 if (s_pfn_Revert_To_Self == NULL)
3811 return FALSE;
3813 return s_pfn_Revert_To_Self ();
3816 static BOOL WINAPI
3817 get_process_memory_info (HANDLE h_proc,
3818 PPROCESS_MEMORY_COUNTERS mem_counters,
3819 DWORD bufsize)
3821 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
3822 HMODULE hm_psapi = NULL;
3823 if (is_windows_9x () == TRUE)
3825 return FALSE;
3827 if (g_b_init_get_process_memory_info == 0)
3829 g_b_init_get_process_memory_info = 1;
3830 hm_psapi = LoadLibrary ("Psapi.dll");
3831 if (hm_psapi)
3832 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
3833 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
3835 if (s_pfn_Get_Process_Memory_Info == NULL)
3837 return FALSE;
3839 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
3842 static BOOL WINAPI
3843 get_process_working_set_size (HANDLE h_proc,
3844 DWORD *minrss,
3845 DWORD *maxrss)
3847 static GetProcessWorkingSetSize_Proc
3848 s_pfn_Get_Process_Working_Set_Size = NULL;
3850 if (is_windows_9x () == TRUE)
3852 return FALSE;
3854 if (g_b_init_get_process_working_set_size == 0)
3856 g_b_init_get_process_working_set_size = 1;
3857 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
3858 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3859 "GetProcessWorkingSetSize");
3861 if (s_pfn_Get_Process_Working_Set_Size == NULL)
3863 return FALSE;
3865 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
3868 static BOOL WINAPI
3869 global_memory_status (MEMORYSTATUS *buf)
3871 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
3873 if (is_windows_9x () == TRUE)
3875 return FALSE;
3877 if (g_b_init_global_memory_status == 0)
3879 g_b_init_global_memory_status = 1;
3880 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
3881 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3882 "GlobalMemoryStatus");
3884 if (s_pfn_Global_Memory_Status == NULL)
3886 return FALSE;
3888 return s_pfn_Global_Memory_Status (buf);
3891 static BOOL WINAPI
3892 global_memory_status_ex (MEMORY_STATUS_EX *buf)
3894 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
3896 if (is_windows_9x () == TRUE)
3898 return FALSE;
3900 if (g_b_init_global_memory_status_ex == 0)
3902 g_b_init_global_memory_status_ex = 1;
3903 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
3904 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3905 "GlobalMemoryStatusEx");
3907 if (s_pfn_Global_Memory_Status_Ex == NULL)
3909 return FALSE;
3911 return s_pfn_Global_Memory_Status_Ex (buf);
3914 Lisp_Object
3915 list_system_processes (void)
3917 struct gcpro gcpro1;
3918 Lisp_Object proclist = Qnil;
3919 HANDLE h_snapshot;
3921 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
3923 if (h_snapshot != INVALID_HANDLE_VALUE)
3925 PROCESSENTRY32 proc_entry;
3926 DWORD proc_id;
3927 BOOL res;
3929 GCPRO1 (proclist);
3931 proc_entry.dwSize = sizeof (PROCESSENTRY32);
3932 for (res = process32_first (h_snapshot, &proc_entry); res;
3933 res = process32_next (h_snapshot, &proc_entry))
3935 proc_id = proc_entry.th32ProcessID;
3936 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
3939 CloseHandle (h_snapshot);
3940 UNGCPRO;
3941 proclist = Fnreverse (proclist);
3944 return proclist;
3947 static int
3948 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
3950 TOKEN_PRIVILEGES priv;
3951 DWORD priv_size = sizeof (priv);
3952 DWORD opriv_size = sizeof (*old_priv);
3953 HANDLE h_token = NULL;
3954 HANDLE h_thread = GetCurrentThread ();
3955 int ret_val = 0;
3956 BOOL res;
3958 res = open_thread_token (h_thread,
3959 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3960 FALSE, &h_token);
3961 if (!res && GetLastError () == ERROR_NO_TOKEN)
3963 if (impersonate_self (SecurityImpersonation))
3964 res = open_thread_token (h_thread,
3965 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3966 FALSE, &h_token);
3968 if (res)
3970 priv.PrivilegeCount = 1;
3971 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
3972 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
3973 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
3974 old_priv, &opriv_size)
3975 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3976 ret_val = 1;
3978 if (h_token)
3979 CloseHandle (h_token);
3981 return ret_val;
3984 static int
3985 restore_privilege (TOKEN_PRIVILEGES *priv)
3987 DWORD priv_size = sizeof (*priv);
3988 HANDLE h_token = NULL;
3989 int ret_val = 0;
3991 if (open_thread_token (GetCurrentThread (),
3992 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3993 FALSE, &h_token))
3995 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
3996 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3997 ret_val = 1;
3999 if (h_token)
4000 CloseHandle (h_token);
4002 return ret_val;
4005 static Lisp_Object
4006 ltime (long time_sec, long time_usec)
4008 return list3 (make_number ((time_sec >> 16) & 0xffff),
4009 make_number (time_sec & 0xffff),
4010 make_number (time_usec));
4013 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
4015 static int
4016 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
4017 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
4018 double *pcpu)
4020 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
4021 ULONGLONG tem1, tem2, tem3, tem;
4023 if (!h_proc
4024 || !get_process_times_fn
4025 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
4026 &ft_kernel, &ft_user))
4027 return 0;
4029 GetSystemTimeAsFileTime (&ft_current);
4031 FILETIME_TO_U64 (tem1, ft_kernel);
4032 tem1 /= 10L;
4033 *stime = U64_TO_LISP_TIME (tem1);
4035 FILETIME_TO_U64 (tem2, ft_user);
4036 tem2 /= 10L;
4037 *utime = U64_TO_LISP_TIME (tem2);
4039 tem3 = tem1 + tem2;
4040 *ttime = U64_TO_LISP_TIME (tem3);
4042 FILETIME_TO_U64 (tem, ft_creation);
4043 /* Process no 4 (System) returns zero creation time. */
4044 if (tem)
4045 tem = (tem - utc_base) / 10L;
4046 *ctime = U64_TO_LISP_TIME (tem);
4048 if (tem)
4050 FILETIME_TO_U64 (tem3, ft_current);
4051 tem = (tem3 - utc_base) / 10L - tem;
4053 *etime = U64_TO_LISP_TIME (tem);
4055 if (tem)
4057 *pcpu = 100.0 * (tem1 + tem2) / tem;
4058 if (*pcpu > 100)
4059 *pcpu = 100.0;
4061 else
4062 *pcpu = 0;
4064 return 1;
4067 Lisp_Object
4068 system_process_attributes (Lisp_Object pid)
4070 struct gcpro gcpro1, gcpro2, gcpro3;
4071 Lisp_Object attrs = Qnil;
4072 Lisp_Object cmd_str, decoded_cmd, tem;
4073 HANDLE h_snapshot, h_proc;
4074 DWORD proc_id;
4075 int found_proc = 0;
4076 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
4077 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
4078 DWORD glength = sizeof (gname);
4079 HANDLE token = NULL;
4080 SID_NAME_USE user_type;
4081 unsigned char *buf = NULL;
4082 DWORD blen = 0;
4083 TOKEN_USER user_token;
4084 TOKEN_PRIMARY_GROUP group_token;
4085 unsigned euid;
4086 unsigned egid;
4087 PROCESS_MEMORY_COUNTERS mem;
4088 PROCESS_MEMORY_COUNTERS_EX mem_ex;
4089 DWORD minrss, maxrss;
4090 MEMORYSTATUS memst;
4091 MEMORY_STATUS_EX memstex;
4092 double totphys = 0.0;
4093 Lisp_Object ctime, stime, utime, etime, ttime;
4094 double pcpu;
4095 BOOL result = FALSE;
4097 CHECK_NUMBER_OR_FLOAT (pid);
4098 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
4100 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4102 GCPRO3 (attrs, decoded_cmd, tem);
4104 if (h_snapshot != INVALID_HANDLE_VALUE)
4106 PROCESSENTRY32 pe;
4107 BOOL res;
4109 pe.dwSize = sizeof (PROCESSENTRY32);
4110 for (res = process32_first (h_snapshot, &pe); res;
4111 res = process32_next (h_snapshot, &pe))
4113 if (proc_id == pe.th32ProcessID)
4115 if (proc_id == 0)
4116 decoded_cmd = build_string ("Idle");
4117 else
4119 /* Decode the command name from locale-specific
4120 encoding. */
4121 cmd_str = make_unibyte_string (pe.szExeFile,
4122 strlen (pe.szExeFile));
4123 decoded_cmd =
4124 code_convert_string_norecord (cmd_str,
4125 Vlocale_coding_system, 0);
4127 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
4128 attrs = Fcons (Fcons (Qppid,
4129 make_fixnum_or_float (pe.th32ParentProcessID)),
4130 attrs);
4131 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
4132 attrs);
4133 attrs = Fcons (Fcons (Qthcount,
4134 make_fixnum_or_float (pe.cntThreads)),
4135 attrs);
4136 found_proc = 1;
4137 break;
4141 CloseHandle (h_snapshot);
4144 if (!found_proc)
4146 UNGCPRO;
4147 return Qnil;
4150 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4151 FALSE, proc_id);
4152 /* If we were denied a handle to the process, try again after
4153 enabling the SeDebugPrivilege in our process. */
4154 if (!h_proc)
4156 TOKEN_PRIVILEGES priv_current;
4158 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
4160 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4161 FALSE, proc_id);
4162 restore_privilege (&priv_current);
4163 revert_to_self ();
4166 if (h_proc)
4168 result = open_process_token (h_proc, TOKEN_QUERY, &token);
4169 if (result)
4171 result = get_token_information (token, TokenUser, NULL, 0, &blen);
4172 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4174 buf = xmalloc (blen);
4175 result = get_token_information (token, TokenUser,
4176 (LPVOID)buf, blen, &needed);
4177 if (result)
4179 memcpy (&user_token, buf, sizeof (user_token));
4180 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
4182 euid = get_rid (user_token.User.Sid);
4183 result = lookup_account_sid (NULL, user_token.User.Sid,
4184 uname, &ulength,
4185 domain, &dlength,
4186 &user_type);
4187 if (result)
4188 w32_add_to_cache (user_token.User.Sid, euid, uname);
4189 else
4191 strcpy (uname, "unknown");
4192 result = TRUE;
4195 ulength = strlen (uname);
4199 if (result)
4201 /* Determine a reasonable euid and gid values. */
4202 if (xstrcasecmp ("administrator", uname) == 0)
4204 euid = 500; /* well-known Administrator uid */
4205 egid = 513; /* well-known None gid */
4207 else
4209 /* Get group id and name. */
4210 result = get_token_information (token, TokenPrimaryGroup,
4211 (LPVOID)buf, blen, &needed);
4212 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4214 buf = xrealloc (buf, blen = needed);
4215 result = get_token_information (token, TokenPrimaryGroup,
4216 (LPVOID)buf, blen, &needed);
4218 if (result)
4220 memcpy (&group_token, buf, sizeof (group_token));
4221 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
4223 egid = get_rid (group_token.PrimaryGroup);
4224 dlength = sizeof (domain);
4225 result =
4226 lookup_account_sid (NULL, group_token.PrimaryGroup,
4227 gname, &glength, NULL, &dlength,
4228 &user_type);
4229 if (result)
4230 w32_add_to_cache (group_token.PrimaryGroup,
4231 egid, gname);
4232 else
4234 strcpy (gname, "None");
4235 result = TRUE;
4238 glength = strlen (gname);
4242 xfree (buf);
4244 if (!result)
4246 if (!is_windows_9x ())
4248 /* We couldn't open the process token, presumably because of
4249 insufficient access rights. Assume this process is run
4250 by the system. */
4251 strcpy (uname, "SYSTEM");
4252 strcpy (gname, "None");
4253 euid = 18; /* SYSTEM */
4254 egid = 513; /* None */
4255 glength = strlen (gname);
4256 ulength = strlen (uname);
4258 /* If we are running under Windows 9X, where security calls are
4259 not supported, we assume all processes are run by the current
4260 user. */
4261 else if (GetUserName (uname, &ulength))
4263 if (xstrcasecmp ("administrator", uname) == 0)
4264 euid = 0;
4265 else
4266 euid = 123;
4267 egid = euid;
4268 strcpy (gname, "None");
4269 glength = strlen (gname);
4270 ulength = strlen (uname);
4272 else
4274 euid = 123;
4275 egid = 123;
4276 strcpy (uname, "administrator");
4277 ulength = strlen (uname);
4278 strcpy (gname, "None");
4279 glength = strlen (gname);
4281 if (token)
4282 CloseHandle (token);
4285 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
4286 tem = make_unibyte_string (uname, ulength);
4287 attrs = Fcons (Fcons (Quser,
4288 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4289 attrs);
4290 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
4291 tem = make_unibyte_string (gname, glength);
4292 attrs = Fcons (Fcons (Qgroup,
4293 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4294 attrs);
4296 if (global_memory_status_ex (&memstex))
4297 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4298 totphys = memstex.ullTotalPhys / 1024.0;
4299 #else
4300 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4301 double, so we need to do this for it... */
4303 DWORD tot_hi = memstex.ullTotalPhys >> 32;
4304 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
4305 DWORD tot_lo = memstex.ullTotalPhys % 1024;
4307 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
4309 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4310 else if (global_memory_status (&memst))
4311 totphys = memst.dwTotalPhys / 1024.0;
4313 if (h_proc
4314 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
4315 sizeof (mem_ex)))
4317 DWORD rss = mem_ex.WorkingSetSize / 1024;
4319 attrs = Fcons (Fcons (Qmajflt,
4320 make_fixnum_or_float (mem_ex.PageFaultCount)),
4321 attrs);
4322 attrs = Fcons (Fcons (Qvsize,
4323 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
4324 attrs);
4325 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4326 if (totphys)
4327 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4329 else if (h_proc
4330 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
4332 DWORD rss = mem_ex.WorkingSetSize / 1024;
4334 attrs = Fcons (Fcons (Qmajflt,
4335 make_fixnum_or_float (mem.PageFaultCount)),
4336 attrs);
4337 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4338 if (totphys)
4339 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4341 else if (h_proc
4342 && get_process_working_set_size (h_proc, &minrss, &maxrss))
4344 DWORD rss = maxrss / 1024;
4346 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
4347 if (totphys)
4348 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4351 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
4353 attrs = Fcons (Fcons (Qutime, utime), attrs);
4354 attrs = Fcons (Fcons (Qstime, stime), attrs);
4355 attrs = Fcons (Fcons (Qtime, ttime), attrs);
4356 attrs = Fcons (Fcons (Qstart, ctime), attrs);
4357 attrs = Fcons (Fcons (Qetime, etime), attrs);
4358 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
4361 /* FIXME: Retrieve command line by walking the PEB of the process. */
4363 if (h_proc)
4364 CloseHandle (h_proc);
4365 UNGCPRO;
4366 return attrs;
4370 /* Wrappers for winsock functions to map between our file descriptors
4371 and winsock's handles; also set h_errno for convenience.
4373 To allow Emacs to run on systems which don't have winsock support
4374 installed, we dynamically link to winsock on startup if present, and
4375 otherwise provide the minimum necessary functionality
4376 (eg. gethostname). */
4378 /* function pointers for relevant socket functions */
4379 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
4380 void (PASCAL *pfn_WSASetLastError) (int iError);
4381 int (PASCAL *pfn_WSAGetLastError) (void);
4382 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
4383 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
4384 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
4385 int (PASCAL *pfn_socket) (int af, int type, int protocol);
4386 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
4387 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
4388 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
4389 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
4390 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
4391 int (PASCAL *pfn_closesocket) (SOCKET s);
4392 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
4393 int (PASCAL *pfn_WSACleanup) (void);
4395 u_short (PASCAL *pfn_htons) (u_short hostshort);
4396 u_short (PASCAL *pfn_ntohs) (u_short netshort);
4397 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
4398 int (PASCAL *pfn_gethostname) (char * name, int namelen);
4399 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
4400 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
4401 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
4402 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
4403 const char * optval, int optlen);
4404 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
4405 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
4406 int * namelen);
4407 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
4408 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
4409 struct sockaddr * from, int * fromlen);
4410 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
4411 const struct sockaddr * to, int tolen);
4413 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4414 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
4415 #ifndef HANDLE_FLAG_INHERIT
4416 #define HANDLE_FLAG_INHERIT 1
4417 #endif
4419 HANDLE winsock_lib;
4420 static int winsock_inuse;
4422 BOOL
4423 term_winsock (void)
4425 if (winsock_lib != NULL && winsock_inuse == 0)
4427 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4428 after WSAStartup returns successfully, but it seems reasonable
4429 to allow unloading winsock anyway in that case. */
4430 if (pfn_WSACleanup () == 0 ||
4431 pfn_WSAGetLastError () == WSAENETDOWN)
4433 if (FreeLibrary (winsock_lib))
4434 winsock_lib = NULL;
4435 return TRUE;
4438 return FALSE;
4441 BOOL
4442 init_winsock (int load_now)
4444 WSADATA winsockData;
4446 if (winsock_lib != NULL)
4447 return TRUE;
4449 pfn_SetHandleInformation
4450 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4451 "SetHandleInformation");
4453 winsock_lib = LoadLibrary ("Ws2_32.dll");
4455 if (winsock_lib != NULL)
4457 /* dynamically link to socket functions */
4459 #define LOAD_PROC(fn) \
4460 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4461 goto fail;
4463 LOAD_PROC (WSAStartup);
4464 LOAD_PROC (WSASetLastError);
4465 LOAD_PROC (WSAGetLastError);
4466 LOAD_PROC (WSAEventSelect);
4467 LOAD_PROC (WSACreateEvent);
4468 LOAD_PROC (WSACloseEvent);
4469 LOAD_PROC (socket);
4470 LOAD_PROC (bind);
4471 LOAD_PROC (connect);
4472 LOAD_PROC (ioctlsocket);
4473 LOAD_PROC (recv);
4474 LOAD_PROC (send);
4475 LOAD_PROC (closesocket);
4476 LOAD_PROC (shutdown);
4477 LOAD_PROC (htons);
4478 LOAD_PROC (ntohs);
4479 LOAD_PROC (inet_addr);
4480 LOAD_PROC (gethostname);
4481 LOAD_PROC (gethostbyname);
4482 LOAD_PROC (getservbyname);
4483 LOAD_PROC (getpeername);
4484 LOAD_PROC (WSACleanup);
4485 LOAD_PROC (setsockopt);
4486 LOAD_PROC (listen);
4487 LOAD_PROC (getsockname);
4488 LOAD_PROC (accept);
4489 LOAD_PROC (recvfrom);
4490 LOAD_PROC (sendto);
4491 #undef LOAD_PROC
4493 /* specify version 1.1 of winsock */
4494 if (pfn_WSAStartup (0x101, &winsockData) == 0)
4496 if (winsockData.wVersion != 0x101)
4497 goto fail;
4499 if (!load_now)
4501 /* Report that winsock exists and is usable, but leave
4502 socket functions disabled. I am assuming that calling
4503 WSAStartup does not require any network interaction,
4504 and in particular does not cause or require a dial-up
4505 connection to be established. */
4507 pfn_WSACleanup ();
4508 FreeLibrary (winsock_lib);
4509 winsock_lib = NULL;
4511 winsock_inuse = 0;
4512 return TRUE;
4515 fail:
4516 FreeLibrary (winsock_lib);
4517 winsock_lib = NULL;
4520 return FALSE;
4524 int h_errno = 0;
4526 /* function to set h_errno for compatibility; map winsock error codes to
4527 normal system codes where they overlap (non-overlapping definitions
4528 are already in <sys/socket.h> */
4529 static void
4530 set_errno (void)
4532 if (winsock_lib == NULL)
4533 h_errno = EINVAL;
4534 else
4535 h_errno = pfn_WSAGetLastError ();
4537 switch (h_errno)
4539 case WSAEACCES: h_errno = EACCES; break;
4540 case WSAEBADF: h_errno = EBADF; break;
4541 case WSAEFAULT: h_errno = EFAULT; break;
4542 case WSAEINTR: h_errno = EINTR; break;
4543 case WSAEINVAL: h_errno = EINVAL; break;
4544 case WSAEMFILE: h_errno = EMFILE; break;
4545 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
4546 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
4548 errno = h_errno;
4551 static void
4552 check_errno (void)
4554 if (h_errno == 0 && winsock_lib != NULL)
4555 pfn_WSASetLastError (0);
4558 /* Extend strerror to handle the winsock-specific error codes. */
4559 struct {
4560 int errnum;
4561 char * msg;
4562 } _wsa_errlist[] = {
4563 {WSAEINTR , "Interrupted function call"},
4564 {WSAEBADF , "Bad file descriptor"},
4565 {WSAEACCES , "Permission denied"},
4566 {WSAEFAULT , "Bad address"},
4567 {WSAEINVAL , "Invalid argument"},
4568 {WSAEMFILE , "Too many open files"},
4570 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
4571 {WSAEINPROGRESS , "Operation now in progress"},
4572 {WSAEALREADY , "Operation already in progress"},
4573 {WSAENOTSOCK , "Socket operation on non-socket"},
4574 {WSAEDESTADDRREQ , "Destination address required"},
4575 {WSAEMSGSIZE , "Message too long"},
4576 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
4577 {WSAENOPROTOOPT , "Bad protocol option"},
4578 {WSAEPROTONOSUPPORT , "Protocol not supported"},
4579 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
4580 {WSAEOPNOTSUPP , "Operation not supported"},
4581 {WSAEPFNOSUPPORT , "Protocol family not supported"},
4582 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
4583 {WSAEADDRINUSE , "Address already in use"},
4584 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
4585 {WSAENETDOWN , "Network is down"},
4586 {WSAENETUNREACH , "Network is unreachable"},
4587 {WSAENETRESET , "Network dropped connection on reset"},
4588 {WSAECONNABORTED , "Software caused connection abort"},
4589 {WSAECONNRESET , "Connection reset by peer"},
4590 {WSAENOBUFS , "No buffer space available"},
4591 {WSAEISCONN , "Socket is already connected"},
4592 {WSAENOTCONN , "Socket is not connected"},
4593 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
4594 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
4595 {WSAETIMEDOUT , "Connection timed out"},
4596 {WSAECONNREFUSED , "Connection refused"},
4597 {WSAELOOP , "Network loop"}, /* not sure */
4598 {WSAENAMETOOLONG , "Name is too long"},
4599 {WSAEHOSTDOWN , "Host is down"},
4600 {WSAEHOSTUNREACH , "No route to host"},
4601 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
4602 {WSAEPROCLIM , "Too many processes"},
4603 {WSAEUSERS , "Too many users"}, /* not sure */
4604 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
4605 {WSAESTALE , "Data is stale"}, /* not sure */
4606 {WSAEREMOTE , "Remote error"}, /* not sure */
4608 {WSASYSNOTREADY , "Network subsystem is unavailable"},
4609 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
4610 {WSANOTINITIALISED , "Winsock not initialized successfully"},
4611 {WSAEDISCON , "Graceful shutdown in progress"},
4612 #ifdef WSAENOMORE
4613 {WSAENOMORE , "No more operations allowed"}, /* not sure */
4614 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
4615 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
4616 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
4617 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
4618 {WSASYSCALLFAILURE , "System call failure"},
4619 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
4620 {WSATYPE_NOT_FOUND , "Class type not found"},
4621 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
4622 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
4623 {WSAEREFUSED , "Operation refused"}, /* not sure */
4624 #endif
4626 {WSAHOST_NOT_FOUND , "Host not found"},
4627 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
4628 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
4629 {WSANO_DATA , "Valid name, no data record of requested type"},
4631 {-1, NULL}
4634 char *
4635 sys_strerror (int error_no)
4637 int i;
4638 static char unknown_msg[40];
4640 if (error_no >= 0 && error_no < sys_nerr)
4641 return sys_errlist[error_no];
4643 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
4644 if (_wsa_errlist[i].errnum == error_no)
4645 return _wsa_errlist[i].msg;
4647 sprintf (unknown_msg, "Unidentified error: %d", error_no);
4648 return unknown_msg;
4651 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4652 but I believe the method of keeping the socket handle separate (and
4653 insuring it is not inheritable) is the correct one. */
4655 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4657 static int socket_to_fd (SOCKET s);
4660 sys_socket (int af, int type, int protocol)
4662 SOCKET s;
4664 if (winsock_lib == NULL)
4666 h_errno = ENETDOWN;
4667 return INVALID_SOCKET;
4670 check_errno ();
4672 /* call the real socket function */
4673 s = pfn_socket (af, type, protocol);
4675 if (s != INVALID_SOCKET)
4676 return socket_to_fd (s);
4678 set_errno ();
4679 return -1;
4682 /* Convert a SOCKET to a file descriptor. */
4683 static int
4684 socket_to_fd (SOCKET s)
4686 int fd;
4687 child_process * cp;
4689 /* Although under NT 3.5 _open_osfhandle will accept a socket
4690 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4691 that does not work under NT 3.1. However, we can get the same
4692 effect by using a backdoor function to replace an existing
4693 descriptor handle with the one we want. */
4695 /* allocate a file descriptor (with appropriate flags) */
4696 fd = _open ("NUL:", _O_RDWR);
4697 if (fd >= 0)
4699 /* Make a non-inheritable copy of the socket handle. Note
4700 that it is possible that sockets aren't actually kernel
4701 handles, which appears to be the case on Windows 9x when
4702 the MS Proxy winsock client is installed. */
4704 /* Apparently there is a bug in NT 3.51 with some service
4705 packs, which prevents using DuplicateHandle to make a
4706 socket handle non-inheritable (causes WSACleanup to
4707 hang). The work-around is to use SetHandleInformation
4708 instead if it is available and implemented. */
4709 if (pfn_SetHandleInformation)
4711 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
4713 else
4715 HANDLE parent = GetCurrentProcess ();
4716 HANDLE new_s = INVALID_HANDLE_VALUE;
4718 if (DuplicateHandle (parent,
4719 (HANDLE) s,
4720 parent,
4721 &new_s,
4723 FALSE,
4724 DUPLICATE_SAME_ACCESS))
4726 /* It is possible that DuplicateHandle succeeds even
4727 though the socket wasn't really a kernel handle,
4728 because a real handle has the same value. So
4729 test whether the new handle really is a socket. */
4730 long nonblocking = 0;
4731 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
4733 pfn_closesocket (s);
4734 s = (SOCKET) new_s;
4736 else
4738 CloseHandle (new_s);
4743 fd_info[fd].hnd = (HANDLE) s;
4745 /* set our own internal flags */
4746 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
4748 cp = new_child ();
4749 if (cp)
4751 cp->fd = fd;
4752 cp->status = STATUS_READ_ACKNOWLEDGED;
4754 /* attach child_process to fd_info */
4755 if (fd_info[ fd ].cp != NULL)
4757 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
4758 abort ();
4761 fd_info[ fd ].cp = cp;
4763 /* success! */
4764 winsock_inuse++; /* count open sockets */
4765 return fd;
4768 /* clean up */
4769 _close (fd);
4771 pfn_closesocket (s);
4772 h_errno = EMFILE;
4773 return -1;
4777 sys_bind (int s, const struct sockaddr * addr, int namelen)
4779 if (winsock_lib == NULL)
4781 h_errno = ENOTSOCK;
4782 return SOCKET_ERROR;
4785 check_errno ();
4786 if (fd_info[s].flags & FILE_SOCKET)
4788 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
4789 if (rc == SOCKET_ERROR)
4790 set_errno ();
4791 return rc;
4793 h_errno = ENOTSOCK;
4794 return SOCKET_ERROR;
4798 sys_connect (int s, const struct sockaddr * name, int namelen)
4800 if (winsock_lib == NULL)
4802 h_errno = ENOTSOCK;
4803 return SOCKET_ERROR;
4806 check_errno ();
4807 if (fd_info[s].flags & FILE_SOCKET)
4809 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
4810 if (rc == SOCKET_ERROR)
4811 set_errno ();
4812 return rc;
4814 h_errno = ENOTSOCK;
4815 return SOCKET_ERROR;
4818 u_short
4819 sys_htons (u_short hostshort)
4821 return (winsock_lib != NULL) ?
4822 pfn_htons (hostshort) : hostshort;
4825 u_short
4826 sys_ntohs (u_short netshort)
4828 return (winsock_lib != NULL) ?
4829 pfn_ntohs (netshort) : netshort;
4832 unsigned long
4833 sys_inet_addr (const char * cp)
4835 return (winsock_lib != NULL) ?
4836 pfn_inet_addr (cp) : INADDR_NONE;
4840 sys_gethostname (char * name, int namelen)
4842 if (winsock_lib != NULL)
4843 return pfn_gethostname (name, namelen);
4845 if (namelen > MAX_COMPUTERNAME_LENGTH)
4846 return !GetComputerName (name, (DWORD *)&namelen);
4848 h_errno = EFAULT;
4849 return SOCKET_ERROR;
4852 struct hostent *
4853 sys_gethostbyname (const char * name)
4855 struct hostent * host;
4857 if (winsock_lib == NULL)
4859 h_errno = ENETDOWN;
4860 return NULL;
4863 check_errno ();
4864 host = pfn_gethostbyname (name);
4865 if (!host)
4866 set_errno ();
4867 return host;
4870 struct servent *
4871 sys_getservbyname (const char * name, const char * proto)
4873 struct servent * serv;
4875 if (winsock_lib == NULL)
4877 h_errno = ENETDOWN;
4878 return NULL;
4881 check_errno ();
4882 serv = pfn_getservbyname (name, proto);
4883 if (!serv)
4884 set_errno ();
4885 return serv;
4889 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
4891 if (winsock_lib == NULL)
4893 h_errno = ENETDOWN;
4894 return SOCKET_ERROR;
4897 check_errno ();
4898 if (fd_info[s].flags & FILE_SOCKET)
4900 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
4901 if (rc == SOCKET_ERROR)
4902 set_errno ();
4903 return rc;
4905 h_errno = ENOTSOCK;
4906 return SOCKET_ERROR;
4910 sys_shutdown (int s, int how)
4912 if (winsock_lib == NULL)
4914 h_errno = ENETDOWN;
4915 return SOCKET_ERROR;
4918 check_errno ();
4919 if (fd_info[s].flags & FILE_SOCKET)
4921 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
4922 if (rc == SOCKET_ERROR)
4923 set_errno ();
4924 return rc;
4926 h_errno = ENOTSOCK;
4927 return SOCKET_ERROR;
4931 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
4933 if (winsock_lib == NULL)
4935 h_errno = ENETDOWN;
4936 return SOCKET_ERROR;
4939 check_errno ();
4940 if (fd_info[s].flags & FILE_SOCKET)
4942 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
4943 (const char *)optval, optlen);
4944 if (rc == SOCKET_ERROR)
4945 set_errno ();
4946 return rc;
4948 h_errno = ENOTSOCK;
4949 return SOCKET_ERROR;
4953 sys_listen (int s, int backlog)
4955 if (winsock_lib == NULL)
4957 h_errno = ENETDOWN;
4958 return SOCKET_ERROR;
4961 check_errno ();
4962 if (fd_info[s].flags & FILE_SOCKET)
4964 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
4965 if (rc == SOCKET_ERROR)
4966 set_errno ();
4967 else
4968 fd_info[s].flags |= FILE_LISTEN;
4969 return rc;
4971 h_errno = ENOTSOCK;
4972 return SOCKET_ERROR;
4976 sys_getsockname (int s, struct sockaddr * name, int * namelen)
4978 if (winsock_lib == NULL)
4980 h_errno = ENETDOWN;
4981 return SOCKET_ERROR;
4984 check_errno ();
4985 if (fd_info[s].flags & FILE_SOCKET)
4987 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
4988 if (rc == SOCKET_ERROR)
4989 set_errno ();
4990 return rc;
4992 h_errno = ENOTSOCK;
4993 return SOCKET_ERROR;
4997 sys_accept (int s, struct sockaddr * addr, int * addrlen)
4999 if (winsock_lib == NULL)
5001 h_errno = ENETDOWN;
5002 return -1;
5005 check_errno ();
5006 if (fd_info[s].flags & FILE_LISTEN)
5008 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
5009 int fd = -1;
5010 if (t == INVALID_SOCKET)
5011 set_errno ();
5012 else
5013 fd = socket_to_fd (t);
5015 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
5016 ResetEvent (fd_info[s].cp->char_avail);
5017 return fd;
5019 h_errno = ENOTSOCK;
5020 return -1;
5024 sys_recvfrom (int s, char * buf, int len, int flags,
5025 struct sockaddr * from, int * fromlen)
5027 if (winsock_lib == NULL)
5029 h_errno = ENETDOWN;
5030 return SOCKET_ERROR;
5033 check_errno ();
5034 if (fd_info[s].flags & FILE_SOCKET)
5036 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
5037 if (rc == SOCKET_ERROR)
5038 set_errno ();
5039 return rc;
5041 h_errno = ENOTSOCK;
5042 return SOCKET_ERROR;
5046 sys_sendto (int s, const char * buf, int len, int flags,
5047 const struct sockaddr * to, int tolen)
5049 if (winsock_lib == NULL)
5051 h_errno = ENETDOWN;
5052 return SOCKET_ERROR;
5055 check_errno ();
5056 if (fd_info[s].flags & FILE_SOCKET)
5058 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
5059 if (rc == SOCKET_ERROR)
5060 set_errno ();
5061 return rc;
5063 h_errno = ENOTSOCK;
5064 return SOCKET_ERROR;
5067 /* Windows does not have an fcntl function. Provide an implementation
5068 solely for making sockets non-blocking. */
5070 fcntl (int s, int cmd, int options)
5072 if (winsock_lib == NULL)
5074 h_errno = ENETDOWN;
5075 return -1;
5078 check_errno ();
5079 if (fd_info[s].flags & FILE_SOCKET)
5081 if (cmd == F_SETFL && options == O_NDELAY)
5083 unsigned long nblock = 1;
5084 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
5085 if (rc == SOCKET_ERROR)
5086 set_errno ();
5087 /* Keep track of the fact that we set this to non-blocking. */
5088 fd_info[s].flags |= FILE_NDELAY;
5089 return rc;
5091 else
5093 h_errno = EINVAL;
5094 return SOCKET_ERROR;
5097 h_errno = ENOTSOCK;
5098 return SOCKET_ERROR;
5102 /* Shadow main io functions: we need to handle pipes and sockets more
5103 intelligently, and implement non-blocking mode as well. */
5106 sys_close (int fd)
5108 int rc;
5110 if (fd < 0)
5112 errno = EBADF;
5113 return -1;
5116 if (fd < MAXDESC && fd_info[fd].cp)
5118 child_process * cp = fd_info[fd].cp;
5120 fd_info[fd].cp = NULL;
5122 if (CHILD_ACTIVE (cp))
5124 /* if last descriptor to active child_process then cleanup */
5125 int i;
5126 for (i = 0; i < MAXDESC; i++)
5128 if (i == fd)
5129 continue;
5130 if (fd_info[i].cp == cp)
5131 break;
5133 if (i == MAXDESC)
5135 if (fd_info[fd].flags & FILE_SOCKET)
5137 if (winsock_lib == NULL) abort ();
5139 pfn_shutdown (SOCK_HANDLE (fd), 2);
5140 rc = pfn_closesocket (SOCK_HANDLE (fd));
5142 winsock_inuse--; /* count open sockets */
5144 delete_child (cp);
5149 /* Note that sockets do not need special treatment here (at least on
5150 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5151 closesocket is equivalent to CloseHandle, which is to be expected
5152 because socket handles are fully fledged kernel handles. */
5153 rc = _close (fd);
5155 if (rc == 0 && fd < MAXDESC)
5156 fd_info[fd].flags = 0;
5158 return rc;
5162 sys_dup (int fd)
5164 int new_fd;
5166 new_fd = _dup (fd);
5167 if (new_fd >= 0 && new_fd < MAXDESC)
5169 /* duplicate our internal info as well */
5170 fd_info[new_fd] = fd_info[fd];
5172 return new_fd;
5176 sys_dup2 (int src, int dst)
5178 int rc;
5180 if (dst < 0 || dst >= MAXDESC)
5182 errno = EBADF;
5183 return -1;
5186 /* make sure we close the destination first if it's a pipe or socket */
5187 if (src != dst && fd_info[dst].flags != 0)
5188 sys_close (dst);
5190 rc = _dup2 (src, dst);
5191 if (rc == 0)
5193 /* duplicate our internal info as well */
5194 fd_info[dst] = fd_info[src];
5196 return rc;
5199 /* Unix pipe() has only one arg */
5201 sys_pipe (int * phandles)
5203 int rc;
5204 unsigned flags;
5206 /* make pipe handles non-inheritable; when we spawn a child, we
5207 replace the relevant handle with an inheritable one. Also put
5208 pipes into binary mode; we will do text mode translation ourselves
5209 if required. */
5210 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
5212 if (rc == 0)
5214 /* Protect against overflow, since Windows can open more handles than
5215 our fd_info array has room for. */
5216 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
5218 _close (phandles[0]);
5219 _close (phandles[1]);
5220 rc = -1;
5222 else
5224 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
5225 fd_info[phandles[0]].flags = flags;
5227 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
5228 fd_info[phandles[1]].flags = flags;
5232 return rc;
5235 /* Function to do blocking read of one byte, needed to implement
5236 select. It is only allowed on sockets and pipes. */
5238 _sys_read_ahead (int fd)
5240 child_process * cp;
5241 int rc;
5243 if (fd < 0 || fd >= MAXDESC)
5244 return STATUS_READ_ERROR;
5246 cp = fd_info[fd].cp;
5248 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5249 return STATUS_READ_ERROR;
5251 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
5252 || (fd_info[fd].flags & FILE_READ) == 0)
5254 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
5255 abort ();
5258 cp->status = STATUS_READ_IN_PROGRESS;
5260 if (fd_info[fd].flags & FILE_PIPE)
5262 rc = _read (fd, &cp->chr, sizeof (char));
5264 /* Give subprocess time to buffer some more output for us before
5265 reporting that input is available; we need this because Windows 95
5266 connects DOS programs to pipes by making the pipe appear to be
5267 the normal console stdout - as a result most DOS programs will
5268 write to stdout without buffering, ie. one character at a
5269 time. Even some W32 programs do this - "dir" in a command
5270 shell on NT is very slow if we don't do this. */
5271 if (rc > 0)
5273 int wait = w32_pipe_read_delay;
5275 if (wait > 0)
5276 Sleep (wait);
5277 else if (wait < 0)
5278 while (++wait <= 0)
5279 /* Yield remainder of our time slice, effectively giving a
5280 temporary priority boost to the child process. */
5281 Sleep (0);
5284 else if (fd_info[fd].flags & FILE_SERIAL)
5286 HANDLE hnd = fd_info[fd].hnd;
5287 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5288 COMMTIMEOUTS ct;
5290 /* Configure timeouts for blocking read. */
5291 if (!GetCommTimeouts (hnd, &ct))
5292 return STATUS_READ_ERROR;
5293 ct.ReadIntervalTimeout = 0;
5294 ct.ReadTotalTimeoutMultiplier = 0;
5295 ct.ReadTotalTimeoutConstant = 0;
5296 if (!SetCommTimeouts (hnd, &ct))
5297 return STATUS_READ_ERROR;
5299 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
5301 if (GetLastError () != ERROR_IO_PENDING)
5302 return STATUS_READ_ERROR;
5303 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5304 return STATUS_READ_ERROR;
5307 else if (fd_info[fd].flags & FILE_SOCKET)
5309 unsigned long nblock = 0;
5310 /* We always want this to block, so temporarily disable NDELAY. */
5311 if (fd_info[fd].flags & FILE_NDELAY)
5312 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5314 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
5316 if (fd_info[fd].flags & FILE_NDELAY)
5318 nblock = 1;
5319 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5323 if (rc == sizeof (char))
5324 cp->status = STATUS_READ_SUCCEEDED;
5325 else
5326 cp->status = STATUS_READ_FAILED;
5328 return cp->status;
5332 _sys_wait_accept (int fd)
5334 HANDLE hEv;
5335 child_process * cp;
5336 int rc;
5338 if (fd < 0 || fd >= MAXDESC)
5339 return STATUS_READ_ERROR;
5341 cp = fd_info[fd].cp;
5343 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5344 return STATUS_READ_ERROR;
5346 cp->status = STATUS_READ_FAILED;
5348 hEv = pfn_WSACreateEvent ();
5349 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
5350 if (rc != SOCKET_ERROR)
5352 rc = WaitForSingleObject (hEv, INFINITE);
5353 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
5354 if (rc == WAIT_OBJECT_0)
5355 cp->status = STATUS_READ_SUCCEEDED;
5357 pfn_WSACloseEvent (hEv);
5359 return cp->status;
5363 sys_read (int fd, char * buffer, unsigned int count)
5365 int nchars;
5366 int to_read;
5367 DWORD waiting;
5368 char * orig_buffer = buffer;
5370 if (fd < 0)
5372 errno = EBADF;
5373 return -1;
5376 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5378 child_process *cp = fd_info[fd].cp;
5380 if ((fd_info[fd].flags & FILE_READ) == 0)
5382 errno = EBADF;
5383 return -1;
5386 nchars = 0;
5388 /* re-read CR carried over from last read */
5389 if (fd_info[fd].flags & FILE_LAST_CR)
5391 if (fd_info[fd].flags & FILE_BINARY) abort ();
5392 *buffer++ = 0x0d;
5393 count--;
5394 nchars++;
5395 fd_info[fd].flags &= ~FILE_LAST_CR;
5398 /* presence of a child_process structure means we are operating in
5399 non-blocking mode - otherwise we just call _read directly.
5400 Note that the child_process structure might be missing because
5401 reap_subprocess has been called; in this case the pipe is
5402 already broken, so calling _read on it is okay. */
5403 if (cp)
5405 int current_status = cp->status;
5407 switch (current_status)
5409 case STATUS_READ_FAILED:
5410 case STATUS_READ_ERROR:
5411 /* report normal EOF if nothing in buffer */
5412 if (nchars <= 0)
5413 fd_info[fd].flags |= FILE_AT_EOF;
5414 return nchars;
5416 case STATUS_READ_READY:
5417 case STATUS_READ_IN_PROGRESS:
5418 DebPrint (("sys_read called when read is in progress\n"));
5419 errno = EWOULDBLOCK;
5420 return -1;
5422 case STATUS_READ_SUCCEEDED:
5423 /* consume read-ahead char */
5424 *buffer++ = cp->chr;
5425 count--;
5426 nchars++;
5427 cp->status = STATUS_READ_ACKNOWLEDGED;
5428 ResetEvent (cp->char_avail);
5430 case STATUS_READ_ACKNOWLEDGED:
5431 break;
5433 default:
5434 DebPrint (("sys_read: bad status %d\n", current_status));
5435 errno = EBADF;
5436 return -1;
5439 if (fd_info[fd].flags & FILE_PIPE)
5441 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
5442 to_read = min (waiting, (DWORD) count);
5444 if (to_read > 0)
5445 nchars += _read (fd, buffer, to_read);
5447 else if (fd_info[fd].flags & FILE_SERIAL)
5449 HANDLE hnd = fd_info[fd].hnd;
5450 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5451 int rc = 0;
5452 COMMTIMEOUTS ct;
5454 if (count > 0)
5456 /* Configure timeouts for non-blocking read. */
5457 if (!GetCommTimeouts (hnd, &ct))
5459 errno = EIO;
5460 return -1;
5462 ct.ReadIntervalTimeout = MAXDWORD;
5463 ct.ReadTotalTimeoutMultiplier = 0;
5464 ct.ReadTotalTimeoutConstant = 0;
5465 if (!SetCommTimeouts (hnd, &ct))
5467 errno = EIO;
5468 return -1;
5471 if (!ResetEvent (ovl->hEvent))
5473 errno = EIO;
5474 return -1;
5476 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
5478 if (GetLastError () != ERROR_IO_PENDING)
5480 errno = EIO;
5481 return -1;
5483 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5485 errno = EIO;
5486 return -1;
5489 nchars += rc;
5492 else /* FILE_SOCKET */
5494 if (winsock_lib == NULL) abort ();
5496 /* do the equivalent of a non-blocking read */
5497 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
5498 if (waiting == 0 && nchars == 0)
5500 h_errno = errno = EWOULDBLOCK;
5501 return -1;
5504 if (waiting)
5506 /* always use binary mode for sockets */
5507 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
5508 if (res == SOCKET_ERROR)
5510 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5511 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5512 set_errno ();
5513 return -1;
5515 nchars += res;
5519 else
5521 int nread = _read (fd, buffer, count);
5522 if (nread >= 0)
5523 nchars += nread;
5524 else if (nchars == 0)
5525 nchars = nread;
5528 if (nchars <= 0)
5529 fd_info[fd].flags |= FILE_AT_EOF;
5530 /* Perform text mode translation if required. */
5531 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
5533 nchars = crlf_to_lf (nchars, orig_buffer);
5534 /* If buffer contains only CR, return that. To be absolutely
5535 sure we should attempt to read the next char, but in
5536 practice a CR to be followed by LF would not appear by
5537 itself in the buffer. */
5538 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
5540 fd_info[fd].flags |= FILE_LAST_CR;
5541 nchars--;
5545 else
5546 nchars = _read (fd, buffer, count);
5548 return nchars;
5551 /* From w32xfns.c */
5552 extern HANDLE interrupt_handle;
5554 /* For now, don't bother with a non-blocking mode */
5556 sys_write (int fd, const void * buffer, unsigned int count)
5558 int nchars;
5560 if (fd < 0)
5562 errno = EBADF;
5563 return -1;
5566 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5568 if ((fd_info[fd].flags & FILE_WRITE) == 0)
5570 errno = EBADF;
5571 return -1;
5574 /* Perform text mode translation if required. */
5575 if ((fd_info[fd].flags & FILE_BINARY) == 0)
5577 char * tmpbuf = alloca (count * 2);
5578 unsigned char * src = (void *)buffer;
5579 unsigned char * dst = tmpbuf;
5580 int nbytes = count;
5582 while (1)
5584 unsigned char *next;
5585 /* copy next line or remaining bytes */
5586 next = _memccpy (dst, src, '\n', nbytes);
5587 if (next)
5589 /* copied one line ending with '\n' */
5590 int copied = next - dst;
5591 nbytes -= copied;
5592 src += copied;
5593 /* insert '\r' before '\n' */
5594 next[-1] = '\r';
5595 next[0] = '\n';
5596 dst = next + 1;
5597 count++;
5599 else
5600 /* copied remaining partial line -> now finished */
5601 break;
5603 buffer = tmpbuf;
5607 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
5609 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
5610 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
5611 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
5612 DWORD active = 0;
5614 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
5616 if (GetLastError () != ERROR_IO_PENDING)
5618 errno = EIO;
5619 return -1;
5621 if (detect_input_pending ())
5622 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
5623 QS_ALLINPUT);
5624 else
5625 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
5626 if (active == WAIT_OBJECT_0)
5627 { /* User pressed C-g, cancel write, then leave. Don't bother
5628 cleaning up as we may only get stuck in buggy drivers. */
5629 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
5630 CancelIo (hnd);
5631 errno = EIO;
5632 return -1;
5634 if (active == WAIT_OBJECT_0 + 1
5635 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
5637 errno = EIO;
5638 return -1;
5642 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
5644 unsigned long nblock = 0;
5645 if (winsock_lib == NULL) abort ();
5647 /* TODO: implement select() properly so non-blocking I/O works. */
5648 /* For now, make sure the write blocks. */
5649 if (fd_info[fd].flags & FILE_NDELAY)
5650 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5652 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
5654 /* Set the socket back to non-blocking if it was before,
5655 for other operations that support it. */
5656 if (fd_info[fd].flags & FILE_NDELAY)
5658 nblock = 1;
5659 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5662 if (nchars == SOCKET_ERROR)
5664 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5665 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5666 set_errno ();
5669 else
5671 /* Some networked filesystems don't like too large writes, so
5672 break them into smaller chunks. See the Comments section of
5673 the MSDN documentation of WriteFile for details behind the
5674 choice of the value of CHUNK below. See also the thread
5675 http://thread.gmane.org/gmane.comp.version-control.git/145294
5676 in the git mailing list. */
5677 const unsigned char *p = buffer;
5678 const unsigned chunk = 30 * 1024 * 1024;
5680 nchars = 0;
5681 while (count > 0)
5683 unsigned this_chunk = count < chunk ? count : chunk;
5684 int n = _write (fd, p, this_chunk);
5686 nchars += n;
5687 if (n < 0)
5689 nchars = n;
5690 break;
5692 else if (n < this_chunk)
5693 break;
5694 count -= n;
5695 p += n;
5699 return nchars;
5702 /* The Windows CRT functions are "optimized for speed", so they don't
5703 check for timezone and DST changes if they were last called less
5704 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
5705 all Emacs features that repeatedly call time functions (e.g.,
5706 display-time) are in real danger of missing timezone and DST
5707 changes. Calling tzset before each localtime call fixes that. */
5708 struct tm *
5709 sys_localtime (const time_t *t)
5711 tzset ();
5712 return localtime (t);
5715 static void
5716 check_windows_init_file (void)
5718 /* A common indication that Emacs is not installed properly is when
5719 it cannot find the Windows installation file. If this file does
5720 not exist in the expected place, tell the user. */
5722 if (!noninteractive && !inhibit_window_system)
5724 Lisp_Object objs[2];
5725 Lisp_Object full_load_path;
5726 Lisp_Object init_file;
5727 int fd;
5729 objs[0] = Vload_path;
5730 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5731 full_load_path = Fappend (2, objs);
5732 init_file = build_string ("term/w32-win");
5733 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
5734 if (fd < 0)
5736 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
5737 char *init_file_name = SDATA (init_file);
5738 char *load_path = SDATA (load_path_print);
5739 char *buffer = alloca (1024
5740 + strlen (init_file_name)
5741 + strlen (load_path));
5743 sprintf (buffer,
5744 "The Emacs Windows initialization file \"%s.el\" "
5745 "could not be found in your Emacs installation. "
5746 "Emacs checked the following directories for this file:\n"
5747 "\n%s\n\n"
5748 "When Emacs cannot find this file, it usually means that it "
5749 "was not installed properly, or its distribution file was "
5750 "not unpacked properly.\nSee the README.W32 file in the "
5751 "top-level Emacs directory for more information.",
5752 init_file_name, load_path);
5753 MessageBox (NULL,
5754 buffer,
5755 "Emacs Abort Dialog",
5756 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
5757 /* Use the low-level Emacs abort. */
5758 #undef abort
5759 abort ();
5761 else
5763 _close (fd);
5768 void
5769 term_ntproc (void)
5771 /* shutdown the socket interface if necessary */
5772 term_winsock ();
5774 term_w32select ();
5777 void
5778 init_ntproc (void)
5780 /* Initialise the socket interface now if available and requested by
5781 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5782 delayed until open-network-stream is called (w32-has-winsock can
5783 also be used to dynamically load or reload winsock).
5785 Conveniently, init_environment is called before us, so
5786 PRELOAD_WINSOCK can be set in the registry. */
5788 /* Always initialize this correctly. */
5789 winsock_lib = NULL;
5791 if (getenv ("PRELOAD_WINSOCK") != NULL)
5792 init_winsock (TRUE);
5794 /* Initial preparation for subprocess support: replace our standard
5795 handles with non-inheritable versions. */
5797 HANDLE parent;
5798 HANDLE stdin_save = INVALID_HANDLE_VALUE;
5799 HANDLE stdout_save = INVALID_HANDLE_VALUE;
5800 HANDLE stderr_save = INVALID_HANDLE_VALUE;
5802 parent = GetCurrentProcess ();
5804 /* ignore errors when duplicating and closing; typically the
5805 handles will be invalid when running as a gui program. */
5806 DuplicateHandle (parent,
5807 GetStdHandle (STD_INPUT_HANDLE),
5808 parent,
5809 &stdin_save,
5811 FALSE,
5812 DUPLICATE_SAME_ACCESS);
5814 DuplicateHandle (parent,
5815 GetStdHandle (STD_OUTPUT_HANDLE),
5816 parent,
5817 &stdout_save,
5819 FALSE,
5820 DUPLICATE_SAME_ACCESS);
5822 DuplicateHandle (parent,
5823 GetStdHandle (STD_ERROR_HANDLE),
5824 parent,
5825 &stderr_save,
5827 FALSE,
5828 DUPLICATE_SAME_ACCESS);
5830 fclose (stdin);
5831 fclose (stdout);
5832 fclose (stderr);
5834 if (stdin_save != INVALID_HANDLE_VALUE)
5835 _open_osfhandle ((long) stdin_save, O_TEXT);
5836 else
5837 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
5838 _fdopen (0, "r");
5840 if (stdout_save != INVALID_HANDLE_VALUE)
5841 _open_osfhandle ((long) stdout_save, O_TEXT);
5842 else
5843 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5844 _fdopen (1, "w");
5846 if (stderr_save != INVALID_HANDLE_VALUE)
5847 _open_osfhandle ((long) stderr_save, O_TEXT);
5848 else
5849 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5850 _fdopen (2, "w");
5853 /* unfortunately, atexit depends on implementation of malloc */
5854 /* atexit (term_ntproc); */
5855 signal (SIGABRT, term_ntproc);
5857 /* determine which drives are fixed, for GetCachedVolumeInformation */
5859 /* GetDriveType must have trailing backslash. */
5860 char drive[] = "A:\\";
5862 /* Loop over all possible drive letters */
5863 while (*drive <= 'Z')
5865 /* Record if this drive letter refers to a fixed drive. */
5866 fixed_drives[DRIVE_INDEX (*drive)] =
5867 (GetDriveType (drive) == DRIVE_FIXED);
5869 (*drive)++;
5872 /* Reset the volume info cache. */
5873 volume_cache = NULL;
5876 /* Check to see if Emacs has been installed correctly. */
5877 check_windows_init_file ();
5881 shutdown_handler ensures that buffers' autosave files are
5882 up to date when the user logs off, or the system shuts down.
5884 static BOOL WINAPI
5885 shutdown_handler (DWORD type)
5887 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5888 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
5889 || type == CTRL_LOGOFF_EVENT /* User logs off. */
5890 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
5892 /* Shut down cleanly, making sure autosave files are up to date. */
5893 shut_down_emacs (0, 0, Qnil);
5896 /* Allow other handlers to handle this signal. */
5897 return FALSE;
5901 globals_of_w32 is used to initialize those global variables that
5902 must always be initialized on startup even when the global variable
5903 initialized is non zero (see the function main in emacs.c).
5905 void
5906 globals_of_w32 (void)
5908 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
5910 get_process_times_fn = (GetProcessTimes_Proc)
5911 GetProcAddress (kernel32, "GetProcessTimes");
5913 g_b_init_is_windows_9x = 0;
5914 g_b_init_open_process_token = 0;
5915 g_b_init_get_token_information = 0;
5916 g_b_init_lookup_account_sid = 0;
5917 g_b_init_get_sid_sub_authority = 0;
5918 g_b_init_get_sid_sub_authority_count = 0;
5919 g_b_init_get_file_security = 0;
5920 g_b_init_get_security_descriptor_owner = 0;
5921 g_b_init_get_security_descriptor_group = 0;
5922 g_b_init_is_valid_sid = 0;
5923 g_b_init_create_toolhelp32_snapshot = 0;
5924 g_b_init_process32_first = 0;
5925 g_b_init_process32_next = 0;
5926 g_b_init_open_thread_token = 0;
5927 g_b_init_impersonate_self = 0;
5928 g_b_init_revert_to_self = 0;
5929 g_b_init_get_process_memory_info = 0;
5930 g_b_init_get_process_working_set_size = 0;
5931 g_b_init_global_memory_status = 0;
5932 g_b_init_global_memory_status_ex = 0;
5933 g_b_init_equal_sid = 0;
5934 g_b_init_copy_sid = 0;
5935 g_b_init_get_length_sid = 0;
5936 g_b_init_get_native_system_info = 0;
5937 g_b_init_get_system_times = 0;
5938 num_of_processors = 0;
5939 /* The following sets a handler for shutdown notifications for
5940 console apps. This actually applies to Emacs in both console and
5941 GUI modes, since we had to fool windows into thinking emacs is a
5942 console application to get console mode to work. */
5943 SetConsoleCtrlHandler (shutdown_handler, TRUE);
5945 /* "None" is the default group name on standalone workstations. */
5946 strcpy (dflt_group_name, "None");
5949 /* For make-serial-process */
5951 serial_open (char *port)
5953 HANDLE hnd;
5954 child_process *cp;
5955 int fd = -1;
5957 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
5958 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
5959 if (hnd == INVALID_HANDLE_VALUE)
5960 error ("Could not open %s", port);
5961 fd = (int) _open_osfhandle ((int) hnd, 0);
5962 if (fd == -1)
5963 error ("Could not open %s", port);
5965 cp = new_child ();
5966 if (!cp)
5967 error ("Could not create child process");
5968 cp->fd = fd;
5969 cp->status = STATUS_READ_ACKNOWLEDGED;
5970 fd_info[ fd ].hnd = hnd;
5971 fd_info[ fd ].flags |=
5972 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
5973 if (fd_info[ fd ].cp != NULL)
5975 error ("fd_info[fd = %d] is already in use", fd);
5977 fd_info[ fd ].cp = cp;
5978 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5979 if (cp->ovl_read.hEvent == NULL)
5980 error ("Could not create read event");
5981 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5982 if (cp->ovl_write.hEvent == NULL)
5983 error ("Could not create write event");
5985 return fd;
5988 /* For serial-process-configure */
5989 void
5990 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
5992 Lisp_Object childp2 = Qnil;
5993 Lisp_Object tem = Qnil;
5994 HANDLE hnd;
5995 DCB dcb;
5996 COMMTIMEOUTS ct;
5997 char summary[4] = "???"; /* This usually becomes "8N1". */
5999 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
6000 error ("Not a serial process");
6001 hnd = fd_info[ p->outfd ].hnd;
6003 childp2 = Fcopy_sequence (p->childp);
6005 /* Initialize timeouts for blocking read and blocking write. */
6006 if (!GetCommTimeouts (hnd, &ct))
6007 error ("GetCommTimeouts() failed");
6008 ct.ReadIntervalTimeout = 0;
6009 ct.ReadTotalTimeoutMultiplier = 0;
6010 ct.ReadTotalTimeoutConstant = 0;
6011 ct.WriteTotalTimeoutMultiplier = 0;
6012 ct.WriteTotalTimeoutConstant = 0;
6013 if (!SetCommTimeouts (hnd, &ct))
6014 error ("SetCommTimeouts() failed");
6015 /* Read port attributes and prepare default configuration. */
6016 memset (&dcb, 0, sizeof (dcb));
6017 dcb.DCBlength = sizeof (DCB);
6018 if (!GetCommState (hnd, &dcb))
6019 error ("GetCommState() failed");
6020 dcb.fBinary = TRUE;
6021 dcb.fNull = FALSE;
6022 dcb.fAbortOnError = FALSE;
6023 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6024 dcb.ErrorChar = 0;
6025 dcb.EofChar = 0;
6026 dcb.EvtChar = 0;
6028 /* Configure speed. */
6029 if (!NILP (Fplist_member (contact, QCspeed)))
6030 tem = Fplist_get (contact, QCspeed);
6031 else
6032 tem = Fplist_get (p->childp, QCspeed);
6033 CHECK_NUMBER (tem);
6034 dcb.BaudRate = XINT (tem);
6035 childp2 = Fplist_put (childp2, QCspeed, tem);
6037 /* Configure bytesize. */
6038 if (!NILP (Fplist_member (contact, QCbytesize)))
6039 tem = Fplist_get (contact, QCbytesize);
6040 else
6041 tem = Fplist_get (p->childp, QCbytesize);
6042 if (NILP (tem))
6043 tem = make_number (8);
6044 CHECK_NUMBER (tem);
6045 if (XINT (tem) != 7 && XINT (tem) != 8)
6046 error (":bytesize must be nil (8), 7, or 8");
6047 dcb.ByteSize = XINT (tem);
6048 summary[0] = XINT (tem) + '0';
6049 childp2 = Fplist_put (childp2, QCbytesize, tem);
6051 /* Configure parity. */
6052 if (!NILP (Fplist_member (contact, QCparity)))
6053 tem = Fplist_get (contact, QCparity);
6054 else
6055 tem = Fplist_get (p->childp, QCparity);
6056 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
6057 error (":parity must be nil (no parity), `even', or `odd'");
6058 dcb.fParity = FALSE;
6059 dcb.Parity = NOPARITY;
6060 dcb.fErrorChar = FALSE;
6061 if (NILP (tem))
6063 summary[1] = 'N';
6065 else if (EQ (tem, Qeven))
6067 summary[1] = 'E';
6068 dcb.fParity = TRUE;
6069 dcb.Parity = EVENPARITY;
6070 dcb.fErrorChar = TRUE;
6072 else if (EQ (tem, Qodd))
6074 summary[1] = 'O';
6075 dcb.fParity = TRUE;
6076 dcb.Parity = ODDPARITY;
6077 dcb.fErrorChar = TRUE;
6079 childp2 = Fplist_put (childp2, QCparity, tem);
6081 /* Configure stopbits. */
6082 if (!NILP (Fplist_member (contact, QCstopbits)))
6083 tem = Fplist_get (contact, QCstopbits);
6084 else
6085 tem = Fplist_get (p->childp, QCstopbits);
6086 if (NILP (tem))
6087 tem = make_number (1);
6088 CHECK_NUMBER (tem);
6089 if (XINT (tem) != 1 && XINT (tem) != 2)
6090 error (":stopbits must be nil (1 stopbit), 1, or 2");
6091 summary[2] = XINT (tem) + '0';
6092 if (XINT (tem) == 1)
6093 dcb.StopBits = ONESTOPBIT;
6094 else if (XINT (tem) == 2)
6095 dcb.StopBits = TWOSTOPBITS;
6096 childp2 = Fplist_put (childp2, QCstopbits, tem);
6098 /* Configure flowcontrol. */
6099 if (!NILP (Fplist_member (contact, QCflowcontrol)))
6100 tem = Fplist_get (contact, QCflowcontrol);
6101 else
6102 tem = Fplist_get (p->childp, QCflowcontrol);
6103 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
6104 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6105 dcb.fOutxCtsFlow = FALSE;
6106 dcb.fOutxDsrFlow = FALSE;
6107 dcb.fDtrControl = DTR_CONTROL_DISABLE;
6108 dcb.fDsrSensitivity = FALSE;
6109 dcb.fTXContinueOnXoff = FALSE;
6110 dcb.fOutX = FALSE;
6111 dcb.fInX = FALSE;
6112 dcb.fRtsControl = RTS_CONTROL_DISABLE;
6113 dcb.XonChar = 17; /* Control-Q */
6114 dcb.XoffChar = 19; /* Control-S */
6115 if (NILP (tem))
6117 /* Already configured. */
6119 else if (EQ (tem, Qhw))
6121 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
6122 dcb.fOutxCtsFlow = TRUE;
6124 else if (EQ (tem, Qsw))
6126 dcb.fOutX = TRUE;
6127 dcb.fInX = TRUE;
6129 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
6131 /* Activate configuration. */
6132 if (!SetCommState (hnd, &dcb))
6133 error ("SetCommState() failed");
6135 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
6136 p->childp = childp2;
6139 #ifdef HAVE_GNUTLS
6141 ssize_t
6142 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
6144 int n, sc, err;
6145 SELECT_TYPE fdset;
6146 EMACS_TIME timeout;
6147 struct Lisp_Process *process = (struct Lisp_Process *)p;
6148 int fd = process->infd;
6150 for (;;)
6152 n = sys_read(fd, (char*)buf, sz);
6154 if (n >= 0)
6155 return n;
6157 err = errno;
6159 if (err == EWOULDBLOCK)
6161 /* Set a small timeout. */
6162 EMACS_SET_SECS_USECS(timeout, 1, 0);
6163 FD_ZERO (&fdset);
6164 FD_SET ((int)fd, &fdset);
6166 /* Use select with the timeout to poll the selector. */
6167 sc = select (fd + 1, &fdset, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
6168 &timeout);
6170 if (sc > 0)
6171 continue; /* Try again. */
6173 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
6174 Also accept select return 0 as an indicator to EAGAIN. */
6175 if (sc == 0 || errno == EWOULDBLOCK)
6176 err = EAGAIN;
6177 else
6178 err = errno; /* Other errors are just passed on. */
6181 gnutls_transport_set_errno (process->gnutls_state, err);
6183 return -1;
6187 ssize_t
6188 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
6190 struct Lisp_Process *process = (struct Lisp_Process *)p;
6191 int fd = process->outfd;
6192 ssize_t n = sys_write(fd, buf, sz);
6194 /* 0 or more bytes written means everything went fine. */
6195 if (n >= 0)
6196 return n;
6198 /* Negative bytes written means we got an error in errno.
6199 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
6200 gnutls_transport_set_errno (process->gnutls_state,
6201 errno == EWOULDBLOCK ? EAGAIN : errno);
6203 return -1;
6205 #endif /* HAVE_GNUTLS */
6207 /* end of w32.c */