Merge from emacs-23.
[emacs.git] / src / w32.c
blobe508e4e3fa5688cb2370b24054da7103390a7817
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
23 #include <stddef.h> /* for offsetof */
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <float.h> /* for DBL_EPSILON */
27 #include <io.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <ctype.h>
31 #include <signal.h>
32 #include <sys/file.h>
33 #include <sys/time.h>
34 #include <sys/utime.h>
35 #include <mbstring.h> /* for _mbspbrk */
36 #include <math.h>
37 #include <setjmp.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 #include "lisp.h"
68 #include <pwd.h>
69 #include <grp.h>
71 #ifdef __GNUC__
72 #define _ANONYMOUS_UNION
73 #define _ANONYMOUS_STRUCT
74 #endif
75 #include <windows.h>
76 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
77 use a different name to avoid compilation problems. */
78 typedef struct _MEMORY_STATUS_EX {
79 DWORD dwLength;
80 DWORD dwMemoryLoad;
81 DWORDLONG ullTotalPhys;
82 DWORDLONG ullAvailPhys;
83 DWORDLONG ullTotalPageFile;
84 DWORDLONG ullAvailPageFile;
85 DWORDLONG ullTotalVirtual;
86 DWORDLONG ullAvailVirtual;
87 DWORDLONG ullAvailExtendedVirtual;
88 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
90 #include <lmcons.h>
91 #include <shlobj.h>
93 #include <tlhelp32.h>
94 #include <psapi.h>
95 #include <w32api.h>
96 #if !defined(__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
97 /* This either is not in psapi.h or guarded by higher value of
98 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
99 defines it in psapi.h */
100 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
101 DWORD cb;
102 DWORD PageFaultCount;
103 DWORD PeakWorkingSetSize;
104 DWORD WorkingSetSize;
105 DWORD QuotaPeakPagedPoolUsage;
106 DWORD QuotaPagedPoolUsage;
107 DWORD QuotaPeakNonPagedPoolUsage;
108 DWORD QuotaNonPagedPoolUsage;
109 DWORD PagefileUsage;
110 DWORD PeakPagefileUsage;
111 DWORD PrivateUsage;
112 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
113 #endif
115 /* TCP connection support. */
116 #include <sys/socket.h>
117 #undef socket
118 #undef bind
119 #undef connect
120 #undef htons
121 #undef ntohs
122 #undef inet_addr
123 #undef gethostname
124 #undef gethostbyname
125 #undef getservbyname
126 #undef getpeername
127 #undef shutdown
128 #undef setsockopt
129 #undef listen
130 #undef getsockname
131 #undef accept
132 #undef recvfrom
133 #undef sendto
135 #include "w32.h"
136 #include "ndir.h"
137 #include "w32heap.h"
138 #include "systime.h"
139 #include "dispextern.h" /* for xstrcasecmp */
140 #include "coding.h" /* for Vlocale_coding_system */
142 /* For serial_configure and serial_open. */
143 #include "process.h"
145 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
146 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
148 void globals_of_w32 (void);
149 static DWORD get_rid (PSID);
151 /* Defined in process.c for its own purpose. */
152 extern Lisp_Object Qlocal;
155 /* Initialization states.
157 WARNING: If you add any more such variables for additional APIs,
158 you MUST add initialization for them to globals_of_w32
159 below. This is because these variables might get set
160 to non-NULL values during dumping, but the dumped Emacs
161 cannot reuse those values, because it could be run on a
162 different version of the OS, where API addresses are
163 different. */
164 static BOOL g_b_init_is_windows_9x;
165 static BOOL g_b_init_open_process_token;
166 static BOOL g_b_init_get_token_information;
167 static BOOL g_b_init_lookup_account_sid;
168 static BOOL g_b_init_get_sid_sub_authority;
169 static BOOL g_b_init_get_sid_sub_authority_count;
170 static BOOL g_b_init_get_file_security;
171 static BOOL g_b_init_get_security_descriptor_owner;
172 static BOOL g_b_init_get_security_descriptor_group;
173 static BOOL g_b_init_is_valid_sid;
174 static BOOL g_b_init_create_toolhelp32_snapshot;
175 static BOOL g_b_init_process32_first;
176 static BOOL g_b_init_process32_next;
177 static BOOL g_b_init_open_thread_token;
178 static BOOL g_b_init_impersonate_self;
179 static BOOL g_b_init_revert_to_self;
180 static BOOL g_b_init_get_process_memory_info;
181 static BOOL g_b_init_get_process_working_set_size;
182 static BOOL g_b_init_global_memory_status;
183 static BOOL g_b_init_global_memory_status_ex;
184 static BOOL g_b_init_get_length_sid;
185 static BOOL g_b_init_equal_sid;
186 static BOOL g_b_init_copy_sid;
187 static BOOL g_b_init_get_native_system_info;
188 static BOOL g_b_init_get_system_times;
191 BEGIN: Wrapper functions around OpenProcessToken
192 and other functions in advapi32.dll that are only
193 supported in Windows NT / 2k / XP
195 /* ** Function pointer typedefs ** */
196 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
197 HANDLE ProcessHandle,
198 DWORD DesiredAccess,
199 PHANDLE TokenHandle);
200 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
201 HANDLE TokenHandle,
202 TOKEN_INFORMATION_CLASS TokenInformationClass,
203 LPVOID TokenInformation,
204 DWORD TokenInformationLength,
205 PDWORD ReturnLength);
206 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
207 HANDLE process_handle,
208 LPFILETIME creation_time,
209 LPFILETIME exit_time,
210 LPFILETIME kernel_time,
211 LPFILETIME user_time);
213 GetProcessTimes_Proc get_process_times_fn = NULL;
215 #ifdef _UNICODE
216 const char * const LookupAccountSid_Name = "LookupAccountSidW";
217 const char * const GetFileSecurity_Name = "GetFileSecurityW";
218 #else
219 const char * const LookupAccountSid_Name = "LookupAccountSidA";
220 const char * const GetFileSecurity_Name = "GetFileSecurityA";
221 #endif
222 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
223 LPCTSTR lpSystemName,
224 PSID Sid,
225 LPTSTR Name,
226 LPDWORD cbName,
227 LPTSTR DomainName,
228 LPDWORD cbDomainName,
229 PSID_NAME_USE peUse);
230 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
231 PSID pSid,
232 DWORD n);
233 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
234 PSID pSid);
235 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
236 LPCTSTR lpFileName,
237 SECURITY_INFORMATION RequestedInformation,
238 PSECURITY_DESCRIPTOR pSecurityDescriptor,
239 DWORD nLength,
240 LPDWORD lpnLengthNeeded);
241 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
242 PSECURITY_DESCRIPTOR pSecurityDescriptor,
243 PSID *pOwner,
244 LPBOOL lpbOwnerDefaulted);
245 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
246 PSECURITY_DESCRIPTOR pSecurityDescriptor,
247 PSID *pGroup,
248 LPBOOL lpbGroupDefaulted);
249 typedef BOOL (WINAPI * IsValidSid_Proc) (
250 PSID sid);
251 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
252 DWORD dwFlags,
253 DWORD th32ProcessID);
254 typedef BOOL (WINAPI * Process32First_Proc) (
255 HANDLE hSnapshot,
256 LPPROCESSENTRY32 lppe);
257 typedef BOOL (WINAPI * Process32Next_Proc) (
258 HANDLE hSnapshot,
259 LPPROCESSENTRY32 lppe);
260 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
261 HANDLE ThreadHandle,
262 DWORD DesiredAccess,
263 BOOL OpenAsSelf,
264 PHANDLE TokenHandle);
265 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
266 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
267 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
268 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
269 HANDLE Process,
270 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
271 DWORD cb);
272 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
273 HANDLE hProcess,
274 DWORD * lpMinimumWorkingSetSize,
275 DWORD * lpMaximumWorkingSetSize);
276 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
277 LPMEMORYSTATUS lpBuffer);
278 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
279 LPMEMORY_STATUS_EX lpBuffer);
280 typedef BOOL (WINAPI * CopySid_Proc) (
281 DWORD nDestinationSidLength,
282 PSID pDestinationSid,
283 PSID pSourceSid);
284 typedef BOOL (WINAPI * EqualSid_Proc) (
285 PSID pSid1,
286 PSID pSid2);
287 typedef DWORD (WINAPI * GetLengthSid_Proc) (
288 PSID pSid);
289 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
290 LPSYSTEM_INFO lpSystemInfo);
291 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
292 LPFILETIME lpIdleTime,
293 LPFILETIME lpKernelTime,
294 LPFILETIME lpUserTime);
296 /* ** A utility function ** */
297 static BOOL
298 is_windows_9x (void)
300 static BOOL s_b_ret = 0;
301 OSVERSIONINFO os_ver;
302 if (g_b_init_is_windows_9x == 0)
304 g_b_init_is_windows_9x = 1;
305 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
306 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
307 if (GetVersionEx (&os_ver))
309 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
312 return s_b_ret;
315 /* Get total user and system times for get-internal-run-time.
316 Returns a list of three integers if the times are provided by the OS
317 (NT derivatives), otherwise it returns the result of current-time. */
318 Lisp_Object
319 w32_get_internal_run_time (void)
321 if (get_process_times_fn)
323 FILETIME create, exit, kernel, user;
324 HANDLE proc = GetCurrentProcess ();
325 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
327 LARGE_INTEGER user_int, kernel_int, total;
328 int microseconds;
329 user_int.LowPart = user.dwLowDateTime;
330 user_int.HighPart = user.dwHighDateTime;
331 kernel_int.LowPart = kernel.dwLowDateTime;
332 kernel_int.HighPart = kernel.dwHighDateTime;
333 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
334 /* FILETIME is 100 nanosecond increments, Emacs only wants
335 microsecond resolution. */
336 total.QuadPart /= 10;
337 microseconds = total.QuadPart % 1000000;
338 total.QuadPart /= 1000000;
340 /* Sanity check to make sure we can represent the result. */
341 if (total.HighPart == 0)
343 int secs = total.LowPart;
345 return list3 (make_number ((secs >> 16) & 0xffff),
346 make_number (secs & 0xffff),
347 make_number (microseconds));
352 return Fcurrent_time ();
355 /* ** The wrapper functions ** */
357 static BOOL WINAPI
358 open_process_token (HANDLE ProcessHandle,
359 DWORD DesiredAccess,
360 PHANDLE TokenHandle)
362 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
363 HMODULE hm_advapi32 = NULL;
364 if (is_windows_9x () == TRUE)
366 return FALSE;
368 if (g_b_init_open_process_token == 0)
370 g_b_init_open_process_token = 1;
371 hm_advapi32 = LoadLibrary ("Advapi32.dll");
372 s_pfn_Open_Process_Token =
373 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
375 if (s_pfn_Open_Process_Token == NULL)
377 return FALSE;
379 return (
380 s_pfn_Open_Process_Token (
381 ProcessHandle,
382 DesiredAccess,
383 TokenHandle)
387 static BOOL WINAPI
388 get_token_information (HANDLE TokenHandle,
389 TOKEN_INFORMATION_CLASS TokenInformationClass,
390 LPVOID TokenInformation,
391 DWORD TokenInformationLength,
392 PDWORD ReturnLength)
394 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
395 HMODULE hm_advapi32 = NULL;
396 if (is_windows_9x () == TRUE)
398 return FALSE;
400 if (g_b_init_get_token_information == 0)
402 g_b_init_get_token_information = 1;
403 hm_advapi32 = LoadLibrary ("Advapi32.dll");
404 s_pfn_Get_Token_Information =
405 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
407 if (s_pfn_Get_Token_Information == NULL)
409 return FALSE;
411 return (
412 s_pfn_Get_Token_Information (
413 TokenHandle,
414 TokenInformationClass,
415 TokenInformation,
416 TokenInformationLength,
417 ReturnLength)
421 static BOOL WINAPI
422 lookup_account_sid (LPCTSTR lpSystemName,
423 PSID Sid,
424 LPTSTR Name,
425 LPDWORD cbName,
426 LPTSTR DomainName,
427 LPDWORD cbDomainName,
428 PSID_NAME_USE peUse)
430 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
431 HMODULE hm_advapi32 = NULL;
432 if (is_windows_9x () == TRUE)
434 return FALSE;
436 if (g_b_init_lookup_account_sid == 0)
438 g_b_init_lookup_account_sid = 1;
439 hm_advapi32 = LoadLibrary ("Advapi32.dll");
440 s_pfn_Lookup_Account_Sid =
441 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
443 if (s_pfn_Lookup_Account_Sid == NULL)
445 return FALSE;
447 return (
448 s_pfn_Lookup_Account_Sid (
449 lpSystemName,
450 Sid,
451 Name,
452 cbName,
453 DomainName,
454 cbDomainName,
455 peUse)
459 static PDWORD WINAPI
460 get_sid_sub_authority (PSID pSid, DWORD n)
462 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
463 static DWORD zero = 0U;
464 HMODULE hm_advapi32 = NULL;
465 if (is_windows_9x () == TRUE)
467 return &zero;
469 if (g_b_init_get_sid_sub_authority == 0)
471 g_b_init_get_sid_sub_authority = 1;
472 hm_advapi32 = LoadLibrary ("Advapi32.dll");
473 s_pfn_Get_Sid_Sub_Authority =
474 (GetSidSubAuthority_Proc) GetProcAddress (
475 hm_advapi32, "GetSidSubAuthority");
477 if (s_pfn_Get_Sid_Sub_Authority == NULL)
479 return &zero;
481 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
484 static PUCHAR WINAPI
485 get_sid_sub_authority_count (PSID pSid)
487 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
488 static UCHAR zero = 0U;
489 HMODULE hm_advapi32 = NULL;
490 if (is_windows_9x () == TRUE)
492 return &zero;
494 if (g_b_init_get_sid_sub_authority_count == 0)
496 g_b_init_get_sid_sub_authority_count = 1;
497 hm_advapi32 = LoadLibrary ("Advapi32.dll");
498 s_pfn_Get_Sid_Sub_Authority_Count =
499 (GetSidSubAuthorityCount_Proc) GetProcAddress (
500 hm_advapi32, "GetSidSubAuthorityCount");
502 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
504 return &zero;
506 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
509 static BOOL WINAPI
510 get_file_security (LPCTSTR lpFileName,
511 SECURITY_INFORMATION RequestedInformation,
512 PSECURITY_DESCRIPTOR pSecurityDescriptor,
513 DWORD nLength,
514 LPDWORD lpnLengthNeeded)
516 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
517 HMODULE hm_advapi32 = NULL;
518 if (is_windows_9x () == TRUE)
520 return FALSE;
522 if (g_b_init_get_file_security == 0)
524 g_b_init_get_file_security = 1;
525 hm_advapi32 = LoadLibrary ("Advapi32.dll");
526 s_pfn_Get_File_Security =
527 (GetFileSecurity_Proc) GetProcAddress (
528 hm_advapi32, GetFileSecurity_Name);
530 if (s_pfn_Get_File_Security == NULL)
532 return FALSE;
534 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
535 pSecurityDescriptor, nLength,
536 lpnLengthNeeded));
539 static BOOL WINAPI
540 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
541 PSID *pOwner,
542 LPBOOL lpbOwnerDefaulted)
544 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
545 HMODULE hm_advapi32 = NULL;
546 if (is_windows_9x () == TRUE)
548 return FALSE;
550 if (g_b_init_get_security_descriptor_owner == 0)
552 g_b_init_get_security_descriptor_owner = 1;
553 hm_advapi32 = LoadLibrary ("Advapi32.dll");
554 s_pfn_Get_Security_Descriptor_Owner =
555 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
556 hm_advapi32, "GetSecurityDescriptorOwner");
558 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
560 return FALSE;
562 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
563 lpbOwnerDefaulted));
566 static BOOL WINAPI
567 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
568 PSID *pGroup,
569 LPBOOL lpbGroupDefaulted)
571 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
572 HMODULE hm_advapi32 = NULL;
573 if (is_windows_9x () == TRUE)
575 return FALSE;
577 if (g_b_init_get_security_descriptor_group == 0)
579 g_b_init_get_security_descriptor_group = 1;
580 hm_advapi32 = LoadLibrary ("Advapi32.dll");
581 s_pfn_Get_Security_Descriptor_Group =
582 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
583 hm_advapi32, "GetSecurityDescriptorGroup");
585 if (s_pfn_Get_Security_Descriptor_Group == NULL)
587 return FALSE;
589 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
590 lpbGroupDefaulted));
593 static BOOL WINAPI
594 is_valid_sid (PSID sid)
596 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
597 HMODULE hm_advapi32 = NULL;
598 if (is_windows_9x () == TRUE)
600 return FALSE;
602 if (g_b_init_is_valid_sid == 0)
604 g_b_init_is_valid_sid = 1;
605 hm_advapi32 = LoadLibrary ("Advapi32.dll");
606 s_pfn_Is_Valid_Sid =
607 (IsValidSid_Proc) GetProcAddress (
608 hm_advapi32, "IsValidSid");
610 if (s_pfn_Is_Valid_Sid == NULL)
612 return FALSE;
614 return (s_pfn_Is_Valid_Sid (sid));
617 static BOOL WINAPI
618 equal_sid (PSID sid1, PSID sid2)
620 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
621 HMODULE hm_advapi32 = NULL;
622 if (is_windows_9x () == TRUE)
624 return FALSE;
626 if (g_b_init_equal_sid == 0)
628 g_b_init_equal_sid = 1;
629 hm_advapi32 = LoadLibrary ("Advapi32.dll");
630 s_pfn_Equal_Sid =
631 (EqualSid_Proc) GetProcAddress (
632 hm_advapi32, "EqualSid");
634 if (s_pfn_Equal_Sid == NULL)
636 return FALSE;
638 return (s_pfn_Equal_Sid (sid1, sid2));
641 static DWORD WINAPI
642 get_length_sid (PSID sid)
644 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
645 HMODULE hm_advapi32 = NULL;
646 if (is_windows_9x () == TRUE)
648 return 0;
650 if (g_b_init_get_length_sid == 0)
652 g_b_init_get_length_sid = 1;
653 hm_advapi32 = LoadLibrary ("Advapi32.dll");
654 s_pfn_Get_Length_Sid =
655 (GetLengthSid_Proc) GetProcAddress (
656 hm_advapi32, "GetLengthSid");
658 if (s_pfn_Get_Length_Sid == NULL)
660 return 0;
662 return (s_pfn_Get_Length_Sid (sid));
665 static BOOL WINAPI
666 copy_sid (DWORD destlen, PSID dest, PSID src)
668 static CopySid_Proc s_pfn_Copy_Sid = NULL;
669 HMODULE hm_advapi32 = NULL;
670 if (is_windows_9x () == TRUE)
672 return FALSE;
674 if (g_b_init_copy_sid == 0)
676 g_b_init_copy_sid = 1;
677 hm_advapi32 = LoadLibrary ("Advapi32.dll");
678 s_pfn_Copy_Sid =
679 (CopySid_Proc) GetProcAddress (
680 hm_advapi32, "CopySid");
682 if (s_pfn_Copy_Sid == NULL)
684 return FALSE;
686 return (s_pfn_Copy_Sid (destlen, dest, src));
690 END: Wrapper functions around OpenProcessToken
691 and other functions in advapi32.dll that are only
692 supported in Windows NT / 2k / XP
695 static void WINAPI
696 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
698 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
699 if (is_windows_9x () != TRUE)
701 if (g_b_init_get_native_system_info == 0)
703 g_b_init_get_native_system_info = 1;
704 s_pfn_Get_Native_System_Info =
705 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
706 "GetNativeSystemInfo");
708 if (s_pfn_Get_Native_System_Info != NULL)
709 s_pfn_Get_Native_System_Info (lpSystemInfo);
711 else
712 lpSystemInfo->dwNumberOfProcessors = -1;
715 static BOOL WINAPI
716 get_system_times (LPFILETIME lpIdleTime,
717 LPFILETIME lpKernelTime,
718 LPFILETIME lpUserTime)
720 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
721 if (is_windows_9x () == TRUE)
723 return FALSE;
725 if (g_b_init_get_system_times == 0)
727 g_b_init_get_system_times = 1;
728 s_pfn_Get_System_times =
729 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
730 "GetSystemTimes");
732 if (s_pfn_Get_System_times == NULL)
733 return FALSE;
734 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
737 /* Equivalent of strerror for W32 error codes. */
738 char *
739 w32_strerror (int error_no)
741 static char buf[500];
743 if (error_no == 0)
744 error_no = GetLastError ();
746 buf[0] = '\0';
747 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
748 error_no,
749 0, /* choose most suitable language */
750 buf, sizeof (buf), NULL))
751 sprintf (buf, "w32 error %u", error_no);
752 return buf;
755 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
756 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
758 This is called from alloc.c:valid_pointer_p. */
760 w32_valid_pointer_p (void *p, int size)
762 SIZE_T done;
763 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
765 if (h)
767 unsigned char *buf = alloca (size);
768 int retval = ReadProcessMemory (h, p, buf, size, &done);
770 CloseHandle (h);
771 return retval;
773 else
774 return -1;
777 static char startup_dir[MAXPATHLEN];
779 /* Get the current working directory. */
780 char *
781 getwd (char *dir)
783 #if 0
784 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
785 return dir;
786 return NULL;
787 #else
788 /* Emacs doesn't actually change directory itself, and we want to
789 force our real wd to be where emacs.exe is to avoid unnecessary
790 conflicts when trying to rename or delete directories. */
791 strcpy (dir, startup_dir);
792 return dir;
793 #endif
796 /* Emulate getloadavg. */
798 struct load_sample {
799 time_t sample_time;
800 ULONGLONG idle;
801 ULONGLONG kernel;
802 ULONGLONG user;
805 /* Number of processors on this machine. */
806 static unsigned num_of_processors;
808 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
809 static struct load_sample samples[16*60];
810 static int first_idx = -1, last_idx = -1;
811 static int max_idx = sizeof (samples) / sizeof (samples[0]);
813 static int
814 buf_next (int from)
816 int next_idx = from + 1;
818 if (next_idx >= max_idx)
819 next_idx = 0;
821 return next_idx;
824 static int
825 buf_prev (int from)
827 int prev_idx = from - 1;
829 if (prev_idx < 0)
830 prev_idx = max_idx - 1;
832 return prev_idx;
835 static void
836 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
838 SYSTEM_INFO sysinfo;
839 FILETIME ft_idle, ft_user, ft_kernel;
841 /* Initialize the number of processors on this machine. */
842 if (num_of_processors <= 0)
844 get_native_system_info (&sysinfo);
845 num_of_processors = sysinfo.dwNumberOfProcessors;
846 if (num_of_processors <= 0)
848 GetSystemInfo (&sysinfo);
849 num_of_processors = sysinfo.dwNumberOfProcessors;
851 if (num_of_processors <= 0)
852 num_of_processors = 1;
855 /* TODO: Take into account threads that are ready to run, by
856 sampling the "\System\Processor Queue Length" performance
857 counter. The code below accounts only for threads that are
858 actually running. */
860 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
862 ULARGE_INTEGER uidle, ukernel, uuser;
864 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
865 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
866 memcpy (&uuser, &ft_user, sizeof (ft_user));
867 *idle = uidle.QuadPart;
868 *kernel = ukernel.QuadPart;
869 *user = uuser.QuadPart;
871 else
873 *idle = 0;
874 *kernel = 0;
875 *user = 0;
879 /* Produce the load average for a given time interval, using the
880 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
881 1-minute, 5-minute, or 15-minute average, respectively. */
882 static double
883 getavg (int which)
885 double retval = -1.0;
886 double tdiff;
887 int idx;
888 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
889 time_t now = samples[last_idx].sample_time;
891 if (first_idx != last_idx)
893 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
895 tdiff = difftime (now, samples[idx].sample_time);
896 if (tdiff >= span - 2*DBL_EPSILON*now)
898 long double sys =
899 samples[last_idx].kernel + samples[last_idx].user
900 - (samples[idx].kernel + samples[idx].user);
901 long double idl = samples[last_idx].idle - samples[idx].idle;
903 retval = (1.0 - idl / sys) * num_of_processors;
904 break;
906 if (idx == first_idx)
907 break;
911 return retval;
915 getloadavg (double loadavg[], int nelem)
917 int elem;
918 ULONGLONG idle, kernel, user;
919 time_t now = time (NULL);
921 /* Store another sample. We ignore samples that are less than 1 sec
922 apart. */
923 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
925 sample_system_load (&idle, &kernel, &user);
926 last_idx = buf_next (last_idx);
927 samples[last_idx].sample_time = now;
928 samples[last_idx].idle = idle;
929 samples[last_idx].kernel = kernel;
930 samples[last_idx].user = user;
931 /* If the buffer has more that 15 min worth of samples, discard
932 the old ones. */
933 if (first_idx == -1)
934 first_idx = last_idx;
935 while (first_idx != last_idx
936 && (difftime (now, samples[first_idx].sample_time)
937 >= 15.0*60 + 2*DBL_EPSILON*now))
938 first_idx = buf_next (first_idx);
941 for (elem = 0; elem < nelem; elem++)
943 double avg = getavg (elem);
945 if (avg < 0)
946 break;
947 loadavg[elem] = avg;
950 return elem;
953 /* Emulate getpwuid, getpwnam and others. */
955 #define PASSWD_FIELD_SIZE 256
957 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
958 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
959 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
960 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
961 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
963 static struct passwd dflt_passwd =
965 dflt_passwd_name,
966 dflt_passwd_passwd,
970 dflt_passwd_gecos,
971 dflt_passwd_dir,
972 dflt_passwd_shell,
975 static char dflt_group_name[GNLEN+1];
977 static struct group dflt_group =
979 /* When group information is not available, we return this as the
980 group for all files. */
981 dflt_group_name,
985 unsigned
986 getuid (void)
988 return dflt_passwd.pw_uid;
991 unsigned
992 geteuid (void)
994 /* I could imagine arguing for checking to see whether the user is
995 in the Administrators group and returning a UID of 0 for that
996 case, but I don't know how wise that would be in the long run. */
997 return getuid ();
1000 unsigned
1001 getgid (void)
1003 return dflt_passwd.pw_gid;
1006 unsigned
1007 getegid (void)
1009 return getgid ();
1012 struct passwd *
1013 getpwuid (unsigned uid)
1015 if (uid == dflt_passwd.pw_uid)
1016 return &dflt_passwd;
1017 return NULL;
1020 struct group *
1021 getgrgid (gid_t gid)
1023 return &dflt_group;
1026 struct passwd *
1027 getpwnam (char *name)
1029 struct passwd *pw;
1031 pw = getpwuid (getuid ());
1032 if (!pw)
1033 return pw;
1035 if (xstrcasecmp (name, pw->pw_name))
1036 return NULL;
1038 return pw;
1041 static void
1042 init_user_info (void)
1044 /* Find the user's real name by opening the process token and
1045 looking up the name associated with the user-sid in that token.
1047 Use the relative portion of the identifier authority value from
1048 the user-sid as the user id value (same for group id using the
1049 primary group sid from the process token). */
1051 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1052 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1053 DWORD glength = sizeof (gname);
1054 HANDLE token = NULL;
1055 SID_NAME_USE user_type;
1056 unsigned char *buf = NULL;
1057 DWORD blen = 0;
1058 TOKEN_USER user_token;
1059 TOKEN_PRIMARY_GROUP group_token;
1060 BOOL result;
1062 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1063 if (result)
1065 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1066 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1068 buf = xmalloc (blen);
1069 result = get_token_information (token, TokenUser,
1070 (LPVOID)buf, blen, &needed);
1071 if (result)
1073 memcpy (&user_token, buf, sizeof (user_token));
1074 result = lookup_account_sid (NULL, user_token.User.Sid,
1075 uname, &ulength,
1076 domain, &dlength, &user_type);
1079 else
1080 result = FALSE;
1082 if (result)
1084 strcpy (dflt_passwd.pw_name, uname);
1085 /* Determine a reasonable uid value. */
1086 if (xstrcasecmp ("administrator", uname) == 0)
1088 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1089 dflt_passwd.pw_gid = 513; /* well-known None gid */
1091 else
1093 /* Use the last sub-authority value of the RID, the relative
1094 portion of the SID, as user/group ID. */
1095 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1097 /* Get group id and name. */
1098 result = get_token_information (token, TokenPrimaryGroup,
1099 (LPVOID)buf, blen, &needed);
1100 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1102 buf = xrealloc (buf, blen = needed);
1103 result = get_token_information (token, TokenPrimaryGroup,
1104 (LPVOID)buf, blen, &needed);
1106 if (result)
1108 memcpy (&group_token, buf, sizeof (group_token));
1109 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1110 dlength = sizeof (domain);
1111 /* If we can get at the real Primary Group name, use that.
1112 Otherwise, the default group name was already set to
1113 "None" in globals_of_w32. */
1114 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1115 gname, &glength, NULL, &dlength,
1116 &user_type))
1117 strcpy (dflt_group_name, gname);
1119 else
1120 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1123 /* If security calls are not supported (presumably because we
1124 are running under Windows 9X), fallback to this: */
1125 else if (GetUserName (uname, &ulength))
1127 strcpy (dflt_passwd.pw_name, uname);
1128 if (xstrcasecmp ("administrator", uname) == 0)
1129 dflt_passwd.pw_uid = 0;
1130 else
1131 dflt_passwd.pw_uid = 123;
1132 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1134 else
1136 strcpy (dflt_passwd.pw_name, "unknown");
1137 dflt_passwd.pw_uid = 123;
1138 dflt_passwd.pw_gid = 123;
1140 dflt_group.gr_gid = dflt_passwd.pw_gid;
1142 /* Ensure HOME and SHELL are defined. */
1143 if (getenv ("HOME") == NULL)
1144 abort ();
1145 if (getenv ("SHELL") == NULL)
1146 abort ();
1148 /* Set dir and shell from environment variables. */
1149 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1150 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1152 xfree (buf);
1153 if (token)
1154 CloseHandle (token);
1158 random (void)
1160 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1161 return ((rand () << 15) | rand ());
1164 void
1165 srandom (int seed)
1167 srand (seed);
1171 /* Normalize filename by converting all path separators to
1172 the specified separator. Also conditionally convert upper
1173 case path name components to lower case. */
1175 static void
1176 normalize_filename (register char *fp, char path_sep)
1178 char sep;
1179 char *elem;
1181 /* Always lower-case drive letters a-z, even if the filesystem
1182 preserves case in filenames.
1183 This is so filenames can be compared by string comparison
1184 functions that are case-sensitive. Even case-preserving filesystems
1185 do not distinguish case in drive letters. */
1186 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
1188 *fp += 'a' - 'A';
1189 fp += 2;
1192 if (NILP (Vw32_downcase_file_names))
1194 while (*fp)
1196 if (*fp == '/' || *fp == '\\')
1197 *fp = path_sep;
1198 fp++;
1200 return;
1203 sep = path_sep; /* convert to this path separator */
1204 elem = fp; /* start of current path element */
1206 do {
1207 if (*fp >= 'a' && *fp <= 'z')
1208 elem = 0; /* don't convert this element */
1210 if (*fp == 0 || *fp == ':')
1212 sep = *fp; /* restore current separator (or 0) */
1213 *fp = '/'; /* after conversion of this element */
1216 if (*fp == '/' || *fp == '\\')
1218 if (elem && elem != fp)
1220 *fp = 0; /* temporary end of string */
1221 _strlwr (elem); /* while we convert to lower case */
1223 *fp = sep; /* convert (or restore) path separator */
1224 elem = fp + 1; /* next element starts after separator */
1225 sep = path_sep;
1227 } while (*fp++);
1230 /* Destructively turn backslashes into slashes. */
1231 void
1232 dostounix_filename (register char *p)
1234 normalize_filename (p, '/');
1237 /* Destructively turn slashes into backslashes. */
1238 void
1239 unixtodos_filename (register char *p)
1241 normalize_filename (p, '\\');
1244 /* Remove all CR's that are followed by a LF.
1245 (From msdos.c...probably should figure out a way to share it,
1246 although this code isn't going to ever change.) */
1247 static int
1248 crlf_to_lf (register int n, register unsigned char *buf)
1250 unsigned char *np = buf;
1251 unsigned char *startp = buf;
1252 unsigned char *endp = buf + n;
1254 if (n == 0)
1255 return n;
1256 while (buf < endp - 1)
1258 if (*buf == 0x0d)
1260 if (*(++buf) != 0x0a)
1261 *np++ = 0x0d;
1263 else
1264 *np++ = *buf++;
1266 if (buf < endp)
1267 *np++ = *buf++;
1268 return np - startp;
1271 /* Parse the root part of file name, if present. Return length and
1272 optionally store pointer to char after root. */
1273 static int
1274 parse_root (char * name, char ** pPath)
1276 char * start = name;
1278 if (name == NULL)
1279 return 0;
1281 /* find the root name of the volume if given */
1282 if (isalpha (name[0]) && name[1] == ':')
1284 /* skip past drive specifier */
1285 name += 2;
1286 if (IS_DIRECTORY_SEP (name[0]))
1287 name++;
1289 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1291 int slashes = 2;
1292 name += 2;
1295 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1296 break;
1297 name++;
1299 while ( *name );
1300 if (IS_DIRECTORY_SEP (name[0]))
1301 name++;
1304 if (pPath)
1305 *pPath = name;
1307 return name - start;
1310 /* Get long base name for name; name is assumed to be absolute. */
1311 static int
1312 get_long_basename (char * name, char * buf, int size)
1314 WIN32_FIND_DATA find_data;
1315 HANDLE dir_handle;
1316 int len = 0;
1318 /* must be valid filename, no wild cards or other invalid characters */
1319 if (_mbspbrk (name, "*?|<>\""))
1320 return 0;
1322 dir_handle = FindFirstFile (name, &find_data);
1323 if (dir_handle != INVALID_HANDLE_VALUE)
1325 if ((len = strlen (find_data.cFileName)) < size)
1326 memcpy (buf, find_data.cFileName, len + 1);
1327 else
1328 len = 0;
1329 FindClose (dir_handle);
1331 return len;
1334 /* Get long name for file, if possible (assumed to be absolute). */
1335 BOOL
1336 w32_get_long_filename (char * name, char * buf, int size)
1338 char * o = buf;
1339 char * p;
1340 char * q;
1341 char full[ MAX_PATH ];
1342 int len;
1344 len = strlen (name);
1345 if (len >= MAX_PATH)
1346 return FALSE;
1348 /* Use local copy for destructive modification. */
1349 memcpy (full, name, len+1);
1350 unixtodos_filename (full);
1352 /* Copy root part verbatim. */
1353 len = parse_root (full, &p);
1354 memcpy (o, full, len);
1355 o += len;
1356 *o = '\0';
1357 size -= len;
1359 while (p != NULL && *p)
1361 q = p;
1362 p = strchr (q, '\\');
1363 if (p) *p = '\0';
1364 len = get_long_basename (full, o, size);
1365 if (len > 0)
1367 o += len;
1368 size -= len;
1369 if (p != NULL)
1371 *p++ = '\\';
1372 if (size < 2)
1373 return FALSE;
1374 *o++ = '\\';
1375 size--;
1376 *o = '\0';
1379 else
1380 return FALSE;
1383 return TRUE;
1386 static int
1387 is_unc_volume (const char *filename)
1389 const char *ptr = filename;
1391 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1392 return 0;
1394 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1395 return 0;
1397 return 1;
1400 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1403 sigsetmask (int signal_mask)
1405 return 0;
1409 sigmask (int sig)
1411 return 0;
1415 sigblock (int sig)
1417 return 0;
1421 sigunblock (int sig)
1423 return 0;
1427 sigemptyset (sigset_t *set)
1429 return 0;
1433 sigaddset (sigset_t *set, int signo)
1435 return 0;
1439 sigfillset (sigset_t *set)
1441 return 0;
1445 sigprocmask (int how, const sigset_t *set, sigset_t *oset)
1447 return 0;
1451 setpgrp (int pid, int gid)
1453 return 0;
1457 alarm (int seconds)
1459 return 0;
1462 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1464 LPBYTE
1465 w32_get_resource (char *key, LPDWORD lpdwtype)
1467 LPBYTE lpvalue;
1468 HKEY hrootkey = NULL;
1469 DWORD cbData;
1471 /* Check both the current user and the local machine to see if
1472 we have any resources. */
1474 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1476 lpvalue = NULL;
1478 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1479 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1480 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1482 RegCloseKey (hrootkey);
1483 return (lpvalue);
1486 xfree (lpvalue);
1488 RegCloseKey (hrootkey);
1491 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1493 lpvalue = NULL;
1495 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1496 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1497 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1499 RegCloseKey (hrootkey);
1500 return (lpvalue);
1503 xfree (lpvalue);
1505 RegCloseKey (hrootkey);
1508 return (NULL);
1511 char *get_emacs_configuration (void);
1512 void
1513 init_environment (char ** argv)
1515 static const char * const tempdirs[] = {
1516 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1519 int i;
1521 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1523 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1524 temporary files and assume "/tmp" if $TMPDIR is unset, which
1525 will break on DOS/Windows. Refuse to work if we cannot find
1526 a directory, not even "c:/", usable for that purpose. */
1527 for (i = 0; i < imax ; i++)
1529 const char *tmp = tempdirs[i];
1531 if (*tmp == '$')
1532 tmp = getenv (tmp + 1);
1533 /* Note that `access' can lie to us if the directory resides on a
1534 read-only filesystem, like CD-ROM or a write-protected floppy.
1535 The only way to be really sure is to actually create a file and
1536 see if it succeeds. But I think that's too much to ask. */
1537 if (tmp && _access (tmp, D_OK) == 0)
1539 char * var = alloca (strlen (tmp) + 8);
1540 sprintf (var, "TMPDIR=%s", tmp);
1541 _putenv (strdup (var));
1542 break;
1545 if (i >= imax)
1546 cmd_error_internal
1547 (Fcons (Qerror,
1548 Fcons (build_string ("no usable temporary directories found!!"),
1549 Qnil)),
1550 "While setting TMPDIR: ");
1552 /* Check for environment variables and use registry settings if they
1553 don't exist. Fallback on default values where applicable. */
1555 int i;
1556 LPBYTE lpval;
1557 DWORD dwType;
1558 char locale_name[32];
1559 struct stat ignored;
1560 char default_home[MAX_PATH];
1562 static const struct env_entry
1564 char * name;
1565 char * def_value;
1566 } dflt_envvars[] =
1568 {"HOME", "C:/"},
1569 {"PRELOAD_WINSOCK", NULL},
1570 {"emacs_dir", "C:/emacs"},
1571 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1572 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1573 {"EMACSDATA", "%emacs_dir%/etc"},
1574 {"EMACSPATH", "%emacs_dir%/bin"},
1575 /* We no longer set INFOPATH because Info-default-directory-list
1576 is then ignored. */
1577 /* {"INFOPATH", "%emacs_dir%/info"}, */
1578 {"EMACSDOC", "%emacs_dir%/etc"},
1579 {"TERM", "cmd"},
1580 {"LANG", NULL},
1583 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1585 /* We need to copy dflt_envvars[] and work on the copy because we
1586 don't want the dumped Emacs to inherit the values of
1587 environment variables we saw during dumping (which could be on
1588 a different system). The defaults above must be left intact. */
1589 struct env_entry env_vars[N_ENV_VARS];
1591 for (i = 0; i < N_ENV_VARS; i++)
1592 env_vars[i] = dflt_envvars[i];
1594 /* For backwards compatibility, check if a .emacs file exists in C:/
1595 If not, then we can try to default to the appdata directory under the
1596 user's profile, which is more likely to be writable. */
1597 if (stat ("C:/.emacs", &ignored) < 0)
1599 HRESULT profile_result;
1600 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1601 of Windows 95 and NT4 that have not been updated to include
1602 MSIE 5. */
1603 ShGetFolderPath_fn get_folder_path;
1604 get_folder_path = (ShGetFolderPath_fn)
1605 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1607 if (get_folder_path != NULL)
1609 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1610 0, default_home);
1612 /* If we can't get the appdata dir, revert to old behavior. */
1613 if (profile_result == S_OK)
1614 env_vars[0].def_value = default_home;
1618 /* Get default locale info and use it for LANG. */
1619 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1620 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1621 locale_name, sizeof (locale_name)))
1623 for (i = 0; i < N_ENV_VARS; i++)
1625 if (strcmp (env_vars[i].name, "LANG") == 0)
1627 env_vars[i].def_value = locale_name;
1628 break;
1633 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1635 /* Treat emacs_dir specially: set it unconditionally based on our
1636 location, if it appears that we are running from the bin subdir
1637 of a standard installation. */
1639 char *p;
1640 char modname[MAX_PATH];
1642 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1643 abort ();
1644 if ((p = strrchr (modname, '\\')) == NULL)
1645 abort ();
1646 *p = 0;
1648 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1650 char buf[SET_ENV_BUF_SIZE];
1652 *p = 0;
1653 for (p = modname; *p; p++)
1654 if (*p == '\\') *p = '/';
1656 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1657 _putenv (strdup (buf));
1659 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1661 /* FIXME: should use substring of get_emacs_configuration ().
1662 But I don't think the Windows build supports alpha, mips etc
1663 anymore, so have taken the easy option for now. */
1664 else if (p && xstrcasecmp (p, "\\i386") == 0)
1666 *p = 0;
1667 p = strrchr (modname, '\\');
1668 if (p != NULL)
1670 *p = 0;
1671 p = strrchr (modname, '\\');
1672 if (p && xstrcasecmp (p, "\\src") == 0)
1674 char buf[SET_ENV_BUF_SIZE];
1676 *p = 0;
1677 for (p = modname; *p; p++)
1678 if (*p == '\\') *p = '/';
1680 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1681 _putenv (strdup (buf));
1687 for (i = 0; i < N_ENV_VARS; i++)
1689 if (!getenv (env_vars[i].name))
1691 int dont_free = 0;
1693 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1694 /* Also ignore empty environment variables. */
1695 || *lpval == 0)
1697 xfree (lpval);
1698 lpval = env_vars[i].def_value;
1699 dwType = REG_EXPAND_SZ;
1700 dont_free = 1;
1703 if (lpval)
1705 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1707 if (dwType == REG_EXPAND_SZ)
1708 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
1709 else if (dwType == REG_SZ)
1710 strcpy (buf1, lpval);
1711 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1713 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
1714 buf1);
1715 _putenv (strdup (buf2));
1718 if (!dont_free)
1719 xfree (lpval);
1725 /* Rebuild system configuration to reflect invoking system. */
1726 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1728 /* Another special case: on NT, the PATH variable is actually named
1729 "Path" although cmd.exe (perhaps NT itself) arranges for
1730 environment variable lookup and setting to be case insensitive.
1731 However, Emacs assumes a fully case sensitive environment, so we
1732 need to change "Path" to "PATH" to match the expectations of
1733 various elisp packages. We do this by the sneaky method of
1734 modifying the string in the C runtime environ entry.
1736 The same applies to COMSPEC. */
1738 char ** envp;
1740 for (envp = environ; *envp; envp++)
1741 if (_strnicmp (*envp, "PATH=", 5) == 0)
1742 memcpy (*envp, "PATH=", 5);
1743 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1744 memcpy (*envp, "COMSPEC=", 8);
1747 /* Remember the initial working directory for getwd, then make the
1748 real wd be the location of emacs.exe to avoid conflicts when
1749 renaming or deleting directories. (We also don't call chdir when
1750 running subprocesses for the same reason.) */
1751 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1752 abort ();
1755 char *p;
1756 static char modname[MAX_PATH];
1758 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1759 abort ();
1760 if ((p = strrchr (modname, '\\')) == NULL)
1761 abort ();
1762 *p = 0;
1764 SetCurrentDirectory (modname);
1766 /* Ensure argv[0] has the full path to Emacs. */
1767 *p = '\\';
1768 argv[0] = modname;
1771 /* Determine if there is a middle mouse button, to allow parse_button
1772 to decide whether right mouse events should be mouse-2 or
1773 mouse-3. */
1774 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1776 init_user_info ();
1779 char *
1780 emacs_root_dir (void)
1782 static char root_dir[FILENAME_MAX];
1783 const char *p;
1785 p = getenv ("emacs_dir");
1786 if (p == NULL)
1787 abort ();
1788 strcpy (root_dir, p);
1789 root_dir[parse_root (root_dir, NULL)] = '\0';
1790 dostounix_filename (root_dir);
1791 return root_dir;
1794 /* We don't have scripts to automatically determine the system configuration
1795 for Emacs before it's compiled, and we don't want to have to make the
1796 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1797 routine. */
1799 char *
1800 get_emacs_configuration (void)
1802 char *arch, *oem, *os;
1803 int build_num;
1804 static char configuration_buffer[32];
1806 /* Determine the processor type. */
1807 switch (get_processor_type ())
1810 #ifdef PROCESSOR_INTEL_386
1811 case PROCESSOR_INTEL_386:
1812 case PROCESSOR_INTEL_486:
1813 case PROCESSOR_INTEL_PENTIUM:
1814 arch = "i386";
1815 break;
1816 #endif
1818 #ifdef PROCESSOR_MIPS_R2000
1819 case PROCESSOR_MIPS_R2000:
1820 case PROCESSOR_MIPS_R3000:
1821 case PROCESSOR_MIPS_R4000:
1822 arch = "mips";
1823 break;
1824 #endif
1826 #ifdef PROCESSOR_ALPHA_21064
1827 case PROCESSOR_ALPHA_21064:
1828 arch = "alpha";
1829 break;
1830 #endif
1832 default:
1833 arch = "unknown";
1834 break;
1837 /* Use the OEM field to reflect the compiler/library combination. */
1838 #ifdef _MSC_VER
1839 #define COMPILER_NAME "msvc"
1840 #else
1841 #ifdef __GNUC__
1842 #define COMPILER_NAME "mingw"
1843 #else
1844 #define COMPILER_NAME "unknown"
1845 #endif
1846 #endif
1847 oem = COMPILER_NAME;
1849 switch (osinfo_cache.dwPlatformId) {
1850 case VER_PLATFORM_WIN32_NT:
1851 os = "nt";
1852 build_num = osinfo_cache.dwBuildNumber;
1853 break;
1854 case VER_PLATFORM_WIN32_WINDOWS:
1855 if (osinfo_cache.dwMinorVersion == 0) {
1856 os = "windows95";
1857 } else {
1858 os = "windows98";
1860 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1861 break;
1862 case VER_PLATFORM_WIN32s:
1863 /* Not supported, should not happen. */
1864 os = "windows32s";
1865 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1866 break;
1867 default:
1868 os = "unknown";
1869 build_num = 0;
1870 break;
1873 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1874 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1875 get_w32_major_version (), get_w32_minor_version (), build_num);
1876 } else {
1877 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1880 return configuration_buffer;
1883 char *
1884 get_emacs_configuration_options (void)
1886 static char *options_buffer;
1887 char cv[32]; /* Enough for COMPILER_VERSION. */
1888 char *options[] = {
1889 cv, /* To be filled later. */
1890 #ifdef EMACSDEBUG
1891 " --no-opt",
1892 #endif
1893 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1894 with a starting space to save work here. */
1895 #ifdef USER_CFLAGS
1896 " --cflags", USER_CFLAGS,
1897 #endif
1898 #ifdef USER_LDFLAGS
1899 " --ldflags", USER_LDFLAGS,
1900 #endif
1901 NULL
1903 size_t size = 0;
1904 int i;
1906 /* Work out the effective configure options for this build. */
1907 #ifdef _MSC_VER
1908 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1909 #else
1910 #ifdef __GNUC__
1911 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1912 #else
1913 #define COMPILER_VERSION ""
1914 #endif
1915 #endif
1917 if (_snprintf (cv, sizeof (cv) - 1, COMPILER_VERSION) < 0)
1918 return "Error: not enough space for compiler version";
1919 cv[sizeof (cv) - 1] = '\0';
1921 for (i = 0; options[i]; i++)
1922 size += strlen (options[i]);
1924 options_buffer = xmalloc (size + 1);
1925 options_buffer[0] = '\0';
1927 for (i = 0; options[i]; i++)
1928 strcat (options_buffer, options[i]);
1930 return options_buffer;
1934 #include <sys/timeb.h>
1936 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1937 void
1938 gettimeofday (struct timeval *tv, struct timezone *tz)
1940 struct _timeb tb;
1941 _ftime (&tb);
1943 tv->tv_sec = tb.time;
1944 tv->tv_usec = tb.millitm * 1000L;
1945 if (tz)
1947 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
1948 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
1952 /* ------------------------------------------------------------------------- */
1953 /* IO support and wrapper functions for W32 API. */
1954 /* ------------------------------------------------------------------------- */
1956 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1957 on network directories, so we handle that case here.
1958 (Ulrich Leodolter, 1/11/95). */
1959 char *
1960 sys_ctime (const time_t *t)
1962 char *str = (char *) ctime (t);
1963 return (str ? str : "Sun Jan 01 00:00:00 1970");
1966 /* Emulate sleep...we could have done this with a define, but that
1967 would necessitate including windows.h in the files that used it.
1968 This is much easier. */
1969 void
1970 sys_sleep (int seconds)
1972 Sleep (seconds * 1000);
1975 /* Internal MSVC functions for low-level descriptor munging */
1976 extern int __cdecl _set_osfhnd (int fd, long h);
1977 extern int __cdecl _free_osfhnd (int fd);
1979 /* parallel array of private info on file handles */
1980 filedesc fd_info [ MAXDESC ];
1982 typedef struct volume_info_data {
1983 struct volume_info_data * next;
1985 /* time when info was obtained */
1986 DWORD timestamp;
1988 /* actual volume info */
1989 char * root_dir;
1990 DWORD serialnum;
1991 DWORD maxcomp;
1992 DWORD flags;
1993 char * name;
1994 char * type;
1995 } volume_info_data;
1997 /* Global referenced by various functions. */
1998 static volume_info_data volume_info;
2000 /* Vector to indicate which drives are local and fixed (for which cached
2001 data never expires). */
2002 static BOOL fixed_drives[26];
2004 /* Consider cached volume information to be stale if older than 10s,
2005 at least for non-local drives. Info for fixed drives is never stale. */
2006 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2007 #define VOLINFO_STILL_VALID( root_dir, info ) \
2008 ( ( isalpha (root_dir[0]) && \
2009 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2010 || GetTickCount () - info->timestamp < 10000 )
2012 /* Cache support functions. */
2014 /* Simple linked list with linear search is sufficient. */
2015 static volume_info_data *volume_cache = NULL;
2017 static volume_info_data *
2018 lookup_volume_info (char * root_dir)
2020 volume_info_data * info;
2022 for (info = volume_cache; info; info = info->next)
2023 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2024 break;
2025 return info;
2028 static void
2029 add_volume_info (char * root_dir, volume_info_data * info)
2031 info->root_dir = xstrdup (root_dir);
2032 info->next = volume_cache;
2033 volume_cache = info;
2037 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2038 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2039 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2040 static volume_info_data *
2041 GetCachedVolumeInformation (char * root_dir)
2043 volume_info_data * info;
2044 char default_root[ MAX_PATH ];
2046 /* NULL for root_dir means use root from current directory. */
2047 if (root_dir == NULL)
2049 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
2050 return NULL;
2051 parse_root (default_root, &root_dir);
2052 *root_dir = 0;
2053 root_dir = default_root;
2056 /* Local fixed drives can be cached permanently. Removable drives
2057 cannot be cached permanently, since the volume name and serial
2058 number (if nothing else) can change. Remote drives should be
2059 treated as if they are removable, since there is no sure way to
2060 tell whether they are or not. Also, the UNC association of drive
2061 letters mapped to remote volumes can be changed at any time (even
2062 by other processes) without notice.
2064 As a compromise, so we can benefit from caching info for remote
2065 volumes, we use a simple expiry mechanism to invalidate cache
2066 entries that are more than ten seconds old. */
2068 #if 0
2069 /* No point doing this, because WNetGetConnection is even slower than
2070 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2071 GetDriveType is about the only call of this type which does not
2072 involve network access, and so is extremely quick). */
2074 /* Map drive letter to UNC if remote. */
2075 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2077 char remote_name[ 256 ];
2078 char drive[3] = { root_dir[0], ':' };
2080 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2081 == NO_ERROR)
2082 /* do something */ ;
2084 #endif
2086 info = lookup_volume_info (root_dir);
2088 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2090 char name[ 256 ];
2091 DWORD serialnum;
2092 DWORD maxcomp;
2093 DWORD flags;
2094 char type[ 256 ];
2096 /* Info is not cached, or is stale. */
2097 if (!GetVolumeInformation (root_dir,
2098 name, sizeof (name),
2099 &serialnum,
2100 &maxcomp,
2101 &flags,
2102 type, sizeof (type)))
2103 return NULL;
2105 /* Cache the volume information for future use, overwriting existing
2106 entry if present. */
2107 if (info == NULL)
2109 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
2110 add_volume_info (root_dir, info);
2112 else
2114 xfree (info->name);
2115 xfree (info->type);
2118 info->name = xstrdup (name);
2119 info->serialnum = serialnum;
2120 info->maxcomp = maxcomp;
2121 info->flags = flags;
2122 info->type = xstrdup (type);
2123 info->timestamp = GetTickCount ();
2126 return info;
2129 /* Get information on the volume where name is held; set path pointer to
2130 start of pathname in name (past UNC header\volume header if present). */
2131 static int
2132 get_volume_info (const char * name, const char ** pPath)
2134 char temp[MAX_PATH];
2135 char *rootname = NULL; /* default to current volume */
2136 volume_info_data * info;
2138 if (name == NULL)
2139 return FALSE;
2141 /* find the root name of the volume if given */
2142 if (isalpha (name[0]) && name[1] == ':')
2144 rootname = temp;
2145 temp[0] = *name++;
2146 temp[1] = *name++;
2147 temp[2] = '\\';
2148 temp[3] = 0;
2150 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2152 char *str = temp;
2153 int slashes = 4;
2154 rootname = temp;
2157 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2158 break;
2159 *str++ = *name++;
2161 while ( *name );
2163 *str++ = '\\';
2164 *str = 0;
2167 if (pPath)
2168 *pPath = name;
2170 info = GetCachedVolumeInformation (rootname);
2171 if (info != NULL)
2173 /* Set global referenced by other functions. */
2174 volume_info = *info;
2175 return TRUE;
2177 return FALSE;
2180 /* Determine if volume is FAT format (ie. only supports short 8.3
2181 names); also set path pointer to start of pathname in name. */
2182 static int
2183 is_fat_volume (const char * name, const char ** pPath)
2185 if (get_volume_info (name, pPath))
2186 return (volume_info.maxcomp == 12);
2187 return FALSE;
2190 /* Map filename to a valid 8.3 name if necessary. */
2191 const char *
2192 map_w32_filename (const char * name, const char ** pPath)
2194 static char shortname[MAX_PATH];
2195 char * str = shortname;
2196 char c;
2197 char * path;
2198 const char * save_name = name;
2200 if (strlen (name) >= MAX_PATH)
2202 /* Return a filename which will cause callers to fail. */
2203 strcpy (shortname, "?");
2204 return shortname;
2207 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2209 register int left = 8; /* maximum number of chars in part */
2210 register int extn = 0; /* extension added? */
2211 register int dots = 2; /* maximum number of dots allowed */
2213 while (name < path)
2214 *str++ = *name++; /* skip past UNC header */
2216 while ((c = *name++))
2218 switch ( c )
2220 case '\\':
2221 case '/':
2222 *str++ = '\\';
2223 extn = 0; /* reset extension flags */
2224 dots = 2; /* max 2 dots */
2225 left = 8; /* max length 8 for main part */
2226 break;
2227 case ':':
2228 *str++ = ':';
2229 extn = 0; /* reset extension flags */
2230 dots = 2; /* max 2 dots */
2231 left = 8; /* max length 8 for main part */
2232 break;
2233 case '.':
2234 if ( dots )
2236 /* Convert path components of the form .xxx to _xxx,
2237 but leave . and .. as they are. This allows .emacs
2238 to be read as _emacs, for example. */
2240 if (! *name ||
2241 *name == '.' ||
2242 IS_DIRECTORY_SEP (*name))
2244 *str++ = '.';
2245 dots--;
2247 else
2249 *str++ = '_';
2250 left--;
2251 dots = 0;
2254 else if ( !extn )
2256 *str++ = '.';
2257 extn = 1; /* we've got an extension */
2258 left = 3; /* 3 chars in extension */
2260 else
2262 /* any embedded dots after the first are converted to _ */
2263 *str++ = '_';
2265 break;
2266 case '~':
2267 case '#': /* don't lose these, they're important */
2268 if ( ! left )
2269 str[-1] = c; /* replace last character of part */
2270 /* FALLTHRU */
2271 default:
2272 if ( left )
2274 *str++ = tolower (c); /* map to lower case (looks nicer) */
2275 left--;
2276 dots = 0; /* started a path component */
2278 break;
2281 *str = '\0';
2283 else
2285 strcpy (shortname, name);
2286 unixtodos_filename (shortname);
2289 if (pPath)
2290 *pPath = shortname + (path - save_name);
2292 return shortname;
2295 static int
2296 is_exec (const char * name)
2298 char * p = strrchr (name, '.');
2299 return
2300 (p != NULL
2301 && (xstrcasecmp (p, ".exe") == 0 ||
2302 xstrcasecmp (p, ".com") == 0 ||
2303 xstrcasecmp (p, ".bat") == 0 ||
2304 xstrcasecmp (p, ".cmd") == 0));
2307 /* Emulate the Unix directory procedures opendir, closedir,
2308 and readdir. We can't use the procedures supplied in sysdep.c,
2309 so we provide them here. */
2311 struct direct dir_static; /* simulated directory contents */
2312 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2313 static int dir_is_fat;
2314 static char dir_pathname[MAXPATHLEN+1];
2315 static WIN32_FIND_DATA dir_find_data;
2317 /* Support shares on a network resource as subdirectories of a read-only
2318 root directory. */
2319 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2320 static HANDLE open_unc_volume (const char *);
2321 static char *read_unc_volume (HANDLE, char *, int);
2322 static void close_unc_volume (HANDLE);
2324 DIR *
2325 opendir (char *filename)
2327 DIR *dirp;
2329 /* Opening is done by FindFirstFile. However, a read is inherent to
2330 this operation, so we defer the open until read time. */
2332 if (dir_find_handle != INVALID_HANDLE_VALUE)
2333 return NULL;
2334 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2335 return NULL;
2337 if (is_unc_volume (filename))
2339 wnet_enum_handle = open_unc_volume (filename);
2340 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2341 return NULL;
2344 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2345 return NULL;
2347 dirp->dd_fd = 0;
2348 dirp->dd_loc = 0;
2349 dirp->dd_size = 0;
2351 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2352 dir_pathname[MAXPATHLEN] = '\0';
2353 dir_is_fat = is_fat_volume (filename, NULL);
2355 return dirp;
2358 void
2359 closedir (DIR *dirp)
2361 /* If we have a find-handle open, close it. */
2362 if (dir_find_handle != INVALID_HANDLE_VALUE)
2364 FindClose (dir_find_handle);
2365 dir_find_handle = INVALID_HANDLE_VALUE;
2367 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2369 close_unc_volume (wnet_enum_handle);
2370 wnet_enum_handle = INVALID_HANDLE_VALUE;
2372 xfree ((char *) dirp);
2375 struct direct *
2376 readdir (DIR *dirp)
2378 int downcase = !NILP (Vw32_downcase_file_names);
2380 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2382 if (!read_unc_volume (wnet_enum_handle,
2383 dir_find_data.cFileName,
2384 MAX_PATH))
2385 return NULL;
2387 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2388 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2390 char filename[MAXNAMLEN + 3];
2391 int ln;
2393 strcpy (filename, dir_pathname);
2394 ln = strlen (filename) - 1;
2395 if (!IS_DIRECTORY_SEP (filename[ln]))
2396 strcat (filename, "\\");
2397 strcat (filename, "*");
2399 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2401 if (dir_find_handle == INVALID_HANDLE_VALUE)
2402 return NULL;
2404 else
2406 if (!FindNextFile (dir_find_handle, &dir_find_data))
2407 return NULL;
2410 /* Emacs never uses this value, so don't bother making it match
2411 value returned by stat(). */
2412 dir_static.d_ino = 1;
2414 strcpy (dir_static.d_name, dir_find_data.cFileName);
2416 /* If the file name in cFileName[] includes `?' characters, it means
2417 the original file name used characters that cannot be represented
2418 by the current ANSI codepage. To avoid total lossage, retrieve
2419 the short 8+3 alias of the long file name. */
2420 if (_mbspbrk (dir_static.d_name, "?"))
2422 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2423 downcase = 1; /* 8+3 aliases are returned in all caps */
2425 dir_static.d_namlen = strlen (dir_static.d_name);
2426 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
2427 dir_static.d_namlen - dir_static.d_namlen % 4;
2429 /* If the file name in cFileName[] includes `?' characters, it means
2430 the original file name used characters that cannot be represented
2431 by the current ANSI codepage. To avoid total lossage, retrieve
2432 the short 8+3 alias of the long file name. */
2433 if (_mbspbrk (dir_find_data.cFileName, "?"))
2435 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2436 /* 8+3 aliases are returned in all caps, which could break
2437 various alists that look at filenames' extensions. */
2438 downcase = 1;
2440 else
2441 strcpy (dir_static.d_name, dir_find_data.cFileName);
2442 dir_static.d_namlen = strlen (dir_static.d_name);
2443 if (dir_is_fat)
2444 _strlwr (dir_static.d_name);
2445 else if (downcase)
2447 register char *p;
2448 for (p = dir_static.d_name; *p; p++)
2449 if (*p >= 'a' && *p <= 'z')
2450 break;
2451 if (!*p)
2452 _strlwr (dir_static.d_name);
2455 return &dir_static;
2458 static HANDLE
2459 open_unc_volume (const char *path)
2461 NETRESOURCE nr;
2462 HANDLE henum;
2463 int result;
2465 nr.dwScope = RESOURCE_GLOBALNET;
2466 nr.dwType = RESOURCETYPE_DISK;
2467 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2468 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2469 nr.lpLocalName = NULL;
2470 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
2471 nr.lpComment = NULL;
2472 nr.lpProvider = NULL;
2474 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2475 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2477 if (result == NO_ERROR)
2478 return henum;
2479 else
2480 return INVALID_HANDLE_VALUE;
2483 static char *
2484 read_unc_volume (HANDLE henum, char *readbuf, int size)
2486 DWORD count;
2487 int result;
2488 DWORD bufsize = 512;
2489 char *buffer;
2490 char *ptr;
2492 count = 1;
2493 buffer = alloca (bufsize);
2494 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
2495 if (result != NO_ERROR)
2496 return NULL;
2498 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2499 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2500 ptr += 2;
2501 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2502 ptr++;
2504 strncpy (readbuf, ptr, size);
2505 return readbuf;
2508 static void
2509 close_unc_volume (HANDLE henum)
2511 if (henum != INVALID_HANDLE_VALUE)
2512 WNetCloseEnum (henum);
2515 static DWORD
2516 unc_volume_file_attributes (const char *path)
2518 HANDLE henum;
2519 DWORD attrs;
2521 henum = open_unc_volume (path);
2522 if (henum == INVALID_HANDLE_VALUE)
2523 return -1;
2525 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2527 close_unc_volume (henum);
2529 return attrs;
2532 /* Ensure a network connection is authenticated. */
2533 static void
2534 logon_network_drive (const char *path)
2536 NETRESOURCE resource;
2537 char share[MAX_PATH];
2538 int i, n_slashes;
2539 char drive[4];
2540 UINT drvtype;
2542 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
2543 drvtype = DRIVE_REMOTE;
2544 else if (path[0] == '\0' || path[1] != ':')
2545 drvtype = GetDriveType (NULL);
2546 else
2548 drive[0] = path[0];
2549 drive[1] = ':';
2550 drive[2] = '\\';
2551 drive[3] = '\0';
2552 drvtype = GetDriveType (drive);
2555 /* Only logon to networked drives. */
2556 if (drvtype != DRIVE_REMOTE)
2557 return;
2559 n_slashes = 2;
2560 strncpy (share, path, MAX_PATH);
2561 /* Truncate to just server and share name. */
2562 for (i = 2; i < MAX_PATH; i++)
2564 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2566 share[i] = '\0';
2567 break;
2571 resource.dwType = RESOURCETYPE_DISK;
2572 resource.lpLocalName = NULL;
2573 resource.lpRemoteName = share;
2574 resource.lpProvider = NULL;
2576 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2579 /* Shadow some MSVC runtime functions to map requests for long filenames
2580 to reasonable short names if necessary. This was originally added to
2581 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2582 long file names. */
2585 sys_access (const char * path, int mode)
2587 DWORD attributes;
2589 /* MSVC implementation doesn't recognize D_OK. */
2590 path = map_w32_filename (path, NULL);
2591 if (is_unc_volume (path))
2593 attributes = unc_volume_file_attributes (path);
2594 if (attributes == -1) {
2595 errno = EACCES;
2596 return -1;
2599 else if ((attributes = GetFileAttributes (path)) == -1)
2601 /* Should try mapping GetLastError to errno; for now just indicate
2602 that path doesn't exist. */
2603 errno = EACCES;
2604 return -1;
2606 if ((mode & X_OK) != 0 && !is_exec (path))
2608 errno = EACCES;
2609 return -1;
2611 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2613 errno = EACCES;
2614 return -1;
2616 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2618 errno = EACCES;
2619 return -1;
2621 return 0;
2625 sys_chdir (const char * path)
2627 return _chdir (map_w32_filename (path, NULL));
2631 sys_chmod (const char * path, int mode)
2633 return _chmod (map_w32_filename (path, NULL), mode);
2637 sys_chown (const char *path, uid_t owner, gid_t group)
2639 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2640 return -1;
2641 return 0;
2645 sys_creat (const char * path, int mode)
2647 return _creat (map_w32_filename (path, NULL), mode);
2650 FILE *
2651 sys_fopen (const char * path, const char * mode)
2653 int fd;
2654 int oflag;
2655 const char * mode_save = mode;
2657 /* Force all file handles to be non-inheritable. This is necessary to
2658 ensure child processes don't unwittingly inherit handles that might
2659 prevent future file access. */
2661 if (mode[0] == 'r')
2662 oflag = O_RDONLY;
2663 else if (mode[0] == 'w' || mode[0] == 'a')
2664 oflag = O_WRONLY | O_CREAT | O_TRUNC;
2665 else
2666 return NULL;
2668 /* Only do simplistic option parsing. */
2669 while (*++mode)
2670 if (mode[0] == '+')
2672 oflag &= ~(O_RDONLY | O_WRONLY);
2673 oflag |= O_RDWR;
2675 else if (mode[0] == 'b')
2677 oflag &= ~O_TEXT;
2678 oflag |= O_BINARY;
2680 else if (mode[0] == 't')
2682 oflag &= ~O_BINARY;
2683 oflag |= O_TEXT;
2685 else break;
2687 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2688 if (fd < 0)
2689 return NULL;
2691 return _fdopen (fd, mode_save);
2694 /* This only works on NTFS volumes, but is useful to have. */
2696 sys_link (const char * old, const char * new)
2698 HANDLE fileh;
2699 int result = -1;
2700 char oldname[MAX_PATH], newname[MAX_PATH];
2702 if (old == NULL || new == NULL)
2704 errno = ENOENT;
2705 return -1;
2708 strcpy (oldname, map_w32_filename (old, NULL));
2709 strcpy (newname, map_w32_filename (new, NULL));
2711 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2712 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2713 if (fileh != INVALID_HANDLE_VALUE)
2715 int wlen;
2717 /* Confusingly, the "alternate" stream name field does not apply
2718 when restoring a hard link, and instead contains the actual
2719 stream data for the link (ie. the name of the link to create).
2720 The WIN32_STREAM_ID structure before the cStreamName field is
2721 the stream header, which is then immediately followed by the
2722 stream data. */
2724 struct {
2725 WIN32_STREAM_ID wid;
2726 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2727 } data;
2729 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2730 data.wid.cStreamName, MAX_PATH);
2731 if (wlen > 0)
2733 LPVOID context = NULL;
2734 DWORD wbytes = 0;
2736 data.wid.dwStreamId = BACKUP_LINK;
2737 data.wid.dwStreamAttributes = 0;
2738 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
2739 data.wid.Size.HighPart = 0;
2740 data.wid.dwStreamNameSize = 0;
2742 if (BackupWrite (fileh, (LPBYTE)&data,
2743 offsetof (WIN32_STREAM_ID, cStreamName)
2744 + data.wid.Size.LowPart,
2745 &wbytes, FALSE, FALSE, &context)
2746 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2748 /* succeeded */
2749 result = 0;
2751 else
2753 /* Should try mapping GetLastError to errno; for now just
2754 indicate a general error (eg. links not supported). */
2755 errno = EINVAL; // perhaps EMLINK?
2759 CloseHandle (fileh);
2761 else
2762 errno = ENOENT;
2764 return result;
2768 sys_mkdir (const char * path)
2770 return _mkdir (map_w32_filename (path, NULL));
2773 /* Because of long name mapping issues, we need to implement this
2774 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2775 a unique name, instead of setting the input template to an empty
2776 string.
2778 Standard algorithm seems to be use pid or tid with a letter on the
2779 front (in place of the 6 X's) and cycle through the letters to find a
2780 unique name. We extend that to allow any reasonable character as the
2781 first of the 6 X's. */
2782 char *
2783 sys_mktemp (char * template)
2785 char * p;
2786 int i;
2787 unsigned uid = GetCurrentThreadId ();
2788 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2790 if (template == NULL)
2791 return NULL;
2792 p = template + strlen (template);
2793 i = 5;
2794 /* replace up to the last 5 X's with uid in decimal */
2795 while (--p >= template && p[0] == 'X' && --i >= 0)
2797 p[0] = '0' + uid % 10;
2798 uid /= 10;
2801 if (i < 0 && p[0] == 'X')
2803 i = 0;
2806 int save_errno = errno;
2807 p[0] = first_char[i];
2808 if (sys_access (template, 0) < 0)
2810 errno = save_errno;
2811 return template;
2814 while (++i < sizeof (first_char));
2817 /* Template is badly formed or else we can't generate a unique name,
2818 so return empty string */
2819 template[0] = 0;
2820 return template;
2824 sys_open (const char * path, int oflag, int mode)
2826 const char* mpath = map_w32_filename (path, NULL);
2827 /* Try to open file without _O_CREAT, to be able to write to hidden
2828 and system files. Force all file handles to be
2829 non-inheritable. */
2830 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2831 if (res >= 0)
2832 return res;
2833 return _open (mpath, oflag | _O_NOINHERIT, mode);
2837 sys_rename (const char * oldname, const char * newname)
2839 BOOL result;
2840 char temp[MAX_PATH];
2842 /* MoveFile on Windows 95 doesn't correctly change the short file name
2843 alias in a number of circumstances (it is not easy to predict when
2844 just by looking at oldname and newname, unfortunately). In these
2845 cases, renaming through a temporary name avoids the problem.
2847 A second problem on Windows 95 is that renaming through a temp name when
2848 newname is uppercase fails (the final long name ends up in
2849 lowercase, although the short alias might be uppercase) UNLESS the
2850 long temp name is not 8.3.
2852 So, on Windows 95 we always rename through a temp name, and we make sure
2853 the temp name has a long extension to ensure correct renaming. */
2855 strcpy (temp, map_w32_filename (oldname, NULL));
2857 if (os_subtype == OS_WIN95)
2859 char * o;
2860 char * p;
2861 int i = 0;
2863 oldname = map_w32_filename (oldname, NULL);
2864 if (o = strrchr (oldname, '\\'))
2865 o++;
2866 else
2867 o = (char *) oldname;
2869 if (p = strrchr (temp, '\\'))
2870 p++;
2871 else
2872 p = temp;
2876 /* Force temp name to require a manufactured 8.3 alias - this
2877 seems to make the second rename work properly. */
2878 sprintf (p, "_.%s.%u", o, i);
2879 i++;
2880 result = rename (oldname, temp);
2882 /* This loop must surely terminate! */
2883 while (result < 0 && errno == EEXIST);
2884 if (result < 0)
2885 return -1;
2888 /* Emulate Unix behavior - newname is deleted if it already exists
2889 (at least if it is a file; don't do this for directories).
2891 Since we mustn't do this if we are just changing the case of the
2892 file name (we would end up deleting the file we are trying to
2893 rename!), we let rename detect if the destination file already
2894 exists - that way we avoid the possible pitfalls of trying to
2895 determine ourselves whether two names really refer to the same
2896 file, which is not always possible in the general case. (Consider
2897 all the permutations of shared or subst'd drives, etc.) */
2899 newname = map_w32_filename (newname, NULL);
2900 result = rename (temp, newname);
2902 if (result < 0
2903 && errno == EEXIST
2904 && _chmod (newname, 0666) == 0
2905 && _unlink (newname) == 0)
2906 result = rename (temp, newname);
2908 return result;
2912 sys_rmdir (const char * path)
2914 return _rmdir (map_w32_filename (path, NULL));
2918 sys_unlink (const char * path)
2920 path = map_w32_filename (path, NULL);
2922 /* On Unix, unlink works without write permission. */
2923 _chmod (path, 0666);
2924 return _unlink (path);
2927 static FILETIME utc_base_ft;
2928 static ULONGLONG utc_base; /* In 100ns units */
2929 static int init = 0;
2931 #define FILETIME_TO_U64(result, ft) \
2932 do { \
2933 ULARGE_INTEGER uiTemp; \
2934 uiTemp.LowPart = (ft).dwLowDateTime; \
2935 uiTemp.HighPart = (ft).dwHighDateTime; \
2936 result = uiTemp.QuadPart; \
2937 } while (0)
2939 static void
2940 initialize_utc_base (void)
2942 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2943 SYSTEMTIME st;
2945 st.wYear = 1970;
2946 st.wMonth = 1;
2947 st.wDay = 1;
2948 st.wHour = 0;
2949 st.wMinute = 0;
2950 st.wSecond = 0;
2951 st.wMilliseconds = 0;
2953 SystemTimeToFileTime (&st, &utc_base_ft);
2954 FILETIME_TO_U64 (utc_base, utc_base_ft);
2957 static time_t
2958 convert_time (FILETIME ft)
2960 ULONGLONG tmp;
2962 if (!init)
2964 initialize_utc_base ();
2965 init = 1;
2968 if (CompareFileTime (&ft, &utc_base_ft) < 0)
2969 return 0;
2971 FILETIME_TO_U64 (tmp, ft);
2972 return (time_t) ((tmp - utc_base) / 10000000L);
2975 static void
2976 convert_from_time_t (time_t time, FILETIME * pft)
2978 ULARGE_INTEGER tmp;
2980 if (!init)
2982 initialize_utc_base ();
2983 init = 1;
2986 /* time in 100ns units since 1-Jan-1601 */
2987 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
2988 pft->dwHighDateTime = tmp.HighPart;
2989 pft->dwLowDateTime = tmp.LowPart;
2992 #if 0
2993 /* No reason to keep this; faking inode values either by hashing or even
2994 using the file index from GetInformationByHandle, is not perfect and
2995 so by default Emacs doesn't use the inode values on Windows.
2996 Instead, we now determine file-truename correctly (except for
2997 possible drive aliasing etc). */
2999 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3000 static unsigned
3001 hashval (const unsigned char * str)
3003 unsigned h = 0;
3004 while (*str)
3006 h = (h << 4) + *str++;
3007 h ^= (h >> 28);
3009 return h;
3012 /* Return the hash value of the canonical pathname, excluding the
3013 drive/UNC header, to get a hopefully unique inode number. */
3014 static DWORD
3015 generate_inode_val (const char * name)
3017 char fullname[ MAX_PATH ];
3018 char * p;
3019 unsigned hash;
3021 /* Get the truly canonical filename, if it exists. (Note: this
3022 doesn't resolve aliasing due to subst commands, or recognise hard
3023 links. */
3024 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3025 abort ();
3027 parse_root (fullname, &p);
3028 /* Normal W32 filesystems are still case insensitive. */
3029 _strlwr (p);
3030 return hashval (p);
3033 #endif
3035 static PSECURITY_DESCRIPTOR
3036 get_file_security_desc (const char *fname)
3038 PSECURITY_DESCRIPTOR psd = NULL;
3039 DWORD sd_len, err;
3040 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3041 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3043 if (!get_file_security (fname, si, psd, 0, &sd_len))
3045 err = GetLastError ();
3046 if (err != ERROR_INSUFFICIENT_BUFFER)
3047 return NULL;
3050 psd = xmalloc (sd_len);
3051 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3053 xfree (psd);
3054 return NULL;
3057 return psd;
3060 static DWORD
3061 get_rid (PSID sid)
3063 unsigned n_subauthorities;
3065 /* Use the last sub-authority value of the RID, the relative
3066 portion of the SID, as user/group ID. */
3067 n_subauthorities = *get_sid_sub_authority_count (sid);
3068 if (n_subauthorities < 1)
3069 return 0; /* the "World" RID */
3070 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3073 /* Caching SID and account values for faster lokup. */
3075 #ifdef __GNUC__
3076 # define FLEXIBLE_ARRAY_MEMBER
3077 #else
3078 # define FLEXIBLE_ARRAY_MEMBER 1
3079 #endif
3081 struct w32_id {
3082 unsigned rid;
3083 struct w32_id *next;
3084 char name[GNLEN+1];
3085 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3088 static struct w32_id *w32_idlist;
3090 static int
3091 w32_cached_id (PSID sid, unsigned *id, char *name)
3093 struct w32_id *tail, *found;
3095 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3097 if (equal_sid ((PSID)tail->sid, sid))
3099 found = tail;
3100 break;
3103 if (found)
3105 *id = found->rid;
3106 strcpy (name, found->name);
3107 return 1;
3109 else
3110 return 0;
3113 static void
3114 w32_add_to_cache (PSID sid, unsigned id, char *name)
3116 DWORD sid_len;
3117 struct w32_id *new_entry;
3119 /* We don't want to leave behind stale cache from when Emacs was
3120 dumped. */
3121 if (initialized)
3123 sid_len = get_length_sid (sid);
3124 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3125 if (new_entry)
3127 new_entry->rid = id;
3128 strcpy (new_entry->name, name);
3129 copy_sid (sid_len, (PSID)new_entry->sid, sid);
3130 new_entry->next = w32_idlist;
3131 w32_idlist = new_entry;
3136 #define UID 1
3137 #define GID 2
3139 static int
3140 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
3141 unsigned *id, char *nm, int what)
3143 PSID sid = NULL;
3144 char machine[MAX_COMPUTERNAME_LENGTH+1];
3145 BOOL dflt;
3146 SID_NAME_USE ignore;
3147 char name[UNLEN+1];
3148 DWORD name_len = sizeof (name);
3149 char domain[1024];
3150 DWORD domain_len = sizeof (domain);
3151 char *mp = NULL;
3152 int use_dflt = 0;
3153 int result;
3155 if (what == UID)
3156 result = get_security_descriptor_owner (psd, &sid, &dflt);
3157 else if (what == GID)
3158 result = get_security_descriptor_group (psd, &sid, &dflt);
3159 else
3160 result = 0;
3162 if (!result || !is_valid_sid (sid))
3163 use_dflt = 1;
3164 else if (!w32_cached_id (sid, id, nm))
3166 /* If FNAME is a UNC, we need to lookup account on the
3167 specified machine. */
3168 if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
3169 && fname[2] != '\0')
3171 const char *s;
3172 char *p;
3174 for (s = fname + 2, p = machine;
3175 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
3176 *p = *s;
3177 *p = '\0';
3178 mp = machine;
3181 if (!lookup_account_sid (mp, sid, name, &name_len,
3182 domain, &domain_len, &ignore)
3183 || name_len > UNLEN+1)
3184 use_dflt = 1;
3185 else
3187 *id = get_rid (sid);
3188 strcpy (nm, name);
3189 w32_add_to_cache (sid, *id, name);
3192 return use_dflt;
3195 static void
3196 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd,
3197 const char *fname,
3198 struct stat *st)
3200 int dflt_usr = 0, dflt_grp = 0;
3202 if (!psd)
3204 dflt_usr = 1;
3205 dflt_grp = 1;
3207 else
3209 if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
3210 dflt_usr = 1;
3211 if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
3212 dflt_grp = 1;
3214 /* Consider files to belong to current user/group, if we cannot get
3215 more accurate information. */
3216 if (dflt_usr)
3218 st->st_uid = dflt_passwd.pw_uid;
3219 strcpy (st->st_uname, dflt_passwd.pw_name);
3221 if (dflt_grp)
3223 st->st_gid = dflt_passwd.pw_gid;
3224 strcpy (st->st_gname, dflt_group.gr_name);
3228 /* Return non-zero if NAME is a potentially slow filesystem. */
3230 is_slow_fs (const char *name)
3232 char drive_root[4];
3233 UINT devtype;
3235 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
3236 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
3237 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
3238 devtype = GetDriveType (NULL); /* use root of current drive */
3239 else
3241 /* GetDriveType needs the root directory of the drive. */
3242 strncpy (drive_root, name, 2);
3243 drive_root[2] = '\\';
3244 drive_root[3] = '\0';
3245 devtype = GetDriveType (drive_root);
3247 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
3250 /* MSVC stat function can't cope with UNC names and has other bugs, so
3251 replace it with our own. This also allows us to calculate consistent
3252 inode values without hacks in the main Emacs code. */
3254 stat (const char * path, struct stat * buf)
3256 char *name, *r;
3257 char drive_root[4];
3258 UINT devtype;
3259 WIN32_FIND_DATA wfd;
3260 HANDLE fh;
3261 unsigned __int64 fake_inode;
3262 int permission;
3263 int len;
3264 int rootdir = FALSE;
3265 PSECURITY_DESCRIPTOR psd = NULL;
3267 if (path == NULL || buf == NULL)
3269 errno = EFAULT;
3270 return -1;
3273 name = (char *) map_w32_filename (path, &path);
3274 /* Must be valid filename, no wild cards or other invalid
3275 characters. We use _mbspbrk to support multibyte strings that
3276 might look to strpbrk as if they included literal *, ?, and other
3277 characters mentioned below that are disallowed by Windows
3278 filesystems. */
3279 if (_mbspbrk (name, "*?|<>\""))
3281 errno = ENOENT;
3282 return -1;
3285 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3286 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3287 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3289 r[1] = r[2] = '\0';
3292 /* Remove trailing directory separator, unless name is the root
3293 directory of a drive or UNC volume in which case ensure there
3294 is a trailing separator. */
3295 len = strlen (name);
3296 rootdir = (path >= name + len - 1
3297 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3298 name = strcpy (alloca (len + 2), name);
3300 if (is_unc_volume (name))
3302 DWORD attrs = unc_volume_file_attributes (name);
3304 if (attrs == -1)
3305 return -1;
3307 memset (&wfd, 0, sizeof (wfd));
3308 wfd.dwFileAttributes = attrs;
3309 wfd.ftCreationTime = utc_base_ft;
3310 wfd.ftLastAccessTime = utc_base_ft;
3311 wfd.ftLastWriteTime = utc_base_ft;
3312 strcpy (wfd.cFileName, name);
3314 else if (rootdir)
3316 if (!IS_DIRECTORY_SEP (name[len-1]))
3317 strcat (name, "\\");
3318 if (GetDriveType (name) < 2)
3320 errno = ENOENT;
3321 return -1;
3323 memset (&wfd, 0, sizeof (wfd));
3324 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
3325 wfd.ftCreationTime = utc_base_ft;
3326 wfd.ftLastAccessTime = utc_base_ft;
3327 wfd.ftLastWriteTime = utc_base_ft;
3328 strcpy (wfd.cFileName, name);
3330 else
3332 if (IS_DIRECTORY_SEP (name[len-1]))
3333 name[len - 1] = 0;
3335 /* (This is hacky, but helps when doing file completions on
3336 network drives.) Optimize by using information available from
3337 active readdir if possible. */
3338 len = strlen (dir_pathname);
3339 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3340 len--;
3341 if (dir_find_handle != INVALID_HANDLE_VALUE
3342 && strnicmp (name, dir_pathname, len) == 0
3343 && IS_DIRECTORY_SEP (name[len])
3344 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3346 /* This was the last entry returned by readdir. */
3347 wfd = dir_find_data;
3349 else
3351 logon_network_drive (name);
3353 fh = FindFirstFile (name, &wfd);
3354 if (fh == INVALID_HANDLE_VALUE)
3356 errno = ENOENT;
3357 return -1;
3359 FindClose (fh);
3363 if (!(NILP (Vw32_get_true_file_attributes)
3364 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
3365 /* No access rights required to get info. */
3366 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
3367 FILE_FLAG_BACKUP_SEMANTICS, NULL))
3368 != INVALID_HANDLE_VALUE)
3370 /* This is more accurate in terms of gettting the correct number
3371 of links, but is quite slow (it is noticeable when Emacs is
3372 making a list of file name completions). */
3373 BY_HANDLE_FILE_INFORMATION info;
3375 if (GetFileInformationByHandle (fh, &info))
3377 buf->st_nlink = info.nNumberOfLinks;
3378 /* Might as well use file index to fake inode values, but this
3379 is not guaranteed to be unique unless we keep a handle open
3380 all the time (even then there are situations where it is
3381 not unique). Reputedly, there are at most 48 bits of info
3382 (on NTFS, presumably less on FAT). */
3383 fake_inode = info.nFileIndexHigh;
3384 fake_inode <<= 32;
3385 fake_inode += info.nFileIndexLow;
3387 else
3389 buf->st_nlink = 1;
3390 fake_inode = 0;
3393 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3395 buf->st_mode = S_IFDIR;
3397 else
3399 switch (GetFileType (fh))
3401 case FILE_TYPE_DISK:
3402 buf->st_mode = S_IFREG;
3403 break;
3404 case FILE_TYPE_PIPE:
3405 buf->st_mode = S_IFIFO;
3406 break;
3407 case FILE_TYPE_CHAR:
3408 case FILE_TYPE_UNKNOWN:
3409 default:
3410 buf->st_mode = S_IFCHR;
3413 CloseHandle (fh);
3414 psd = get_file_security_desc (name);
3415 get_file_owner_and_group (psd, name, buf);
3417 else
3419 /* Don't bother to make this information more accurate. */
3420 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
3421 S_IFDIR : S_IFREG;
3422 buf->st_nlink = 1;
3423 fake_inode = 0;
3425 get_file_owner_and_group (NULL, name, buf);
3427 xfree (psd);
3429 #if 0
3430 /* Not sure if there is any point in this. */
3431 if (!NILP (Vw32_generate_fake_inodes))
3432 fake_inode = generate_inode_val (name);
3433 else if (fake_inode == 0)
3435 /* For want of something better, try to make everything unique. */
3436 static DWORD gen_num = 0;
3437 fake_inode = ++gen_num;
3439 #endif
3441 /* MSVC defines _ino_t to be short; other libc's might not. */
3442 if (sizeof (buf->st_ino) == 2)
3443 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3444 else
3445 buf->st_ino = fake_inode;
3447 /* volume_info is set indirectly by map_w32_filename */
3448 buf->st_dev = volume_info.serialnum;
3449 buf->st_rdev = volume_info.serialnum;
3451 buf->st_size = wfd.nFileSizeHigh;
3452 buf->st_size <<= 32;
3453 buf->st_size += wfd.nFileSizeLow;
3455 /* Convert timestamps to Unix format. */
3456 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
3457 buf->st_atime = convert_time (wfd.ftLastAccessTime);
3458 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3459 buf->st_ctime = convert_time (wfd.ftCreationTime);
3460 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3462 /* determine rwx permissions */
3463 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3464 permission = S_IREAD;
3465 else
3466 permission = S_IREAD | S_IWRITE;
3468 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3469 permission |= S_IEXEC;
3470 else if (is_exec (name))
3471 permission |= S_IEXEC;
3473 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3475 return 0;
3478 /* Provide fstat and utime as well as stat for consistent handling of
3479 file timestamps. */
3481 fstat (int desc, struct stat * buf)
3483 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3484 BY_HANDLE_FILE_INFORMATION info;
3485 unsigned __int64 fake_inode;
3486 int permission;
3488 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3490 case FILE_TYPE_DISK:
3491 buf->st_mode = S_IFREG;
3492 if (!GetFileInformationByHandle (fh, &info))
3494 errno = EACCES;
3495 return -1;
3497 break;
3498 case FILE_TYPE_PIPE:
3499 buf->st_mode = S_IFIFO;
3500 goto non_disk;
3501 case FILE_TYPE_CHAR:
3502 case FILE_TYPE_UNKNOWN:
3503 default:
3504 buf->st_mode = S_IFCHR;
3505 non_disk:
3506 memset (&info, 0, sizeof (info));
3507 info.dwFileAttributes = 0;
3508 info.ftCreationTime = utc_base_ft;
3509 info.ftLastAccessTime = utc_base_ft;
3510 info.ftLastWriteTime = utc_base_ft;
3513 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3514 buf->st_mode = S_IFDIR;
3516 buf->st_nlink = info.nNumberOfLinks;
3517 /* Might as well use file index to fake inode values, but this
3518 is not guaranteed to be unique unless we keep a handle open
3519 all the time (even then there are situations where it is
3520 not unique). Reputedly, there are at most 48 bits of info
3521 (on NTFS, presumably less on FAT). */
3522 fake_inode = info.nFileIndexHigh;
3523 fake_inode <<= 32;
3524 fake_inode += info.nFileIndexLow;
3526 /* MSVC defines _ino_t to be short; other libc's might not. */
3527 if (sizeof (buf->st_ino) == 2)
3528 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3529 else
3530 buf->st_ino = fake_inode;
3532 /* Consider files to belong to current user.
3533 FIXME: this should use GetSecurityInfo API, but it is only
3534 available for _WIN32_WINNT >= 0x501. */
3535 buf->st_uid = dflt_passwd.pw_uid;
3536 buf->st_gid = dflt_passwd.pw_gid;
3537 strcpy (buf->st_uname, dflt_passwd.pw_name);
3538 strcpy (buf->st_gname, dflt_group.gr_name);
3540 buf->st_dev = info.dwVolumeSerialNumber;
3541 buf->st_rdev = info.dwVolumeSerialNumber;
3543 buf->st_size = info.nFileSizeHigh;
3544 buf->st_size <<= 32;
3545 buf->st_size += info.nFileSizeLow;
3547 /* Convert timestamps to Unix format. */
3548 buf->st_mtime = convert_time (info.ftLastWriteTime);
3549 buf->st_atime = convert_time (info.ftLastAccessTime);
3550 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3551 buf->st_ctime = convert_time (info.ftCreationTime);
3552 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3554 /* determine rwx permissions */
3555 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3556 permission = S_IREAD;
3557 else
3558 permission = S_IREAD | S_IWRITE;
3560 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3561 permission |= S_IEXEC;
3562 else
3564 #if 0 /* no way of knowing the filename */
3565 char * p = strrchr (name, '.');
3566 if (p != NULL &&
3567 (xstrcasecmp (p, ".exe") == 0 ||
3568 xstrcasecmp (p, ".com") == 0 ||
3569 xstrcasecmp (p, ".bat") == 0 ||
3570 xstrcasecmp (p, ".cmd") == 0))
3571 permission |= S_IEXEC;
3572 #endif
3575 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3577 return 0;
3581 utime (const char *name, struct utimbuf *times)
3583 struct utimbuf deftime;
3584 HANDLE fh;
3585 FILETIME mtime;
3586 FILETIME atime;
3588 if (times == NULL)
3590 deftime.modtime = deftime.actime = time (NULL);
3591 times = &deftime;
3594 /* Need write access to set times. */
3595 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
3596 0, OPEN_EXISTING, 0, NULL);
3597 if (fh)
3599 convert_from_time_t (times->actime, &atime);
3600 convert_from_time_t (times->modtime, &mtime);
3601 if (!SetFileTime (fh, NULL, &atime, &mtime))
3603 CloseHandle (fh);
3604 errno = EACCES;
3605 return -1;
3607 CloseHandle (fh);
3609 else
3611 errno = EINVAL;
3612 return -1;
3614 return 0;
3618 /* Support for browsing other processes and their attributes. See
3619 process.c for the Lisp bindings. */
3621 /* Helper wrapper functions. */
3623 static HANDLE WINAPI
3624 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
3626 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
3628 if (g_b_init_create_toolhelp32_snapshot == 0)
3630 g_b_init_create_toolhelp32_snapshot = 1;
3631 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
3632 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3633 "CreateToolhelp32Snapshot");
3635 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
3637 return INVALID_HANDLE_VALUE;
3639 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
3642 static BOOL WINAPI
3643 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
3645 static Process32First_Proc s_pfn_Process32_First = NULL;
3647 if (g_b_init_process32_first == 0)
3649 g_b_init_process32_first = 1;
3650 s_pfn_Process32_First = (Process32First_Proc)
3651 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3652 "Process32First");
3654 if (s_pfn_Process32_First == NULL)
3656 return FALSE;
3658 return (s_pfn_Process32_First (hSnapshot, lppe));
3661 static BOOL WINAPI
3662 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
3664 static Process32Next_Proc s_pfn_Process32_Next = NULL;
3666 if (g_b_init_process32_next == 0)
3668 g_b_init_process32_next = 1;
3669 s_pfn_Process32_Next = (Process32Next_Proc)
3670 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3671 "Process32Next");
3673 if (s_pfn_Process32_Next == NULL)
3675 return FALSE;
3677 return (s_pfn_Process32_Next (hSnapshot, lppe));
3680 static BOOL WINAPI
3681 open_thread_token (HANDLE ThreadHandle,
3682 DWORD DesiredAccess,
3683 BOOL OpenAsSelf,
3684 PHANDLE TokenHandle)
3686 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
3687 HMODULE hm_advapi32 = NULL;
3688 if (is_windows_9x () == TRUE)
3690 SetLastError (ERROR_NOT_SUPPORTED);
3691 return FALSE;
3693 if (g_b_init_open_thread_token == 0)
3695 g_b_init_open_thread_token = 1;
3696 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3697 s_pfn_Open_Thread_Token =
3698 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
3700 if (s_pfn_Open_Thread_Token == NULL)
3702 SetLastError (ERROR_NOT_SUPPORTED);
3703 return FALSE;
3705 return (
3706 s_pfn_Open_Thread_Token (
3707 ThreadHandle,
3708 DesiredAccess,
3709 OpenAsSelf,
3710 TokenHandle)
3714 static BOOL WINAPI
3715 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
3717 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
3718 HMODULE hm_advapi32 = NULL;
3719 if (is_windows_9x () == TRUE)
3721 return FALSE;
3723 if (g_b_init_impersonate_self == 0)
3725 g_b_init_impersonate_self = 1;
3726 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3727 s_pfn_Impersonate_Self =
3728 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
3730 if (s_pfn_Impersonate_Self == NULL)
3732 return FALSE;
3734 return s_pfn_Impersonate_Self (ImpersonationLevel);
3737 static BOOL WINAPI
3738 revert_to_self (void)
3740 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
3741 HMODULE hm_advapi32 = NULL;
3742 if (is_windows_9x () == TRUE)
3744 return FALSE;
3746 if (g_b_init_revert_to_self == 0)
3748 g_b_init_revert_to_self = 1;
3749 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3750 s_pfn_Revert_To_Self =
3751 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
3753 if (s_pfn_Revert_To_Self == NULL)
3755 return FALSE;
3757 return s_pfn_Revert_To_Self ();
3760 static BOOL WINAPI
3761 get_process_memory_info (HANDLE h_proc,
3762 PPROCESS_MEMORY_COUNTERS mem_counters,
3763 DWORD bufsize)
3765 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
3766 HMODULE hm_psapi = NULL;
3767 if (is_windows_9x () == TRUE)
3769 return FALSE;
3771 if (g_b_init_get_process_memory_info == 0)
3773 g_b_init_get_process_memory_info = 1;
3774 hm_psapi = LoadLibrary ("Psapi.dll");
3775 if (hm_psapi)
3776 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
3777 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
3779 if (s_pfn_Get_Process_Memory_Info == NULL)
3781 return FALSE;
3783 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
3786 static BOOL WINAPI
3787 get_process_working_set_size (HANDLE h_proc,
3788 DWORD *minrss,
3789 DWORD *maxrss)
3791 static GetProcessWorkingSetSize_Proc
3792 s_pfn_Get_Process_Working_Set_Size = NULL;
3794 if (is_windows_9x () == TRUE)
3796 return FALSE;
3798 if (g_b_init_get_process_working_set_size == 0)
3800 g_b_init_get_process_working_set_size = 1;
3801 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
3802 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3803 "GetProcessWorkingSetSize");
3805 if (s_pfn_Get_Process_Working_Set_Size == NULL)
3807 return FALSE;
3809 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
3812 static BOOL WINAPI
3813 global_memory_status (MEMORYSTATUS *buf)
3815 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
3817 if (is_windows_9x () == TRUE)
3819 return FALSE;
3821 if (g_b_init_global_memory_status == 0)
3823 g_b_init_global_memory_status = 1;
3824 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
3825 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3826 "GlobalMemoryStatus");
3828 if (s_pfn_Global_Memory_Status == NULL)
3830 return FALSE;
3832 return s_pfn_Global_Memory_Status (buf);
3835 static BOOL WINAPI
3836 global_memory_status_ex (MEMORY_STATUS_EX *buf)
3838 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
3840 if (is_windows_9x () == TRUE)
3842 return FALSE;
3844 if (g_b_init_global_memory_status_ex == 0)
3846 g_b_init_global_memory_status_ex = 1;
3847 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
3848 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3849 "GlobalMemoryStatusEx");
3851 if (s_pfn_Global_Memory_Status_Ex == NULL)
3853 return FALSE;
3855 return s_pfn_Global_Memory_Status_Ex (buf);
3858 Lisp_Object
3859 list_system_processes (void)
3861 struct gcpro gcpro1;
3862 Lisp_Object proclist = Qnil;
3863 HANDLE h_snapshot;
3865 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
3867 if (h_snapshot != INVALID_HANDLE_VALUE)
3869 PROCESSENTRY32 proc_entry;
3870 DWORD proc_id;
3871 BOOL res;
3873 GCPRO1 (proclist);
3875 proc_entry.dwSize = sizeof (PROCESSENTRY32);
3876 for (res = process32_first (h_snapshot, &proc_entry); res;
3877 res = process32_next (h_snapshot, &proc_entry))
3879 proc_id = proc_entry.th32ProcessID;
3880 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
3883 CloseHandle (h_snapshot);
3884 UNGCPRO;
3885 proclist = Fnreverse (proclist);
3888 return proclist;
3891 static int
3892 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
3894 TOKEN_PRIVILEGES priv;
3895 DWORD priv_size = sizeof (priv);
3896 DWORD opriv_size = sizeof (*old_priv);
3897 HANDLE h_token = NULL;
3898 HANDLE h_thread = GetCurrentThread ();
3899 int ret_val = 0;
3900 BOOL res;
3902 res = open_thread_token (h_thread,
3903 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3904 FALSE, &h_token);
3905 if (!res && GetLastError () == ERROR_NO_TOKEN)
3907 if (impersonate_self (SecurityImpersonation))
3908 res = open_thread_token (h_thread,
3909 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3910 FALSE, &h_token);
3912 if (res)
3914 priv.PrivilegeCount = 1;
3915 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
3916 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
3917 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
3918 old_priv, &opriv_size)
3919 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3920 ret_val = 1;
3922 if (h_token)
3923 CloseHandle (h_token);
3925 return ret_val;
3928 static int
3929 restore_privilege (TOKEN_PRIVILEGES *priv)
3931 DWORD priv_size = sizeof (*priv);
3932 HANDLE h_token = NULL;
3933 int ret_val = 0;
3935 if (open_thread_token (GetCurrentThread (),
3936 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3937 FALSE, &h_token))
3939 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
3940 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3941 ret_val = 1;
3943 if (h_token)
3944 CloseHandle (h_token);
3946 return ret_val;
3949 static Lisp_Object
3950 ltime (long time_sec, long time_usec)
3952 return list3 (make_number ((time_sec >> 16) & 0xffff),
3953 make_number (time_sec & 0xffff),
3954 make_number (time_usec));
3957 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
3959 static int
3960 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
3961 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
3962 double *pcpu)
3964 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
3965 ULONGLONG tem1, tem2, tem3, tem;
3967 if (!h_proc
3968 || !get_process_times_fn
3969 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
3970 &ft_kernel, &ft_user))
3971 return 0;
3973 GetSystemTimeAsFileTime (&ft_current);
3975 FILETIME_TO_U64 (tem1, ft_kernel);
3976 tem1 /= 10L;
3977 *stime = U64_TO_LISP_TIME (tem1);
3979 FILETIME_TO_U64 (tem2, ft_user);
3980 tem2 /= 10L;
3981 *utime = U64_TO_LISP_TIME (tem2);
3983 tem3 = tem1 + tem2;
3984 *ttime = U64_TO_LISP_TIME (tem3);
3986 FILETIME_TO_U64 (tem, ft_creation);
3987 /* Process no 4 (System) returns zero creation time. */
3988 if (tem)
3989 tem = (tem - utc_base) / 10L;
3990 *ctime = U64_TO_LISP_TIME (tem);
3992 if (tem)
3994 FILETIME_TO_U64 (tem3, ft_current);
3995 tem = (tem3 - utc_base) / 10L - tem;
3997 *etime = U64_TO_LISP_TIME (tem);
3999 if (tem)
4001 *pcpu = 100.0 * (tem1 + tem2) / tem;
4002 if (*pcpu > 100)
4003 *pcpu = 100.0;
4005 else
4006 *pcpu = 0;
4008 return 1;
4011 Lisp_Object
4012 system_process_attributes (Lisp_Object pid)
4014 struct gcpro gcpro1, gcpro2, gcpro3;
4015 Lisp_Object attrs = Qnil;
4016 Lisp_Object cmd_str, decoded_cmd, tem;
4017 HANDLE h_snapshot, h_proc;
4018 DWORD proc_id;
4019 int found_proc = 0;
4020 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
4021 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
4022 DWORD glength = sizeof (gname);
4023 HANDLE token = NULL;
4024 SID_NAME_USE user_type;
4025 unsigned char *buf = NULL;
4026 DWORD blen = 0;
4027 TOKEN_USER user_token;
4028 TOKEN_PRIMARY_GROUP group_token;
4029 unsigned euid;
4030 unsigned egid;
4031 DWORD sess;
4032 PROCESS_MEMORY_COUNTERS mem;
4033 PROCESS_MEMORY_COUNTERS_EX mem_ex;
4034 DWORD minrss, maxrss;
4035 MEMORYSTATUS memst;
4036 MEMORY_STATUS_EX memstex;
4037 double totphys = 0.0;
4038 Lisp_Object ctime, stime, utime, etime, ttime;
4039 double pcpu;
4040 BOOL result = FALSE;
4042 CHECK_NUMBER_OR_FLOAT (pid);
4043 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
4045 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4047 GCPRO3 (attrs, decoded_cmd, tem);
4049 if (h_snapshot != INVALID_HANDLE_VALUE)
4051 PROCESSENTRY32 pe;
4052 BOOL res;
4054 pe.dwSize = sizeof (PROCESSENTRY32);
4055 for (res = process32_first (h_snapshot, &pe); res;
4056 res = process32_next (h_snapshot, &pe))
4058 if (proc_id == pe.th32ProcessID)
4060 if (proc_id == 0)
4061 decoded_cmd = build_string ("Idle");
4062 else
4064 /* Decode the command name from locale-specific
4065 encoding. */
4066 cmd_str = make_unibyte_string (pe.szExeFile,
4067 strlen (pe.szExeFile));
4068 decoded_cmd =
4069 code_convert_string_norecord (cmd_str,
4070 Vlocale_coding_system, 0);
4072 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
4073 attrs = Fcons (Fcons (Qppid,
4074 make_fixnum_or_float (pe.th32ParentProcessID)),
4075 attrs);
4076 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
4077 attrs);
4078 attrs = Fcons (Fcons (Qthcount,
4079 make_fixnum_or_float (pe.cntThreads)),
4080 attrs);
4081 found_proc = 1;
4082 break;
4086 CloseHandle (h_snapshot);
4089 if (!found_proc)
4091 UNGCPRO;
4092 return Qnil;
4095 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4096 FALSE, proc_id);
4097 /* If we were denied a handle to the process, try again after
4098 enabling the SeDebugPrivilege in our process. */
4099 if (!h_proc)
4101 TOKEN_PRIVILEGES priv_current;
4103 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
4105 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4106 FALSE, proc_id);
4107 restore_privilege (&priv_current);
4108 revert_to_self ();
4111 if (h_proc)
4113 result = open_process_token (h_proc, TOKEN_QUERY, &token);
4114 if (result)
4116 result = get_token_information (token, TokenUser, NULL, 0, &blen);
4117 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4119 buf = xmalloc (blen);
4120 result = get_token_information (token, TokenUser,
4121 (LPVOID)buf, blen, &needed);
4122 if (result)
4124 memcpy (&user_token, buf, sizeof (user_token));
4125 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
4127 euid = get_rid (user_token.User.Sid);
4128 result = lookup_account_sid (NULL, user_token.User.Sid,
4129 uname, &ulength,
4130 domain, &dlength,
4131 &user_type);
4132 if (result)
4133 w32_add_to_cache (user_token.User.Sid, euid, uname);
4134 else
4136 strcpy (uname, "unknown");
4137 result = TRUE;
4140 ulength = strlen (uname);
4144 if (result)
4146 /* Determine a reasonable euid and gid values. */
4147 if (xstrcasecmp ("administrator", uname) == 0)
4149 euid = 500; /* well-known Administrator uid */
4150 egid = 513; /* well-known None gid */
4152 else
4154 /* Get group id and name. */
4155 result = get_token_information (token, TokenPrimaryGroup,
4156 (LPVOID)buf, blen, &needed);
4157 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4159 buf = xrealloc (buf, blen = needed);
4160 result = get_token_information (token, TokenPrimaryGroup,
4161 (LPVOID)buf, blen, &needed);
4163 if (result)
4165 memcpy (&group_token, buf, sizeof (group_token));
4166 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
4168 egid = get_rid (group_token.PrimaryGroup);
4169 dlength = sizeof (domain);
4170 result =
4171 lookup_account_sid (NULL, group_token.PrimaryGroup,
4172 gname, &glength, NULL, &dlength,
4173 &user_type);
4174 if (result)
4175 w32_add_to_cache (group_token.PrimaryGroup,
4176 egid, gname);
4177 else
4179 strcpy (gname, "None");
4180 result = TRUE;
4183 glength = strlen (gname);
4187 xfree (buf);
4189 if (!result)
4191 if (!is_windows_9x ())
4193 /* We couldn't open the process token, presumably because of
4194 insufficient access rights. Assume this process is run
4195 by the system. */
4196 strcpy (uname, "SYSTEM");
4197 strcpy (gname, "None");
4198 euid = 18; /* SYSTEM */
4199 egid = 513; /* None */
4200 glength = strlen (gname);
4201 ulength = strlen (uname);
4203 /* If we are running under Windows 9X, where security calls are
4204 not supported, we assume all processes are run by the current
4205 user. */
4206 else if (GetUserName (uname, &ulength))
4208 if (xstrcasecmp ("administrator", uname) == 0)
4209 euid = 0;
4210 else
4211 euid = 123;
4212 egid = euid;
4213 strcpy (gname, "None");
4214 glength = strlen (gname);
4215 ulength = strlen (uname);
4217 else
4219 euid = 123;
4220 egid = 123;
4221 strcpy (uname, "administrator");
4222 ulength = strlen (uname);
4223 strcpy (gname, "None");
4224 glength = strlen (gname);
4226 if (token)
4227 CloseHandle (token);
4230 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
4231 tem = make_unibyte_string (uname, ulength);
4232 attrs = Fcons (Fcons (Quser,
4233 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4234 attrs);
4235 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
4236 tem = make_unibyte_string (gname, glength);
4237 attrs = Fcons (Fcons (Qgroup,
4238 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4239 attrs);
4241 if (global_memory_status_ex (&memstex))
4242 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4243 totphys = memstex.ullTotalPhys / 1024.0;
4244 #else
4245 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4246 double, so we need to do this for it... */
4248 DWORD tot_hi = memstex.ullTotalPhys >> 32;
4249 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
4250 DWORD tot_lo = memstex.ullTotalPhys % 1024;
4252 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
4254 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4255 else if (global_memory_status (&memst))
4256 totphys = memst.dwTotalPhys / 1024.0;
4258 if (h_proc
4259 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
4260 sizeof (mem_ex)))
4262 DWORD rss = mem_ex.WorkingSetSize / 1024;
4264 attrs = Fcons (Fcons (Qmajflt,
4265 make_fixnum_or_float (mem_ex.PageFaultCount)),
4266 attrs);
4267 attrs = Fcons (Fcons (Qvsize,
4268 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
4269 attrs);
4270 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4271 if (totphys)
4272 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4274 else if (h_proc
4275 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
4277 DWORD rss = mem_ex.WorkingSetSize / 1024;
4279 attrs = Fcons (Fcons (Qmajflt,
4280 make_fixnum_or_float (mem.PageFaultCount)),
4281 attrs);
4282 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4283 if (totphys)
4284 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4286 else if (h_proc
4287 && get_process_working_set_size (h_proc, &minrss, &maxrss))
4289 DWORD rss = maxrss / 1024;
4291 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
4292 if (totphys)
4293 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4296 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
4298 attrs = Fcons (Fcons (Qutime, utime), attrs);
4299 attrs = Fcons (Fcons (Qstime, stime), attrs);
4300 attrs = Fcons (Fcons (Qtime, ttime), attrs);
4301 attrs = Fcons (Fcons (Qstart, ctime), attrs);
4302 attrs = Fcons (Fcons (Qetime, etime), attrs);
4303 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
4306 /* FIXME: Retrieve command line by walking the PEB of the process. */
4308 if (h_proc)
4309 CloseHandle (h_proc);
4310 UNGCPRO;
4311 return attrs;
4315 /* Wrappers for winsock functions to map between our file descriptors
4316 and winsock's handles; also set h_errno for convenience.
4318 To allow Emacs to run on systems which don't have winsock support
4319 installed, we dynamically link to winsock on startup if present, and
4320 otherwise provide the minimum necessary functionality
4321 (eg. gethostname). */
4323 /* function pointers for relevant socket functions */
4324 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
4325 void (PASCAL *pfn_WSASetLastError) (int iError);
4326 int (PASCAL *pfn_WSAGetLastError) (void);
4327 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
4328 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
4329 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
4330 int (PASCAL *pfn_socket) (int af, int type, int protocol);
4331 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
4332 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
4333 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
4334 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
4335 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
4336 int (PASCAL *pfn_closesocket) (SOCKET s);
4337 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
4338 int (PASCAL *pfn_WSACleanup) (void);
4340 u_short (PASCAL *pfn_htons) (u_short hostshort);
4341 u_short (PASCAL *pfn_ntohs) (u_short netshort);
4342 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
4343 int (PASCAL *pfn_gethostname) (char * name, int namelen);
4344 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
4345 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
4346 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
4347 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
4348 const char * optval, int optlen);
4349 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
4350 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
4351 int * namelen);
4352 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
4353 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
4354 struct sockaddr * from, int * fromlen);
4355 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
4356 const struct sockaddr * to, int tolen);
4358 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4359 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
4360 #ifndef HANDLE_FLAG_INHERIT
4361 #define HANDLE_FLAG_INHERIT 1
4362 #endif
4364 HANDLE winsock_lib;
4365 static int winsock_inuse;
4367 BOOL
4368 term_winsock (void)
4370 if (winsock_lib != NULL && winsock_inuse == 0)
4372 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4373 after WSAStartup returns successfully, but it seems reasonable
4374 to allow unloading winsock anyway in that case. */
4375 if (pfn_WSACleanup () == 0 ||
4376 pfn_WSAGetLastError () == WSAENETDOWN)
4378 if (FreeLibrary (winsock_lib))
4379 winsock_lib = NULL;
4380 return TRUE;
4383 return FALSE;
4386 BOOL
4387 init_winsock (int load_now)
4389 WSADATA winsockData;
4391 if (winsock_lib != NULL)
4392 return TRUE;
4394 pfn_SetHandleInformation
4395 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4396 "SetHandleInformation");
4398 winsock_lib = LoadLibrary ("Ws2_32.dll");
4400 if (winsock_lib != NULL)
4402 /* dynamically link to socket functions */
4404 #define LOAD_PROC(fn) \
4405 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4406 goto fail;
4408 LOAD_PROC (WSAStartup);
4409 LOAD_PROC (WSASetLastError);
4410 LOAD_PROC (WSAGetLastError);
4411 LOAD_PROC (WSAEventSelect);
4412 LOAD_PROC (WSACreateEvent);
4413 LOAD_PROC (WSACloseEvent);
4414 LOAD_PROC (socket);
4415 LOAD_PROC (bind);
4416 LOAD_PROC (connect);
4417 LOAD_PROC (ioctlsocket);
4418 LOAD_PROC (recv);
4419 LOAD_PROC (send);
4420 LOAD_PROC (closesocket);
4421 LOAD_PROC (shutdown);
4422 LOAD_PROC (htons);
4423 LOAD_PROC (ntohs);
4424 LOAD_PROC (inet_addr);
4425 LOAD_PROC (gethostname);
4426 LOAD_PROC (gethostbyname);
4427 LOAD_PROC (getservbyname);
4428 LOAD_PROC (getpeername);
4429 LOAD_PROC (WSACleanup);
4430 LOAD_PROC (setsockopt);
4431 LOAD_PROC (listen);
4432 LOAD_PROC (getsockname);
4433 LOAD_PROC (accept);
4434 LOAD_PROC (recvfrom);
4435 LOAD_PROC (sendto);
4436 #undef LOAD_PROC
4438 /* specify version 1.1 of winsock */
4439 if (pfn_WSAStartup (0x101, &winsockData) == 0)
4441 if (winsockData.wVersion != 0x101)
4442 goto fail;
4444 if (!load_now)
4446 /* Report that winsock exists and is usable, but leave
4447 socket functions disabled. I am assuming that calling
4448 WSAStartup does not require any network interaction,
4449 and in particular does not cause or require a dial-up
4450 connection to be established. */
4452 pfn_WSACleanup ();
4453 FreeLibrary (winsock_lib);
4454 winsock_lib = NULL;
4456 winsock_inuse = 0;
4457 return TRUE;
4460 fail:
4461 FreeLibrary (winsock_lib);
4462 winsock_lib = NULL;
4465 return FALSE;
4469 int h_errno = 0;
4471 /* function to set h_errno for compatibility; map winsock error codes to
4472 normal system codes where they overlap (non-overlapping definitions
4473 are already in <sys/socket.h> */
4474 static void
4475 set_errno (void)
4477 if (winsock_lib == NULL)
4478 h_errno = EINVAL;
4479 else
4480 h_errno = pfn_WSAGetLastError ();
4482 switch (h_errno)
4484 case WSAEACCES: h_errno = EACCES; break;
4485 case WSAEBADF: h_errno = EBADF; break;
4486 case WSAEFAULT: h_errno = EFAULT; break;
4487 case WSAEINTR: h_errno = EINTR; break;
4488 case WSAEINVAL: h_errno = EINVAL; break;
4489 case WSAEMFILE: h_errno = EMFILE; break;
4490 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
4491 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
4493 errno = h_errno;
4496 static void
4497 check_errno (void)
4499 if (h_errno == 0 && winsock_lib != NULL)
4500 pfn_WSASetLastError (0);
4503 /* Extend strerror to handle the winsock-specific error codes. */
4504 struct {
4505 int errnum;
4506 char * msg;
4507 } _wsa_errlist[] = {
4508 WSAEINTR , "Interrupted function call",
4509 WSAEBADF , "Bad file descriptor",
4510 WSAEACCES , "Permission denied",
4511 WSAEFAULT , "Bad address",
4512 WSAEINVAL , "Invalid argument",
4513 WSAEMFILE , "Too many open files",
4515 WSAEWOULDBLOCK , "Resource temporarily unavailable",
4516 WSAEINPROGRESS , "Operation now in progress",
4517 WSAEALREADY , "Operation already in progress",
4518 WSAENOTSOCK , "Socket operation on non-socket",
4519 WSAEDESTADDRREQ , "Destination address required",
4520 WSAEMSGSIZE , "Message too long",
4521 WSAEPROTOTYPE , "Protocol wrong type for socket",
4522 WSAENOPROTOOPT , "Bad protocol option",
4523 WSAEPROTONOSUPPORT , "Protocol not supported",
4524 WSAESOCKTNOSUPPORT , "Socket type not supported",
4525 WSAEOPNOTSUPP , "Operation not supported",
4526 WSAEPFNOSUPPORT , "Protocol family not supported",
4527 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
4528 WSAEADDRINUSE , "Address already in use",
4529 WSAEADDRNOTAVAIL , "Cannot assign requested address",
4530 WSAENETDOWN , "Network is down",
4531 WSAENETUNREACH , "Network is unreachable",
4532 WSAENETRESET , "Network dropped connection on reset",
4533 WSAECONNABORTED , "Software caused connection abort",
4534 WSAECONNRESET , "Connection reset by peer",
4535 WSAENOBUFS , "No buffer space available",
4536 WSAEISCONN , "Socket is already connected",
4537 WSAENOTCONN , "Socket is not connected",
4538 WSAESHUTDOWN , "Cannot send after socket shutdown",
4539 WSAETOOMANYREFS , "Too many references", /* not sure */
4540 WSAETIMEDOUT , "Connection timed out",
4541 WSAECONNREFUSED , "Connection refused",
4542 WSAELOOP , "Network loop", /* not sure */
4543 WSAENAMETOOLONG , "Name is too long",
4544 WSAEHOSTDOWN , "Host is down",
4545 WSAEHOSTUNREACH , "No route to host",
4546 WSAENOTEMPTY , "Buffer not empty", /* not sure */
4547 WSAEPROCLIM , "Too many processes",
4548 WSAEUSERS , "Too many users", /* not sure */
4549 WSAEDQUOT , "Double quote in host name", /* really not sure */
4550 WSAESTALE , "Data is stale", /* not sure */
4551 WSAEREMOTE , "Remote error", /* not sure */
4553 WSASYSNOTREADY , "Network subsystem is unavailable",
4554 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
4555 WSANOTINITIALISED , "Winsock not initialized successfully",
4556 WSAEDISCON , "Graceful shutdown in progress",
4557 #ifdef WSAENOMORE
4558 WSAENOMORE , "No more operations allowed", /* not sure */
4559 WSAECANCELLED , "Operation cancelled", /* not sure */
4560 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
4561 WSAEINVALIDPROVIDER , "Invalid service provider version number",
4562 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
4563 WSASYSCALLFAILURE , "System call failure",
4564 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
4565 WSATYPE_NOT_FOUND , "Class type not found",
4566 WSA_E_NO_MORE , "No more resources available", /* really not sure */
4567 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
4568 WSAEREFUSED , "Operation refused", /* not sure */
4569 #endif
4571 WSAHOST_NOT_FOUND , "Host not found",
4572 WSATRY_AGAIN , "Authoritative host not found during name lookup",
4573 WSANO_RECOVERY , "Non-recoverable error during name lookup",
4574 WSANO_DATA , "Valid name, no data record of requested type",
4576 -1, NULL
4579 char *
4580 sys_strerror (int error_no)
4582 int i;
4583 static char unknown_msg[40];
4585 if (error_no >= 0 && error_no < sys_nerr)
4586 return sys_errlist[error_no];
4588 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
4589 if (_wsa_errlist[i].errnum == error_no)
4590 return _wsa_errlist[i].msg;
4592 sprintf (unknown_msg, "Unidentified error: %d", error_no);
4593 return unknown_msg;
4596 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4597 but I believe the method of keeping the socket handle separate (and
4598 insuring it is not inheritable) is the correct one. */
4600 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4602 static int socket_to_fd (SOCKET s);
4605 sys_socket (int af, int type, int protocol)
4607 SOCKET s;
4609 if (winsock_lib == NULL)
4611 h_errno = ENETDOWN;
4612 return INVALID_SOCKET;
4615 check_errno ();
4617 /* call the real socket function */
4618 s = pfn_socket (af, type, protocol);
4620 if (s != INVALID_SOCKET)
4621 return socket_to_fd (s);
4623 set_errno ();
4624 return -1;
4627 /* Convert a SOCKET to a file descriptor. */
4628 static int
4629 socket_to_fd (SOCKET s)
4631 int fd;
4632 child_process * cp;
4634 /* Although under NT 3.5 _open_osfhandle will accept a socket
4635 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4636 that does not work under NT 3.1. However, we can get the same
4637 effect by using a backdoor function to replace an existing
4638 descriptor handle with the one we want. */
4640 /* allocate a file descriptor (with appropriate flags) */
4641 fd = _open ("NUL:", _O_RDWR);
4642 if (fd >= 0)
4644 /* Make a non-inheritable copy of the socket handle. Note
4645 that it is possible that sockets aren't actually kernel
4646 handles, which appears to be the case on Windows 9x when
4647 the MS Proxy winsock client is installed. */
4649 /* Apparently there is a bug in NT 3.51 with some service
4650 packs, which prevents using DuplicateHandle to make a
4651 socket handle non-inheritable (causes WSACleanup to
4652 hang). The work-around is to use SetHandleInformation
4653 instead if it is available and implemented. */
4654 if (pfn_SetHandleInformation)
4656 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
4658 else
4660 HANDLE parent = GetCurrentProcess ();
4661 HANDLE new_s = INVALID_HANDLE_VALUE;
4663 if (DuplicateHandle (parent,
4664 (HANDLE) s,
4665 parent,
4666 &new_s,
4668 FALSE,
4669 DUPLICATE_SAME_ACCESS))
4671 /* It is possible that DuplicateHandle succeeds even
4672 though the socket wasn't really a kernel handle,
4673 because a real handle has the same value. So
4674 test whether the new handle really is a socket. */
4675 long nonblocking = 0;
4676 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
4678 pfn_closesocket (s);
4679 s = (SOCKET) new_s;
4681 else
4683 CloseHandle (new_s);
4688 fd_info[fd].hnd = (HANDLE) s;
4690 /* set our own internal flags */
4691 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
4693 cp = new_child ();
4694 if (cp)
4696 cp->fd = fd;
4697 cp->status = STATUS_READ_ACKNOWLEDGED;
4699 /* attach child_process to fd_info */
4700 if (fd_info[ fd ].cp != NULL)
4702 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
4703 abort ();
4706 fd_info[ fd ].cp = cp;
4708 /* success! */
4709 winsock_inuse++; /* count open sockets */
4710 return fd;
4713 /* clean up */
4714 _close (fd);
4716 pfn_closesocket (s);
4717 h_errno = EMFILE;
4718 return -1;
4722 sys_bind (int s, const struct sockaddr * addr, int namelen)
4724 if (winsock_lib == NULL)
4726 h_errno = ENOTSOCK;
4727 return SOCKET_ERROR;
4730 check_errno ();
4731 if (fd_info[s].flags & FILE_SOCKET)
4733 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
4734 if (rc == SOCKET_ERROR)
4735 set_errno ();
4736 return rc;
4738 h_errno = ENOTSOCK;
4739 return SOCKET_ERROR;
4743 sys_connect (int s, const struct sockaddr * name, int namelen)
4745 if (winsock_lib == NULL)
4747 h_errno = ENOTSOCK;
4748 return SOCKET_ERROR;
4751 check_errno ();
4752 if (fd_info[s].flags & FILE_SOCKET)
4754 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
4755 if (rc == SOCKET_ERROR)
4756 set_errno ();
4757 return rc;
4759 h_errno = ENOTSOCK;
4760 return SOCKET_ERROR;
4763 u_short
4764 sys_htons (u_short hostshort)
4766 return (winsock_lib != NULL) ?
4767 pfn_htons (hostshort) : hostshort;
4770 u_short
4771 sys_ntohs (u_short netshort)
4773 return (winsock_lib != NULL) ?
4774 pfn_ntohs (netshort) : netshort;
4777 unsigned long
4778 sys_inet_addr (const char * cp)
4780 return (winsock_lib != NULL) ?
4781 pfn_inet_addr (cp) : INADDR_NONE;
4785 sys_gethostname (char * name, int namelen)
4787 if (winsock_lib != NULL)
4788 return pfn_gethostname (name, namelen);
4790 if (namelen > MAX_COMPUTERNAME_LENGTH)
4791 return !GetComputerName (name, (DWORD *)&namelen);
4793 h_errno = EFAULT;
4794 return SOCKET_ERROR;
4797 struct hostent *
4798 sys_gethostbyname (const char * name)
4800 struct hostent * host;
4802 if (winsock_lib == NULL)
4804 h_errno = ENETDOWN;
4805 return NULL;
4808 check_errno ();
4809 host = pfn_gethostbyname (name);
4810 if (!host)
4811 set_errno ();
4812 return host;
4815 struct servent *
4816 sys_getservbyname (const char * name, const char * proto)
4818 struct servent * serv;
4820 if (winsock_lib == NULL)
4822 h_errno = ENETDOWN;
4823 return NULL;
4826 check_errno ();
4827 serv = pfn_getservbyname (name, proto);
4828 if (!serv)
4829 set_errno ();
4830 return serv;
4834 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
4836 if (winsock_lib == NULL)
4838 h_errno = ENETDOWN;
4839 return SOCKET_ERROR;
4842 check_errno ();
4843 if (fd_info[s].flags & FILE_SOCKET)
4845 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
4846 if (rc == SOCKET_ERROR)
4847 set_errno ();
4848 return rc;
4850 h_errno = ENOTSOCK;
4851 return SOCKET_ERROR;
4855 sys_shutdown (int s, int how)
4857 if (winsock_lib == NULL)
4859 h_errno = ENETDOWN;
4860 return SOCKET_ERROR;
4863 check_errno ();
4864 if (fd_info[s].flags & FILE_SOCKET)
4866 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
4867 if (rc == SOCKET_ERROR)
4868 set_errno ();
4869 return rc;
4871 h_errno = ENOTSOCK;
4872 return SOCKET_ERROR;
4876 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
4878 if (winsock_lib == NULL)
4880 h_errno = ENETDOWN;
4881 return SOCKET_ERROR;
4884 check_errno ();
4885 if (fd_info[s].flags & FILE_SOCKET)
4887 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
4888 (const char *)optval, optlen);
4889 if (rc == SOCKET_ERROR)
4890 set_errno ();
4891 return rc;
4893 h_errno = ENOTSOCK;
4894 return SOCKET_ERROR;
4898 sys_listen (int s, int backlog)
4900 if (winsock_lib == NULL)
4902 h_errno = ENETDOWN;
4903 return SOCKET_ERROR;
4906 check_errno ();
4907 if (fd_info[s].flags & FILE_SOCKET)
4909 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
4910 if (rc == SOCKET_ERROR)
4911 set_errno ();
4912 else
4913 fd_info[s].flags |= FILE_LISTEN;
4914 return rc;
4916 h_errno = ENOTSOCK;
4917 return SOCKET_ERROR;
4921 sys_getsockname (int s, struct sockaddr * name, int * namelen)
4923 if (winsock_lib == NULL)
4925 h_errno = ENETDOWN;
4926 return SOCKET_ERROR;
4929 check_errno ();
4930 if (fd_info[s].flags & FILE_SOCKET)
4932 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
4933 if (rc == SOCKET_ERROR)
4934 set_errno ();
4935 return rc;
4937 h_errno = ENOTSOCK;
4938 return SOCKET_ERROR;
4942 sys_accept (int s, struct sockaddr * addr, int * addrlen)
4944 if (winsock_lib == NULL)
4946 h_errno = ENETDOWN;
4947 return -1;
4950 check_errno ();
4951 if (fd_info[s].flags & FILE_LISTEN)
4953 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
4954 int fd = -1;
4955 if (t == INVALID_SOCKET)
4956 set_errno ();
4957 else
4958 fd = socket_to_fd (t);
4960 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
4961 ResetEvent (fd_info[s].cp->char_avail);
4962 return fd;
4964 h_errno = ENOTSOCK;
4965 return -1;
4969 sys_recvfrom (int s, char * buf, int len, int flags,
4970 struct sockaddr * from, int * fromlen)
4972 if (winsock_lib == NULL)
4974 h_errno = ENETDOWN;
4975 return SOCKET_ERROR;
4978 check_errno ();
4979 if (fd_info[s].flags & FILE_SOCKET)
4981 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
4982 if (rc == SOCKET_ERROR)
4983 set_errno ();
4984 return rc;
4986 h_errno = ENOTSOCK;
4987 return SOCKET_ERROR;
4991 sys_sendto (int s, const char * buf, int len, int flags,
4992 const struct sockaddr * to, int tolen)
4994 if (winsock_lib == NULL)
4996 h_errno = ENETDOWN;
4997 return SOCKET_ERROR;
5000 check_errno ();
5001 if (fd_info[s].flags & FILE_SOCKET)
5003 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
5004 if (rc == SOCKET_ERROR)
5005 set_errno ();
5006 return rc;
5008 h_errno = ENOTSOCK;
5009 return SOCKET_ERROR;
5012 /* Windows does not have an fcntl function. Provide an implementation
5013 solely for making sockets non-blocking. */
5015 fcntl (int s, int cmd, int options)
5017 if (winsock_lib == NULL)
5019 h_errno = ENETDOWN;
5020 return -1;
5023 check_errno ();
5024 if (fd_info[s].flags & FILE_SOCKET)
5026 if (cmd == F_SETFL && options == O_NDELAY)
5028 unsigned long nblock = 1;
5029 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
5030 if (rc == SOCKET_ERROR)
5031 set_errno ();
5032 /* Keep track of the fact that we set this to non-blocking. */
5033 fd_info[s].flags |= FILE_NDELAY;
5034 return rc;
5036 else
5038 h_errno = EINVAL;
5039 return SOCKET_ERROR;
5042 h_errno = ENOTSOCK;
5043 return SOCKET_ERROR;
5047 /* Shadow main io functions: we need to handle pipes and sockets more
5048 intelligently, and implement non-blocking mode as well. */
5051 sys_close (int fd)
5053 int rc;
5055 if (fd < 0)
5057 errno = EBADF;
5058 return -1;
5061 if (fd < MAXDESC && fd_info[fd].cp)
5063 child_process * cp = fd_info[fd].cp;
5065 fd_info[fd].cp = NULL;
5067 if (CHILD_ACTIVE (cp))
5069 /* if last descriptor to active child_process then cleanup */
5070 int i;
5071 for (i = 0; i < MAXDESC; i++)
5073 if (i == fd)
5074 continue;
5075 if (fd_info[i].cp == cp)
5076 break;
5078 if (i == MAXDESC)
5080 if (fd_info[fd].flags & FILE_SOCKET)
5082 if (winsock_lib == NULL) abort ();
5084 pfn_shutdown (SOCK_HANDLE (fd), 2);
5085 rc = pfn_closesocket (SOCK_HANDLE (fd));
5087 winsock_inuse--; /* count open sockets */
5089 delete_child (cp);
5094 /* Note that sockets do not need special treatment here (at least on
5095 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5096 closesocket is equivalent to CloseHandle, which is to be expected
5097 because socket handles are fully fledged kernel handles. */
5098 rc = _close (fd);
5100 if (rc == 0 && fd < MAXDESC)
5101 fd_info[fd].flags = 0;
5103 return rc;
5107 sys_dup (int fd)
5109 int new_fd;
5111 new_fd = _dup (fd);
5112 if (new_fd >= 0 && new_fd < MAXDESC)
5114 /* duplicate our internal info as well */
5115 fd_info[new_fd] = fd_info[fd];
5117 return new_fd;
5121 sys_dup2 (int src, int dst)
5123 int rc;
5125 if (dst < 0 || dst >= MAXDESC)
5127 errno = EBADF;
5128 return -1;
5131 /* make sure we close the destination first if it's a pipe or socket */
5132 if (src != dst && fd_info[dst].flags != 0)
5133 sys_close (dst);
5135 rc = _dup2 (src, dst);
5136 if (rc == 0)
5138 /* duplicate our internal info as well */
5139 fd_info[dst] = fd_info[src];
5141 return rc;
5144 /* Unix pipe() has only one arg */
5146 sys_pipe (int * phandles)
5148 int rc;
5149 unsigned flags;
5151 /* make pipe handles non-inheritable; when we spawn a child, we
5152 replace the relevant handle with an inheritable one. Also put
5153 pipes into binary mode; we will do text mode translation ourselves
5154 if required. */
5155 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
5157 if (rc == 0)
5159 /* Protect against overflow, since Windows can open more handles than
5160 our fd_info array has room for. */
5161 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
5163 _close (phandles[0]);
5164 _close (phandles[1]);
5165 rc = -1;
5167 else
5169 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
5170 fd_info[phandles[0]].flags = flags;
5172 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
5173 fd_info[phandles[1]].flags = flags;
5177 return rc;
5180 /* Function to do blocking read of one byte, needed to implement
5181 select. It is only allowed on sockets and pipes. */
5183 _sys_read_ahead (int fd)
5185 child_process * cp;
5186 int rc;
5188 if (fd < 0 || fd >= MAXDESC)
5189 return STATUS_READ_ERROR;
5191 cp = fd_info[fd].cp;
5193 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5194 return STATUS_READ_ERROR;
5196 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
5197 || (fd_info[fd].flags & FILE_READ) == 0)
5199 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
5200 abort ();
5203 cp->status = STATUS_READ_IN_PROGRESS;
5205 if (fd_info[fd].flags & FILE_PIPE)
5207 rc = _read (fd, &cp->chr, sizeof (char));
5209 /* Give subprocess time to buffer some more output for us before
5210 reporting that input is available; we need this because Windows 95
5211 connects DOS programs to pipes by making the pipe appear to be
5212 the normal console stdout - as a result most DOS programs will
5213 write to stdout without buffering, ie. one character at a
5214 time. Even some W32 programs do this - "dir" in a command
5215 shell on NT is very slow if we don't do this. */
5216 if (rc > 0)
5218 int wait = w32_pipe_read_delay;
5220 if (wait > 0)
5221 Sleep (wait);
5222 else if (wait < 0)
5223 while (++wait <= 0)
5224 /* Yield remainder of our time slice, effectively giving a
5225 temporary priority boost to the child process. */
5226 Sleep (0);
5229 else if (fd_info[fd].flags & FILE_SERIAL)
5231 HANDLE hnd = fd_info[fd].hnd;
5232 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5233 COMMTIMEOUTS ct;
5235 /* Configure timeouts for blocking read. */
5236 if (!GetCommTimeouts (hnd, &ct))
5237 return STATUS_READ_ERROR;
5238 ct.ReadIntervalTimeout = 0;
5239 ct.ReadTotalTimeoutMultiplier = 0;
5240 ct.ReadTotalTimeoutConstant = 0;
5241 if (!SetCommTimeouts (hnd, &ct))
5242 return STATUS_READ_ERROR;
5244 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
5246 if (GetLastError () != ERROR_IO_PENDING)
5247 return STATUS_READ_ERROR;
5248 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5249 return STATUS_READ_ERROR;
5252 else if (fd_info[fd].flags & FILE_SOCKET)
5254 unsigned long nblock = 0;
5255 /* We always want this to block, so temporarily disable NDELAY. */
5256 if (fd_info[fd].flags & FILE_NDELAY)
5257 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5259 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
5261 if (fd_info[fd].flags & FILE_NDELAY)
5263 nblock = 1;
5264 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5268 if (rc == sizeof (char))
5269 cp->status = STATUS_READ_SUCCEEDED;
5270 else
5271 cp->status = STATUS_READ_FAILED;
5273 return cp->status;
5277 _sys_wait_accept (int fd)
5279 HANDLE hEv;
5280 child_process * cp;
5281 int rc;
5283 if (fd < 0 || fd >= MAXDESC)
5284 return STATUS_READ_ERROR;
5286 cp = fd_info[fd].cp;
5288 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5289 return STATUS_READ_ERROR;
5291 cp->status = STATUS_READ_FAILED;
5293 hEv = pfn_WSACreateEvent ();
5294 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
5295 if (rc != SOCKET_ERROR)
5297 rc = WaitForSingleObject (hEv, INFINITE);
5298 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
5299 if (rc == WAIT_OBJECT_0)
5300 cp->status = STATUS_READ_SUCCEEDED;
5302 pfn_WSACloseEvent (hEv);
5304 return cp->status;
5308 sys_read (int fd, char * buffer, unsigned int count)
5310 int nchars;
5311 int to_read;
5312 DWORD waiting;
5313 char * orig_buffer = buffer;
5315 if (fd < 0)
5317 errno = EBADF;
5318 return -1;
5321 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5323 child_process *cp = fd_info[fd].cp;
5325 if ((fd_info[fd].flags & FILE_READ) == 0)
5327 errno = EBADF;
5328 return -1;
5331 nchars = 0;
5333 /* re-read CR carried over from last read */
5334 if (fd_info[fd].flags & FILE_LAST_CR)
5336 if (fd_info[fd].flags & FILE_BINARY) abort ();
5337 *buffer++ = 0x0d;
5338 count--;
5339 nchars++;
5340 fd_info[fd].flags &= ~FILE_LAST_CR;
5343 /* presence of a child_process structure means we are operating in
5344 non-blocking mode - otherwise we just call _read directly.
5345 Note that the child_process structure might be missing because
5346 reap_subprocess has been called; in this case the pipe is
5347 already broken, so calling _read on it is okay. */
5348 if (cp)
5350 int current_status = cp->status;
5352 switch (current_status)
5354 case STATUS_READ_FAILED:
5355 case STATUS_READ_ERROR:
5356 /* report normal EOF if nothing in buffer */
5357 if (nchars <= 0)
5358 fd_info[fd].flags |= FILE_AT_EOF;
5359 return nchars;
5361 case STATUS_READ_READY:
5362 case STATUS_READ_IN_PROGRESS:
5363 DebPrint (("sys_read called when read is in progress\n"));
5364 errno = EWOULDBLOCK;
5365 return -1;
5367 case STATUS_READ_SUCCEEDED:
5368 /* consume read-ahead char */
5369 *buffer++ = cp->chr;
5370 count--;
5371 nchars++;
5372 cp->status = STATUS_READ_ACKNOWLEDGED;
5373 ResetEvent (cp->char_avail);
5375 case STATUS_READ_ACKNOWLEDGED:
5376 break;
5378 default:
5379 DebPrint (("sys_read: bad status %d\n", current_status));
5380 errno = EBADF;
5381 return -1;
5384 if (fd_info[fd].flags & FILE_PIPE)
5386 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
5387 to_read = min (waiting, (DWORD) count);
5389 if (to_read > 0)
5390 nchars += _read (fd, buffer, to_read);
5392 else if (fd_info[fd].flags & FILE_SERIAL)
5394 HANDLE hnd = fd_info[fd].hnd;
5395 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5396 DWORD err = 0;
5397 int rc = 0;
5398 COMMTIMEOUTS ct;
5400 if (count > 0)
5402 /* Configure timeouts for non-blocking read. */
5403 if (!GetCommTimeouts (hnd, &ct))
5405 errno = EIO;
5406 return -1;
5408 ct.ReadIntervalTimeout = MAXDWORD;
5409 ct.ReadTotalTimeoutMultiplier = 0;
5410 ct.ReadTotalTimeoutConstant = 0;
5411 if (!SetCommTimeouts (hnd, &ct))
5413 errno = EIO;
5414 return -1;
5417 if (!ResetEvent (ovl->hEvent))
5419 errno = EIO;
5420 return -1;
5422 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
5424 if (GetLastError () != ERROR_IO_PENDING)
5426 errno = EIO;
5427 return -1;
5429 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5431 errno = EIO;
5432 return -1;
5435 nchars += rc;
5438 else /* FILE_SOCKET */
5440 if (winsock_lib == NULL) abort ();
5442 /* do the equivalent of a non-blocking read */
5443 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
5444 if (waiting == 0 && nchars == 0)
5446 h_errno = errno = EWOULDBLOCK;
5447 return -1;
5450 if (waiting)
5452 /* always use binary mode for sockets */
5453 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
5454 if (res == SOCKET_ERROR)
5456 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5457 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5458 set_errno ();
5459 return -1;
5461 nchars += res;
5465 else
5467 int nread = _read (fd, buffer, count);
5468 if (nread >= 0)
5469 nchars += nread;
5470 else if (nchars == 0)
5471 nchars = nread;
5474 if (nchars <= 0)
5475 fd_info[fd].flags |= FILE_AT_EOF;
5476 /* Perform text mode translation if required. */
5477 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
5479 nchars = crlf_to_lf (nchars, orig_buffer);
5480 /* If buffer contains only CR, return that. To be absolutely
5481 sure we should attempt to read the next char, but in
5482 practice a CR to be followed by LF would not appear by
5483 itself in the buffer. */
5484 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
5486 fd_info[fd].flags |= FILE_LAST_CR;
5487 nchars--;
5491 else
5492 nchars = _read (fd, buffer, count);
5494 return nchars;
5497 /* From w32xfns.c */
5498 extern HANDLE interrupt_handle;
5500 /* For now, don't bother with a non-blocking mode */
5502 sys_write (int fd, const void * buffer, unsigned int count)
5504 int nchars;
5506 if (fd < 0)
5508 errno = EBADF;
5509 return -1;
5512 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5514 if ((fd_info[fd].flags & FILE_WRITE) == 0)
5516 errno = EBADF;
5517 return -1;
5520 /* Perform text mode translation if required. */
5521 if ((fd_info[fd].flags & FILE_BINARY) == 0)
5523 char * tmpbuf = alloca (count * 2);
5524 unsigned char * src = (void *)buffer;
5525 unsigned char * dst = tmpbuf;
5526 int nbytes = count;
5528 while (1)
5530 unsigned char *next;
5531 /* copy next line or remaining bytes */
5532 next = _memccpy (dst, src, '\n', nbytes);
5533 if (next)
5535 /* copied one line ending with '\n' */
5536 int copied = next - dst;
5537 nbytes -= copied;
5538 src += copied;
5539 /* insert '\r' before '\n' */
5540 next[-1] = '\r';
5541 next[0] = '\n';
5542 dst = next + 1;
5543 count++;
5545 else
5546 /* copied remaining partial line -> now finished */
5547 break;
5549 buffer = tmpbuf;
5553 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
5555 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
5556 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
5557 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
5558 DWORD active = 0;
5560 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
5562 if (GetLastError () != ERROR_IO_PENDING)
5564 errno = EIO;
5565 return -1;
5567 if (detect_input_pending ())
5568 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
5569 QS_ALLINPUT);
5570 else
5571 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
5572 if (active == WAIT_OBJECT_0)
5573 { /* User pressed C-g, cancel write, then leave. Don't bother
5574 cleaning up as we may only get stuck in buggy drivers. */
5575 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
5576 CancelIo (hnd);
5577 errno = EIO;
5578 return -1;
5580 if (active == WAIT_OBJECT_0 + 1
5581 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
5583 errno = EIO;
5584 return -1;
5588 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
5590 unsigned long nblock = 0;
5591 if (winsock_lib == NULL) abort ();
5593 /* TODO: implement select() properly so non-blocking I/O works. */
5594 /* For now, make sure the write blocks. */
5595 if (fd_info[fd].flags & FILE_NDELAY)
5596 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5598 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
5600 /* Set the socket back to non-blocking if it was before,
5601 for other operations that support it. */
5602 if (fd_info[fd].flags & FILE_NDELAY)
5604 nblock = 1;
5605 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5608 if (nchars == SOCKET_ERROR)
5610 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5611 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5612 set_errno ();
5615 else
5617 /* Some networked filesystems don't like too large writes, so
5618 break them into smaller chunks. See the Comments section of
5619 the MSDN documentation of WriteFile for details behind the
5620 choice of the value of CHUNK below. See also the thread
5621 http://thread.gmane.org/gmane.comp.version-control.git/145294
5622 in the git mailing list. */
5623 const unsigned char *p = buffer;
5624 const unsigned chunk = 30 * 1024 * 1024;
5626 nchars = 0;
5627 while (count > 0)
5629 unsigned this_chunk = count < chunk ? count : chunk;
5630 int n = _write (fd, p, this_chunk);
5632 nchars += n;
5633 if (n < 0)
5635 nchars = n;
5636 break;
5638 else if (n < this_chunk)
5639 break;
5640 count -= n;
5641 p += n;
5645 return nchars;
5648 static void
5649 check_windows_init_file (void)
5651 extern int noninteractive, inhibit_window_system;
5653 /* A common indication that Emacs is not installed properly is when
5654 it cannot find the Windows installation file. If this file does
5655 not exist in the expected place, tell the user. */
5657 if (!noninteractive && !inhibit_window_system)
5659 Lisp_Object objs[2];
5660 Lisp_Object full_load_path;
5661 Lisp_Object init_file;
5662 int fd;
5664 objs[0] = Vload_path;
5665 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5666 full_load_path = Fappend (2, objs);
5667 init_file = build_string ("term/w32-win");
5668 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
5669 if (fd < 0)
5671 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
5672 char *init_file_name = SDATA (init_file);
5673 char *load_path = SDATA (load_path_print);
5674 char *buffer = alloca (1024
5675 + strlen (init_file_name)
5676 + strlen (load_path));
5678 sprintf (buffer,
5679 "The Emacs Windows initialization file \"%s.el\" "
5680 "could not be found in your Emacs installation. "
5681 "Emacs checked the following directories for this file:\n"
5682 "\n%s\n\n"
5683 "When Emacs cannot find this file, it usually means that it "
5684 "was not installed properly, or its distribution file was "
5685 "not unpacked properly.\nSee the README.W32 file in the "
5686 "top-level Emacs directory for more information.",
5687 init_file_name, load_path);
5688 MessageBox (NULL,
5689 buffer,
5690 "Emacs Abort Dialog",
5691 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
5692 /* Use the low-level Emacs abort. */
5693 #undef abort
5694 abort ();
5696 else
5698 _close (fd);
5703 void
5704 term_ntproc (void)
5706 /* shutdown the socket interface if necessary */
5707 term_winsock ();
5709 term_w32select ();
5712 void
5713 init_ntproc (void)
5715 /* Initialise the socket interface now if available and requested by
5716 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5717 delayed until open-network-stream is called (w32-has-winsock can
5718 also be used to dynamically load or reload winsock).
5720 Conveniently, init_environment is called before us, so
5721 PRELOAD_WINSOCK can be set in the registry. */
5723 /* Always initialize this correctly. */
5724 winsock_lib = NULL;
5726 if (getenv ("PRELOAD_WINSOCK") != NULL)
5727 init_winsock (TRUE);
5729 /* Initial preparation for subprocess support: replace our standard
5730 handles with non-inheritable versions. */
5732 HANDLE parent;
5733 HANDLE stdin_save = INVALID_HANDLE_VALUE;
5734 HANDLE stdout_save = INVALID_HANDLE_VALUE;
5735 HANDLE stderr_save = INVALID_HANDLE_VALUE;
5737 parent = GetCurrentProcess ();
5739 /* ignore errors when duplicating and closing; typically the
5740 handles will be invalid when running as a gui program. */
5741 DuplicateHandle (parent,
5742 GetStdHandle (STD_INPUT_HANDLE),
5743 parent,
5744 &stdin_save,
5746 FALSE,
5747 DUPLICATE_SAME_ACCESS);
5749 DuplicateHandle (parent,
5750 GetStdHandle (STD_OUTPUT_HANDLE),
5751 parent,
5752 &stdout_save,
5754 FALSE,
5755 DUPLICATE_SAME_ACCESS);
5757 DuplicateHandle (parent,
5758 GetStdHandle (STD_ERROR_HANDLE),
5759 parent,
5760 &stderr_save,
5762 FALSE,
5763 DUPLICATE_SAME_ACCESS);
5765 fclose (stdin);
5766 fclose (stdout);
5767 fclose (stderr);
5769 if (stdin_save != INVALID_HANDLE_VALUE)
5770 _open_osfhandle ((long) stdin_save, O_TEXT);
5771 else
5772 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
5773 _fdopen (0, "r");
5775 if (stdout_save != INVALID_HANDLE_VALUE)
5776 _open_osfhandle ((long) stdout_save, O_TEXT);
5777 else
5778 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5779 _fdopen (1, "w");
5781 if (stderr_save != INVALID_HANDLE_VALUE)
5782 _open_osfhandle ((long) stderr_save, O_TEXT);
5783 else
5784 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5785 _fdopen (2, "w");
5788 /* unfortunately, atexit depends on implementation of malloc */
5789 /* atexit (term_ntproc); */
5790 signal (SIGABRT, term_ntproc);
5792 /* determine which drives are fixed, for GetCachedVolumeInformation */
5794 /* GetDriveType must have trailing backslash. */
5795 char drive[] = "A:\\";
5797 /* Loop over all possible drive letters */
5798 while (*drive <= 'Z')
5800 /* Record if this drive letter refers to a fixed drive. */
5801 fixed_drives[DRIVE_INDEX (*drive)] =
5802 (GetDriveType (drive) == DRIVE_FIXED);
5804 (*drive)++;
5807 /* Reset the volume info cache. */
5808 volume_cache = NULL;
5811 /* Check to see if Emacs has been installed correctly. */
5812 check_windows_init_file ();
5816 shutdown_handler ensures that buffers' autosave files are
5817 up to date when the user logs off, or the system shuts down.
5819 static BOOL WINAPI
5820 shutdown_handler (DWORD type)
5822 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5823 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
5824 || type == CTRL_LOGOFF_EVENT /* User logs off. */
5825 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
5827 /* Shut down cleanly, making sure autosave files are up to date. */
5828 shut_down_emacs (0, 0, Qnil);
5831 /* Allow other handlers to handle this signal. */
5832 return FALSE;
5836 globals_of_w32 is used to initialize those global variables that
5837 must always be initialized on startup even when the global variable
5838 initialized is non zero (see the function main in emacs.c).
5840 void
5841 globals_of_w32 (void)
5843 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
5845 get_process_times_fn = (GetProcessTimes_Proc)
5846 GetProcAddress (kernel32, "GetProcessTimes");
5848 g_b_init_is_windows_9x = 0;
5849 g_b_init_open_process_token = 0;
5850 g_b_init_get_token_information = 0;
5851 g_b_init_lookup_account_sid = 0;
5852 g_b_init_get_sid_sub_authority = 0;
5853 g_b_init_get_sid_sub_authority_count = 0;
5854 g_b_init_get_file_security = 0;
5855 g_b_init_get_security_descriptor_owner = 0;
5856 g_b_init_get_security_descriptor_group = 0;
5857 g_b_init_is_valid_sid = 0;
5858 g_b_init_create_toolhelp32_snapshot = 0;
5859 g_b_init_process32_first = 0;
5860 g_b_init_process32_next = 0;
5861 g_b_init_open_thread_token = 0;
5862 g_b_init_impersonate_self = 0;
5863 g_b_init_revert_to_self = 0;
5864 g_b_init_get_process_memory_info = 0;
5865 g_b_init_get_process_working_set_size = 0;
5866 g_b_init_global_memory_status = 0;
5867 g_b_init_global_memory_status_ex = 0;
5868 g_b_init_equal_sid = 0;
5869 g_b_init_copy_sid = 0;
5870 g_b_init_get_length_sid = 0;
5871 g_b_init_get_native_system_info = 0;
5872 g_b_init_get_system_times = 0;
5873 num_of_processors = 0;
5874 /* The following sets a handler for shutdown notifications for
5875 console apps. This actually applies to Emacs in both console and
5876 GUI modes, since we had to fool windows into thinking emacs is a
5877 console application to get console mode to work. */
5878 SetConsoleCtrlHandler (shutdown_handler, TRUE);
5880 /* "None" is the default group name on standalone workstations. */
5881 strcpy (dflt_group_name, "None");
5884 /* For make-serial-process */
5886 serial_open (char *port)
5888 HANDLE hnd;
5889 child_process *cp;
5890 int fd = -1;
5892 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
5893 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
5894 if (hnd == INVALID_HANDLE_VALUE)
5895 error ("Could not open %s", port);
5896 fd = (int) _open_osfhandle ((int) hnd, 0);
5897 if (fd == -1)
5898 error ("Could not open %s", port);
5900 cp = new_child ();
5901 if (!cp)
5902 error ("Could not create child process");
5903 cp->fd = fd;
5904 cp->status = STATUS_READ_ACKNOWLEDGED;
5905 fd_info[ fd ].hnd = hnd;
5906 fd_info[ fd ].flags |=
5907 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
5908 if (fd_info[ fd ].cp != NULL)
5910 error ("fd_info[fd = %d] is already in use", fd);
5912 fd_info[ fd ].cp = cp;
5913 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5914 if (cp->ovl_read.hEvent == NULL)
5915 error ("Could not create read event");
5916 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5917 if (cp->ovl_write.hEvent == NULL)
5918 error ("Could not create write event");
5920 return fd;
5923 /* For serial-process-configure */
5924 void
5925 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
5927 Lisp_Object childp2 = Qnil;
5928 Lisp_Object tem = Qnil;
5929 HANDLE hnd;
5930 DCB dcb;
5931 COMMTIMEOUTS ct;
5932 char summary[4] = "???"; /* This usually becomes "8N1". */
5934 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
5935 error ("Not a serial process");
5936 hnd = fd_info[ p->outfd ].hnd;
5938 childp2 = Fcopy_sequence (p->childp);
5940 /* Initialize timeouts for blocking read and blocking write. */
5941 if (!GetCommTimeouts (hnd, &ct))
5942 error ("GetCommTimeouts() failed");
5943 ct.ReadIntervalTimeout = 0;
5944 ct.ReadTotalTimeoutMultiplier = 0;
5945 ct.ReadTotalTimeoutConstant = 0;
5946 ct.WriteTotalTimeoutMultiplier = 0;
5947 ct.WriteTotalTimeoutConstant = 0;
5948 if (!SetCommTimeouts (hnd, &ct))
5949 error ("SetCommTimeouts() failed");
5950 /* Read port attributes and prepare default configuration. */
5951 memset (&dcb, 0, sizeof (dcb));
5952 dcb.DCBlength = sizeof (DCB);
5953 if (!GetCommState (hnd, &dcb))
5954 error ("GetCommState() failed");
5955 dcb.fBinary = TRUE;
5956 dcb.fNull = FALSE;
5957 dcb.fAbortOnError = FALSE;
5958 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
5959 dcb.ErrorChar = 0;
5960 dcb.EofChar = 0;
5961 dcb.EvtChar = 0;
5963 /* Configure speed. */
5964 if (!NILP (Fplist_member (contact, QCspeed)))
5965 tem = Fplist_get (contact, QCspeed);
5966 else
5967 tem = Fplist_get (p->childp, QCspeed);
5968 CHECK_NUMBER (tem);
5969 dcb.BaudRate = XINT (tem);
5970 childp2 = Fplist_put (childp2, QCspeed, tem);
5972 /* Configure bytesize. */
5973 if (!NILP (Fplist_member (contact, QCbytesize)))
5974 tem = Fplist_get (contact, QCbytesize);
5975 else
5976 tem = Fplist_get (p->childp, QCbytesize);
5977 if (NILP (tem))
5978 tem = make_number (8);
5979 CHECK_NUMBER (tem);
5980 if (XINT (tem) != 7 && XINT (tem) != 8)
5981 error (":bytesize must be nil (8), 7, or 8");
5982 dcb.ByteSize = XINT (tem);
5983 summary[0] = XINT (tem) + '0';
5984 childp2 = Fplist_put (childp2, QCbytesize, tem);
5986 /* Configure parity. */
5987 if (!NILP (Fplist_member (contact, QCparity)))
5988 tem = Fplist_get (contact, QCparity);
5989 else
5990 tem = Fplist_get (p->childp, QCparity);
5991 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
5992 error (":parity must be nil (no parity), `even', or `odd'");
5993 dcb.fParity = FALSE;
5994 dcb.Parity = NOPARITY;
5995 dcb.fErrorChar = FALSE;
5996 if (NILP (tem))
5998 summary[1] = 'N';
6000 else if (EQ (tem, Qeven))
6002 summary[1] = 'E';
6003 dcb.fParity = TRUE;
6004 dcb.Parity = EVENPARITY;
6005 dcb.fErrorChar = TRUE;
6007 else if (EQ (tem, Qodd))
6009 summary[1] = 'O';
6010 dcb.fParity = TRUE;
6011 dcb.Parity = ODDPARITY;
6012 dcb.fErrorChar = TRUE;
6014 childp2 = Fplist_put (childp2, QCparity, tem);
6016 /* Configure stopbits. */
6017 if (!NILP (Fplist_member (contact, QCstopbits)))
6018 tem = Fplist_get (contact, QCstopbits);
6019 else
6020 tem = Fplist_get (p->childp, QCstopbits);
6021 if (NILP (tem))
6022 tem = make_number (1);
6023 CHECK_NUMBER (tem);
6024 if (XINT (tem) != 1 && XINT (tem) != 2)
6025 error (":stopbits must be nil (1 stopbit), 1, or 2");
6026 summary[2] = XINT (tem) + '0';
6027 if (XINT (tem) == 1)
6028 dcb.StopBits = ONESTOPBIT;
6029 else if (XINT (tem) == 2)
6030 dcb.StopBits = TWOSTOPBITS;
6031 childp2 = Fplist_put (childp2, QCstopbits, tem);
6033 /* Configure flowcontrol. */
6034 if (!NILP (Fplist_member (contact, QCflowcontrol)))
6035 tem = Fplist_get (contact, QCflowcontrol);
6036 else
6037 tem = Fplist_get (p->childp, QCflowcontrol);
6038 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
6039 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6040 dcb.fOutxCtsFlow = FALSE;
6041 dcb.fOutxDsrFlow = FALSE;
6042 dcb.fDtrControl = DTR_CONTROL_DISABLE;
6043 dcb.fDsrSensitivity = FALSE;
6044 dcb.fTXContinueOnXoff = FALSE;
6045 dcb.fOutX = FALSE;
6046 dcb.fInX = FALSE;
6047 dcb.fRtsControl = RTS_CONTROL_DISABLE;
6048 dcb.XonChar = 17; /* Control-Q */
6049 dcb.XoffChar = 19; /* Control-S */
6050 if (NILP (tem))
6052 /* Already configured. */
6054 else if (EQ (tem, Qhw))
6056 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
6057 dcb.fOutxCtsFlow = TRUE;
6059 else if (EQ (tem, Qsw))
6061 dcb.fOutX = TRUE;
6062 dcb.fInX = TRUE;
6064 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
6066 /* Activate configuration. */
6067 if (!SetCommState (hnd, &dcb))
6068 error ("SetCommState() failed");
6070 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
6071 p->childp = childp2;
6074 /* end of w32.c */