* lispref/modes.texi (Region to Refontify): Rename from "Region to Fontify".
[emacs.git] / src / w32.c
blob804d6d0c4bc11a2b6879fcfdc56f1ebf98868712
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>
38 #include <time.h>
40 /* must include CRT headers *before* config.h */
42 #ifdef HAVE_CONFIG_H
43 #include <config.h>
44 #endif
46 #undef access
47 #undef chdir
48 #undef chmod
49 #undef creat
50 #undef ctime
51 #undef fopen
52 #undef link
53 #undef mkdir
54 #undef mktemp
55 #undef open
56 #undef rename
57 #undef rmdir
58 #undef unlink
60 #undef close
61 #undef dup
62 #undef dup2
63 #undef pipe
64 #undef read
65 #undef write
67 #undef strerror
69 #undef localtime
71 #include "lisp.h"
73 #include <pwd.h>
74 #include <grp.h>
76 #ifdef __GNUC__
77 #define _ANONYMOUS_UNION
78 #define _ANONYMOUS_STRUCT
79 #endif
80 #include <windows.h>
81 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
82 use a different name to avoid compilation problems. */
83 typedef struct _MEMORY_STATUS_EX {
84 DWORD dwLength;
85 DWORD dwMemoryLoad;
86 DWORDLONG ullTotalPhys;
87 DWORDLONG ullAvailPhys;
88 DWORDLONG ullTotalPageFile;
89 DWORDLONG ullAvailPageFile;
90 DWORDLONG ullTotalVirtual;
91 DWORDLONG ullAvailVirtual;
92 DWORDLONG ullAvailExtendedVirtual;
93 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
95 #include <lmcons.h>
96 #include <shlobj.h>
98 #include <tlhelp32.h>
99 #include <psapi.h>
100 #include <w32api.h>
101 #if !defined(__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
102 /* This either is not in psapi.h or guarded by higher value of
103 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
104 defines it in psapi.h */
105 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
106 DWORD cb;
107 DWORD PageFaultCount;
108 DWORD PeakWorkingSetSize;
109 DWORD WorkingSetSize;
110 DWORD QuotaPeakPagedPoolUsage;
111 DWORD QuotaPagedPoolUsage;
112 DWORD QuotaPeakNonPagedPoolUsage;
113 DWORD QuotaNonPagedPoolUsage;
114 DWORD PagefileUsage;
115 DWORD PeakPagefileUsage;
116 DWORD PrivateUsage;
117 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
118 #endif
120 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
121 #include <sys/socket.h>
122 #undef socket
123 #undef bind
124 #undef connect
125 #undef htons
126 #undef ntohs
127 #undef inet_addr
128 #undef gethostname
129 #undef gethostbyname
130 #undef getservbyname
131 #undef getpeername
132 #undef shutdown
133 #undef setsockopt
134 #undef listen
135 #undef getsockname
136 #undef accept
137 #undef recvfrom
138 #undef sendto
139 #endif
141 #include "w32.h"
142 #include "ndir.h"
143 #include "w32heap.h"
144 #include "systime.h"
145 #include "dispextern.h" /* for xstrcasecmp */
146 #include "coding.h" /* for Vlocale_coding_system */
148 /* For serial_configure and serial_open. */
149 #include "process.h"
150 /* From process.c */
151 extern Lisp_Object QCport, QCspeed, QCprocess;
152 extern Lisp_Object QCbytesize, QCstopbits, QCparity, Qodd, Qeven;
153 extern Lisp_Object QCflowcontrol, Qhw, Qsw, QCsummary;
155 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
156 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
158 void globals_of_w32 ();
159 static DWORD get_rid (PSID);
161 extern Lisp_Object Vw32_downcase_file_names;
162 extern Lisp_Object Vw32_generate_fake_inodes;
163 extern Lisp_Object Vw32_get_true_file_attributes;
164 /* Defined in process.c for its own purpose. */
165 extern Lisp_Object Qlocal;
167 extern int w32_num_mouse_buttons;
170 /* Initialization states.
172 WARNING: If you add any more such variables for additional APIs,
173 you MUST add initialization for them to globals_of_w32
174 below. This is because these variables might get set
175 to non-NULL values during dumping, but the dumped Emacs
176 cannot reuse those values, because it could be run on a
177 different version of the OS, where API addresses are
178 different. */
179 static BOOL g_b_init_is_windows_9x;
180 static BOOL g_b_init_open_process_token;
181 static BOOL g_b_init_get_token_information;
182 static BOOL g_b_init_lookup_account_sid;
183 static BOOL g_b_init_get_sid_identifier_authority;
184 static BOOL g_b_init_get_sid_sub_authority;
185 static BOOL g_b_init_get_sid_sub_authority_count;
186 static BOOL g_b_init_get_file_security;
187 static BOOL g_b_init_get_security_descriptor_owner;
188 static BOOL g_b_init_get_security_descriptor_group;
189 static BOOL g_b_init_is_valid_sid;
190 static BOOL g_b_init_create_toolhelp32_snapshot;
191 static BOOL g_b_init_process32_first;
192 static BOOL g_b_init_process32_next;
193 static BOOL g_b_init_open_thread_token;
194 static BOOL g_b_init_impersonate_self;
195 static BOOL g_b_init_revert_to_self;
196 static BOOL g_b_init_get_process_memory_info;
197 static BOOL g_b_init_get_process_working_set_size;
198 static BOOL g_b_init_global_memory_status;
199 static BOOL g_b_init_global_memory_status_ex;
200 static BOOL g_b_init_get_length_sid;
201 static BOOL g_b_init_equal_sid;
202 static BOOL g_b_init_copy_sid;
203 static BOOL g_b_init_get_native_system_info;
204 static BOOL g_b_init_get_system_times;
207 BEGIN: Wrapper functions around OpenProcessToken
208 and other functions in advapi32.dll that are only
209 supported in Windows NT / 2k / XP
211 /* ** Function pointer typedefs ** */
212 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
213 HANDLE ProcessHandle,
214 DWORD DesiredAccess,
215 PHANDLE TokenHandle);
216 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
217 HANDLE TokenHandle,
218 TOKEN_INFORMATION_CLASS TokenInformationClass,
219 LPVOID TokenInformation,
220 DWORD TokenInformationLength,
221 PDWORD ReturnLength);
222 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
223 HANDLE process_handle,
224 LPFILETIME creation_time,
225 LPFILETIME exit_time,
226 LPFILETIME kernel_time,
227 LPFILETIME user_time);
229 GetProcessTimes_Proc get_process_times_fn = NULL;
231 #ifdef _UNICODE
232 const char * const LookupAccountSid_Name = "LookupAccountSidW";
233 const char * const GetFileSecurity_Name = "GetFileSecurityW";
234 #else
235 const char * const LookupAccountSid_Name = "LookupAccountSidA";
236 const char * const GetFileSecurity_Name = "GetFileSecurityA";
237 #endif
238 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
239 LPCTSTR lpSystemName,
240 PSID Sid,
241 LPTSTR Name,
242 LPDWORD cbName,
243 LPTSTR DomainName,
244 LPDWORD cbDomainName,
245 PSID_NAME_USE peUse);
246 typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) (
247 PSID pSid);
248 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
249 PSID pSid,
250 DWORD n);
251 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
252 PSID pSid);
253 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
254 LPCTSTR lpFileName,
255 SECURITY_INFORMATION RequestedInformation,
256 PSECURITY_DESCRIPTOR pSecurityDescriptor,
257 DWORD nLength,
258 LPDWORD lpnLengthNeeded);
259 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
260 PSECURITY_DESCRIPTOR pSecurityDescriptor,
261 PSID *pOwner,
262 LPBOOL lpbOwnerDefaulted);
263 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
264 PSECURITY_DESCRIPTOR pSecurityDescriptor,
265 PSID *pGroup,
266 LPBOOL lpbGroupDefaulted);
267 typedef BOOL (WINAPI * IsValidSid_Proc) (
268 PSID sid);
269 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
270 DWORD dwFlags,
271 DWORD th32ProcessID);
272 typedef BOOL (WINAPI * Process32First_Proc) (
273 HANDLE hSnapshot,
274 LPPROCESSENTRY32 lppe);
275 typedef BOOL (WINAPI * Process32Next_Proc) (
276 HANDLE hSnapshot,
277 LPPROCESSENTRY32 lppe);
278 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
279 HANDLE ThreadHandle,
280 DWORD DesiredAccess,
281 BOOL OpenAsSelf,
282 PHANDLE TokenHandle);
283 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
284 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
285 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
286 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
287 HANDLE Process,
288 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
289 DWORD cb);
290 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
291 HANDLE hProcess,
292 DWORD * lpMinimumWorkingSetSize,
293 DWORD * lpMaximumWorkingSetSize);
294 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
295 LPMEMORYSTATUS lpBuffer);
296 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
297 LPMEMORY_STATUS_EX lpBuffer);
298 typedef BOOL (WINAPI * CopySid_Proc) (
299 DWORD nDestinationSidLength,
300 PSID pDestinationSid,
301 PSID pSourceSid);
302 typedef BOOL (WINAPI * EqualSid_Proc) (
303 PSID pSid1,
304 PSID pSid2);
305 typedef DWORD (WINAPI * GetLengthSid_Proc) (
306 PSID pSid);
307 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
308 LPSYSTEM_INFO lpSystemInfo);
309 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
310 LPFILETIME lpIdleTime,
311 LPFILETIME lpKernelTime,
312 LPFILETIME lpUserTime);
316 /* ** A utility function ** */
317 static BOOL
318 is_windows_9x ()
320 static BOOL s_b_ret=0;
321 OSVERSIONINFO os_ver;
322 if (g_b_init_is_windows_9x == 0)
324 g_b_init_is_windows_9x = 1;
325 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
326 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
327 if (GetVersionEx (&os_ver))
329 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
332 return s_b_ret;
335 /* Get total user and system times for get-internal-run-time.
336 Returns a list of three integers if the times are provided by the OS
337 (NT derivatives), otherwise it returns the result of current-time. */
338 Lisp_Object
339 w32_get_internal_run_time ()
341 if (get_process_times_fn)
343 FILETIME create, exit, kernel, user;
344 HANDLE proc = GetCurrentProcess ();
345 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
347 LARGE_INTEGER user_int, kernel_int, total;
348 int microseconds;
349 user_int.LowPart = user.dwLowDateTime;
350 user_int.HighPart = user.dwHighDateTime;
351 kernel_int.LowPart = kernel.dwLowDateTime;
352 kernel_int.HighPart = kernel.dwHighDateTime;
353 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
354 /* FILETIME is 100 nanosecond increments, Emacs only wants
355 microsecond resolution. */
356 total.QuadPart /= 10;
357 microseconds = total.QuadPart % 1000000;
358 total.QuadPart /= 1000000;
360 /* Sanity check to make sure we can represent the result. */
361 if (total.HighPart == 0)
363 int secs = total.LowPart;
365 return list3 (make_number ((secs >> 16) & 0xffff),
366 make_number (secs & 0xffff),
367 make_number (microseconds));
372 return Fcurrent_time ();
375 /* ** The wrapper functions ** */
377 BOOL WINAPI
378 open_process_token (HANDLE ProcessHandle,
379 DWORD DesiredAccess,
380 PHANDLE TokenHandle)
382 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
383 HMODULE hm_advapi32 = NULL;
384 if (is_windows_9x () == TRUE)
386 return FALSE;
388 if (g_b_init_open_process_token == 0)
390 g_b_init_open_process_token = 1;
391 hm_advapi32 = LoadLibrary ("Advapi32.dll");
392 s_pfn_Open_Process_Token =
393 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
395 if (s_pfn_Open_Process_Token == NULL)
397 return FALSE;
399 return (
400 s_pfn_Open_Process_Token (
401 ProcessHandle,
402 DesiredAccess,
403 TokenHandle)
407 BOOL WINAPI
408 get_token_information (HANDLE TokenHandle,
409 TOKEN_INFORMATION_CLASS TokenInformationClass,
410 LPVOID TokenInformation,
411 DWORD TokenInformationLength,
412 PDWORD ReturnLength)
414 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
415 HMODULE hm_advapi32 = NULL;
416 if (is_windows_9x () == TRUE)
418 return FALSE;
420 if (g_b_init_get_token_information == 0)
422 g_b_init_get_token_information = 1;
423 hm_advapi32 = LoadLibrary ("Advapi32.dll");
424 s_pfn_Get_Token_Information =
425 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
427 if (s_pfn_Get_Token_Information == NULL)
429 return FALSE;
431 return (
432 s_pfn_Get_Token_Information (
433 TokenHandle,
434 TokenInformationClass,
435 TokenInformation,
436 TokenInformationLength,
437 ReturnLength)
441 BOOL WINAPI
442 lookup_account_sid (LPCTSTR lpSystemName,
443 PSID Sid,
444 LPTSTR Name,
445 LPDWORD cbName,
446 LPTSTR DomainName,
447 LPDWORD cbDomainName,
448 PSID_NAME_USE peUse)
450 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
451 HMODULE hm_advapi32 = NULL;
452 if (is_windows_9x () == TRUE)
454 return FALSE;
456 if (g_b_init_lookup_account_sid == 0)
458 g_b_init_lookup_account_sid = 1;
459 hm_advapi32 = LoadLibrary ("Advapi32.dll");
460 s_pfn_Lookup_Account_Sid =
461 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
463 if (s_pfn_Lookup_Account_Sid == NULL)
465 return FALSE;
467 return (
468 s_pfn_Lookup_Account_Sid (
469 lpSystemName,
470 Sid,
471 Name,
472 cbName,
473 DomainName,
474 cbDomainName,
475 peUse)
479 PSID_IDENTIFIER_AUTHORITY WINAPI
480 get_sid_identifier_authority (PSID pSid)
482 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority = NULL;
483 HMODULE hm_advapi32 = NULL;
484 if (is_windows_9x () == TRUE)
486 return NULL;
488 if (g_b_init_get_sid_identifier_authority == 0)
490 g_b_init_get_sid_identifier_authority = 1;
491 hm_advapi32 = LoadLibrary ("Advapi32.dll");
492 s_pfn_Get_Sid_Identifier_Authority =
493 (GetSidIdentifierAuthority_Proc) GetProcAddress (
494 hm_advapi32, "GetSidIdentifierAuthority");
496 if (s_pfn_Get_Sid_Identifier_Authority == NULL)
498 return NULL;
500 return (s_pfn_Get_Sid_Identifier_Authority (pSid));
503 PDWORD WINAPI
504 get_sid_sub_authority (PSID pSid, DWORD n)
506 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
507 static DWORD zero = 0U;
508 HMODULE hm_advapi32 = NULL;
509 if (is_windows_9x () == TRUE)
511 return &zero;
513 if (g_b_init_get_sid_sub_authority == 0)
515 g_b_init_get_sid_sub_authority = 1;
516 hm_advapi32 = LoadLibrary ("Advapi32.dll");
517 s_pfn_Get_Sid_Sub_Authority =
518 (GetSidSubAuthority_Proc) GetProcAddress (
519 hm_advapi32, "GetSidSubAuthority");
521 if (s_pfn_Get_Sid_Sub_Authority == NULL)
523 return &zero;
525 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
528 PUCHAR WINAPI
529 get_sid_sub_authority_count (PSID pSid)
531 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
532 static UCHAR zero = 0U;
533 HMODULE hm_advapi32 = NULL;
534 if (is_windows_9x () == TRUE)
536 return &zero;
538 if (g_b_init_get_sid_sub_authority_count == 0)
540 g_b_init_get_sid_sub_authority_count = 1;
541 hm_advapi32 = LoadLibrary ("Advapi32.dll");
542 s_pfn_Get_Sid_Sub_Authority_Count =
543 (GetSidSubAuthorityCount_Proc) GetProcAddress (
544 hm_advapi32, "GetSidSubAuthorityCount");
546 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
548 return &zero;
550 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
553 BOOL WINAPI
554 get_file_security (LPCTSTR lpFileName,
555 SECURITY_INFORMATION RequestedInformation,
556 PSECURITY_DESCRIPTOR pSecurityDescriptor,
557 DWORD nLength,
558 LPDWORD lpnLengthNeeded)
560 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
561 HMODULE hm_advapi32 = NULL;
562 if (is_windows_9x () == TRUE)
564 return FALSE;
566 if (g_b_init_get_file_security == 0)
568 g_b_init_get_file_security = 1;
569 hm_advapi32 = LoadLibrary ("Advapi32.dll");
570 s_pfn_Get_File_Security =
571 (GetFileSecurity_Proc) GetProcAddress (
572 hm_advapi32, GetFileSecurity_Name);
574 if (s_pfn_Get_File_Security == NULL)
576 return FALSE;
578 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
579 pSecurityDescriptor, nLength,
580 lpnLengthNeeded));
583 BOOL WINAPI
584 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
585 PSID *pOwner,
586 LPBOOL lpbOwnerDefaulted)
588 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
589 HMODULE hm_advapi32 = NULL;
590 if (is_windows_9x () == TRUE)
592 return FALSE;
594 if (g_b_init_get_security_descriptor_owner == 0)
596 g_b_init_get_security_descriptor_owner = 1;
597 hm_advapi32 = LoadLibrary ("Advapi32.dll");
598 s_pfn_Get_Security_Descriptor_Owner =
599 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
600 hm_advapi32, "GetSecurityDescriptorOwner");
602 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
604 return FALSE;
606 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
607 lpbOwnerDefaulted));
610 BOOL WINAPI
611 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
612 PSID *pGroup,
613 LPBOOL lpbGroupDefaulted)
615 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
616 HMODULE hm_advapi32 = NULL;
617 if (is_windows_9x () == TRUE)
619 return FALSE;
621 if (g_b_init_get_security_descriptor_group == 0)
623 g_b_init_get_security_descriptor_group = 1;
624 hm_advapi32 = LoadLibrary ("Advapi32.dll");
625 s_pfn_Get_Security_Descriptor_Group =
626 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
627 hm_advapi32, "GetSecurityDescriptorGroup");
629 if (s_pfn_Get_Security_Descriptor_Group == NULL)
631 return FALSE;
633 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
634 lpbGroupDefaulted));
637 BOOL WINAPI
638 is_valid_sid (PSID sid)
640 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
641 HMODULE hm_advapi32 = NULL;
642 if (is_windows_9x () == TRUE)
644 return FALSE;
646 if (g_b_init_is_valid_sid == 0)
648 g_b_init_is_valid_sid = 1;
649 hm_advapi32 = LoadLibrary ("Advapi32.dll");
650 s_pfn_Is_Valid_Sid =
651 (IsValidSid_Proc) GetProcAddress (
652 hm_advapi32, "IsValidSid");
654 if (s_pfn_Is_Valid_Sid == NULL)
656 return FALSE;
658 return (s_pfn_Is_Valid_Sid (sid));
661 BOOL WINAPI
662 equal_sid (PSID sid1, PSID sid2)
664 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
665 HMODULE hm_advapi32 = NULL;
666 if (is_windows_9x () == TRUE)
668 return FALSE;
670 if (g_b_init_equal_sid == 0)
672 g_b_init_equal_sid = 1;
673 hm_advapi32 = LoadLibrary ("Advapi32.dll");
674 s_pfn_Equal_Sid =
675 (EqualSid_Proc) GetProcAddress (
676 hm_advapi32, "EqualSid");
678 if (s_pfn_Equal_Sid == NULL)
680 return FALSE;
682 return (s_pfn_Equal_Sid (sid1, sid2));
685 DWORD WINAPI
686 get_length_sid (PSID sid)
688 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
689 HMODULE hm_advapi32 = NULL;
690 if (is_windows_9x () == TRUE)
692 return 0;
694 if (g_b_init_get_length_sid == 0)
696 g_b_init_get_length_sid = 1;
697 hm_advapi32 = LoadLibrary ("Advapi32.dll");
698 s_pfn_Get_Length_Sid =
699 (GetLengthSid_Proc) GetProcAddress (
700 hm_advapi32, "GetLengthSid");
702 if (s_pfn_Get_Length_Sid == NULL)
704 return 0;
706 return (s_pfn_Get_Length_Sid (sid));
709 BOOL WINAPI
710 copy_sid (DWORD destlen, PSID dest, PSID src)
712 static CopySid_Proc s_pfn_Copy_Sid = NULL;
713 HMODULE hm_advapi32 = NULL;
714 if (is_windows_9x () == TRUE)
716 return FALSE;
718 if (g_b_init_copy_sid == 0)
720 g_b_init_copy_sid = 1;
721 hm_advapi32 = LoadLibrary ("Advapi32.dll");
722 s_pfn_Copy_Sid =
723 (CopySid_Proc) GetProcAddress (
724 hm_advapi32, "CopySid");
726 if (s_pfn_Copy_Sid == NULL)
728 return FALSE;
730 return (s_pfn_Copy_Sid (destlen, dest, src));
734 END: Wrapper functions around OpenProcessToken
735 and other functions in advapi32.dll that are only
736 supported in Windows NT / 2k / XP
739 void WINAPI
740 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
742 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
743 if (is_windows_9x () != TRUE)
745 if (g_b_init_get_native_system_info == 0)
747 g_b_init_get_native_system_info = 1;
748 s_pfn_Get_Native_System_Info =
749 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
750 "GetNativeSystemInfo");
752 if (s_pfn_Get_Native_System_Info != NULL)
753 s_pfn_Get_Native_System_Info (lpSystemInfo);
755 else
756 lpSystemInfo->dwNumberOfProcessors = -1;
759 BOOL WINAPI
760 get_system_times (LPFILETIME lpIdleTime,
761 LPFILETIME lpKernelTime,
762 LPFILETIME lpUserTime)
764 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
765 if (is_windows_9x () == TRUE)
767 return FALSE;
769 if (g_b_init_get_system_times == 0)
771 g_b_init_get_system_times = 1;
772 s_pfn_Get_System_times =
773 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
774 "GetSystemTimes");
776 if (s_pfn_Get_System_times == NULL)
777 return FALSE;
778 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
781 /* Equivalent of strerror for W32 error codes. */
782 char *
783 w32_strerror (int error_no)
785 static char buf[500];
787 if (error_no == 0)
788 error_no = GetLastError ();
790 buf[0] = '\0';
791 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
792 error_no,
793 0, /* choose most suitable language */
794 buf, sizeof (buf), NULL))
795 sprintf (buf, "w32 error %u", error_no);
796 return buf;
799 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
800 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
802 This is called from alloc.c:valid_pointer_p. */
804 w32_valid_pointer_p (void *p, int size)
806 SIZE_T done;
807 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
809 if (h)
811 unsigned char *buf = alloca (size);
812 int retval = ReadProcessMemory (h, p, buf, size, &done);
814 CloseHandle (h);
815 return retval;
817 else
818 return -1;
821 static char startup_dir[MAXPATHLEN];
823 /* Get the current working directory. */
824 char *
825 getwd (char *dir)
827 #if 0
828 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
829 return dir;
830 return NULL;
831 #else
832 /* Emacs doesn't actually change directory itself, and we want to
833 force our real wd to be where emacs.exe is to avoid unnecessary
834 conflicts when trying to rename or delete directories. */
835 strcpy (dir, startup_dir);
836 return dir;
837 #endif
840 #ifndef HAVE_SOCKETS
841 /* Emulate gethostname. */
843 gethostname (char *buffer, int size)
845 /* NT only allows small host names, so the buffer is
846 certainly large enough. */
847 return !GetComputerName (buffer, &size);
849 #endif /* HAVE_SOCKETS */
851 /* Emulate getloadavg. */
853 struct load_sample {
854 time_t sample_time;
855 ULONGLONG idle;
856 ULONGLONG kernel;
857 ULONGLONG user;
860 /* Number of processors on this machine. */
861 static unsigned num_of_processors;
863 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
864 static struct load_sample samples[16*60];
865 static int first_idx = -1, last_idx = -1;
866 static int max_idx = sizeof (samples) / sizeof (samples[0]);
868 static int
869 buf_next (int from)
871 int next_idx = from + 1;
873 if (next_idx >= max_idx)
874 next_idx = 0;
876 return next_idx;
879 static int
880 buf_prev (int from)
882 int prev_idx = from - 1;
884 if (prev_idx < 0)
885 prev_idx = max_idx - 1;
887 return prev_idx;
890 static void
891 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
893 SYSTEM_INFO sysinfo;
894 FILETIME ft_idle, ft_user, ft_kernel;
896 /* Initialize the number of processors on this machine. */
897 if (num_of_processors <= 0)
899 get_native_system_info (&sysinfo);
900 num_of_processors = sysinfo.dwNumberOfProcessors;
901 if (num_of_processors <= 0)
903 GetSystemInfo (&sysinfo);
904 num_of_processors = sysinfo.dwNumberOfProcessors;
906 if (num_of_processors <= 0)
907 num_of_processors = 1;
910 /* TODO: Take into account threads that are ready to run, by
911 sampling the "\System\Processor Queue Length" performance
912 counter. The code below accounts only for threads that are
913 actually running. */
915 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
917 ULARGE_INTEGER uidle, ukernel, uuser;
919 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
920 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
921 memcpy (&uuser, &ft_user, sizeof (ft_user));
922 *idle = uidle.QuadPart;
923 *kernel = ukernel.QuadPart;
924 *user = uuser.QuadPart;
926 else
928 *idle = 0;
929 *kernel = 0;
930 *user = 0;
934 /* Produce the load average for a given time interval, using the
935 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
936 1-minute, 5-minute, or 15-minute average, respectively. */
937 static double
938 getavg (int which)
940 double retval = -1.0;
941 double tdiff;
942 int idx;
943 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
944 time_t now = samples[last_idx].sample_time;
946 if (first_idx != last_idx)
948 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
950 tdiff = difftime (now, samples[idx].sample_time);
951 if (tdiff >= span - 2*DBL_EPSILON*now)
953 long double sys =
954 samples[last_idx].kernel + samples[last_idx].user
955 - (samples[idx].kernel + samples[idx].user);
956 long double idl = samples[last_idx].idle - samples[idx].idle;
958 retval = (1.0 - idl / sys) * num_of_processors;
959 break;
961 if (idx == first_idx)
962 break;
966 return retval;
970 getloadavg (double loadavg[], int nelem)
972 int elem;
973 ULONGLONG idle, kernel, user;
974 time_t now = time (NULL);
976 /* Store another sample. We ignore samples that are less than 1 sec
977 apart. */
978 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
980 sample_system_load (&idle, &kernel, &user);
981 last_idx = buf_next (last_idx);
982 samples[last_idx].sample_time = now;
983 samples[last_idx].idle = idle;
984 samples[last_idx].kernel = kernel;
985 samples[last_idx].user = user;
986 /* If the buffer has more that 15 min worth of samples, discard
987 the old ones. */
988 if (first_idx == -1)
989 first_idx = last_idx;
990 while (first_idx != last_idx
991 && (difftime (now, samples[first_idx].sample_time)
992 >= 15.0*60 + 2*DBL_EPSILON*now))
993 first_idx = buf_next (first_idx);
996 for (elem = 0; elem < nelem; elem++)
998 double avg = getavg (elem);
1000 if (avg < 0)
1001 break;
1002 loadavg[elem] = avg;
1005 return elem;
1008 /* Emulate getpwuid, getpwnam and others. */
1010 #define PASSWD_FIELD_SIZE 256
1012 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1013 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1014 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1015 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
1016 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
1018 static struct passwd dflt_passwd =
1020 dflt_passwd_name,
1021 dflt_passwd_passwd,
1025 dflt_passwd_gecos,
1026 dflt_passwd_dir,
1027 dflt_passwd_shell,
1030 static char dflt_group_name[GNLEN+1];
1032 static struct group dflt_group =
1034 /* When group information is not available, we return this as the
1035 group for all files. */
1036 dflt_group_name,
1040 unsigned
1041 getuid ()
1043 return dflt_passwd.pw_uid;
1046 unsigned
1047 geteuid ()
1049 /* I could imagine arguing for checking to see whether the user is
1050 in the Administrators group and returning a UID of 0 for that
1051 case, but I don't know how wise that would be in the long run. */
1052 return getuid ();
1055 unsigned
1056 getgid ()
1058 return dflt_passwd.pw_gid;
1061 unsigned
1062 getegid ()
1064 return getgid ();
1067 struct passwd *
1068 getpwuid (unsigned uid)
1070 if (uid == dflt_passwd.pw_uid)
1071 return &dflt_passwd;
1072 return NULL;
1075 struct group *
1076 getgrgid (gid_t gid)
1078 return &dflt_group;
1081 struct passwd *
1082 getpwnam (char *name)
1084 struct passwd *pw;
1086 pw = getpwuid (getuid ());
1087 if (!pw)
1088 return pw;
1090 if (xstrcasecmp (name, pw->pw_name))
1091 return NULL;
1093 return pw;
1096 void
1097 init_user_info ()
1099 /* Find the user's real name by opening the process token and
1100 looking up the name associated with the user-sid in that token.
1102 Use the relative portion of the identifier authority value from
1103 the user-sid as the user id value (same for group id using the
1104 primary group sid from the process token). */
1106 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1107 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1108 DWORD glength = sizeof (gname);
1109 HANDLE token = NULL;
1110 SID_NAME_USE user_type;
1111 unsigned char *buf = NULL;
1112 DWORD blen = 0;
1113 TOKEN_USER user_token;
1114 TOKEN_PRIMARY_GROUP group_token;
1115 BOOL result;
1117 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1118 if (result)
1120 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1121 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1123 buf = xmalloc (blen);
1124 result = get_token_information (token, TokenUser,
1125 (LPVOID)buf, blen, &needed);
1126 if (result)
1128 memcpy (&user_token, buf, sizeof (user_token));
1129 result = lookup_account_sid (NULL, user_token.User.Sid,
1130 uname, &ulength,
1131 domain, &dlength, &user_type);
1134 else
1135 result = FALSE;
1137 if (result)
1139 strcpy (dflt_passwd.pw_name, uname);
1140 /* Determine a reasonable uid value. */
1141 if (xstrcasecmp ("administrator", uname) == 0)
1143 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1144 dflt_passwd.pw_gid = 513; /* well-known None gid */
1146 else
1148 /* Use the last sub-authority value of the RID, the relative
1149 portion of the SID, as user/group ID. */
1150 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1152 /* Get group id and name. */
1153 result = get_token_information (token, TokenPrimaryGroup,
1154 (LPVOID)buf, blen, &needed);
1155 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1157 buf = xrealloc (buf, blen = needed);
1158 result = get_token_information (token, TokenPrimaryGroup,
1159 (LPVOID)buf, blen, &needed);
1161 if (result)
1163 memcpy (&group_token, buf, sizeof (group_token));
1164 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1165 dlength = sizeof (domain);
1166 /* If we can get at the real Primary Group name, use that.
1167 Otherwise, the default group name was already set to
1168 "None" in globals_of_w32. */
1169 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1170 gname, &glength, NULL, &dlength,
1171 &user_type))
1172 strcpy (dflt_group_name, gname);
1174 else
1175 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1178 /* If security calls are not supported (presumably because we
1179 are running under Windows 9X), fallback to this: */
1180 else if (GetUserName (uname, &ulength))
1182 strcpy (dflt_passwd.pw_name, uname);
1183 if (xstrcasecmp ("administrator", uname) == 0)
1184 dflt_passwd.pw_uid = 0;
1185 else
1186 dflt_passwd.pw_uid = 123;
1187 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1189 else
1191 strcpy (dflt_passwd.pw_name, "unknown");
1192 dflt_passwd.pw_uid = 123;
1193 dflt_passwd.pw_gid = 123;
1195 dflt_group.gr_gid = dflt_passwd.pw_gid;
1197 /* Ensure HOME and SHELL are defined. */
1198 if (getenv ("HOME") == NULL)
1199 abort ();
1200 if (getenv ("SHELL") == NULL)
1201 abort ();
1203 /* Set dir and shell from environment variables. */
1204 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1205 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1207 xfree (buf);
1208 if (token)
1209 CloseHandle (token);
1213 random ()
1215 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1216 return ((rand () << 15) | rand ());
1219 void
1220 srandom (int seed)
1222 srand (seed);
1226 /* Normalize filename by converting all path separators to
1227 the specified separator. Also conditionally convert upper
1228 case path name components to lower case. */
1230 static void
1231 normalize_filename (fp, path_sep)
1232 register char *fp;
1233 char path_sep;
1235 char sep;
1236 char *elem;
1238 /* Always lower-case drive letters a-z, even if the filesystem
1239 preserves case in filenames.
1240 This is so filenames can be compared by string comparison
1241 functions that are case-sensitive. Even case-preserving filesystems
1242 do not distinguish case in drive letters. */
1243 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
1245 *fp += 'a' - 'A';
1246 fp += 2;
1249 if (NILP (Vw32_downcase_file_names))
1251 while (*fp)
1253 if (*fp == '/' || *fp == '\\')
1254 *fp = path_sep;
1255 fp++;
1257 return;
1260 sep = path_sep; /* convert to this path separator */
1261 elem = fp; /* start of current path element */
1263 do {
1264 if (*fp >= 'a' && *fp <= 'z')
1265 elem = 0; /* don't convert this element */
1267 if (*fp == 0 || *fp == ':')
1269 sep = *fp; /* restore current separator (or 0) */
1270 *fp = '/'; /* after conversion of this element */
1273 if (*fp == '/' || *fp == '\\')
1275 if (elem && elem != fp)
1277 *fp = 0; /* temporary end of string */
1278 _strlwr (elem); /* while we convert to lower case */
1280 *fp = sep; /* convert (or restore) path separator */
1281 elem = fp + 1; /* next element starts after separator */
1282 sep = path_sep;
1284 } while (*fp++);
1287 /* Destructively turn backslashes into slashes. */
1288 void
1289 dostounix_filename (p)
1290 register char *p;
1292 normalize_filename (p, '/');
1295 /* Destructively turn slashes into backslashes. */
1296 void
1297 unixtodos_filename (p)
1298 register char *p;
1300 normalize_filename (p, '\\');
1303 /* Remove all CR's that are followed by a LF.
1304 (From msdos.c...probably should figure out a way to share it,
1305 although this code isn't going to ever change.) */
1307 crlf_to_lf (n, buf)
1308 register int n;
1309 register unsigned char *buf;
1311 unsigned char *np = buf;
1312 unsigned char *startp = buf;
1313 unsigned char *endp = buf + n;
1315 if (n == 0)
1316 return n;
1317 while (buf < endp - 1)
1319 if (*buf == 0x0d)
1321 if (*(++buf) != 0x0a)
1322 *np++ = 0x0d;
1324 else
1325 *np++ = *buf++;
1327 if (buf < endp)
1328 *np++ = *buf++;
1329 return np - startp;
1332 /* Parse the root part of file name, if present. Return length and
1333 optionally store pointer to char after root. */
1334 static int
1335 parse_root (char * name, char ** pPath)
1337 char * start = name;
1339 if (name == NULL)
1340 return 0;
1342 /* find the root name of the volume if given */
1343 if (isalpha (name[0]) && name[1] == ':')
1345 /* skip past drive specifier */
1346 name += 2;
1347 if (IS_DIRECTORY_SEP (name[0]))
1348 name++;
1350 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1352 int slashes = 2;
1353 name += 2;
1356 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1357 break;
1358 name++;
1360 while ( *name );
1361 if (IS_DIRECTORY_SEP (name[0]))
1362 name++;
1365 if (pPath)
1366 *pPath = name;
1368 return name - start;
1371 /* Get long base name for name; name is assumed to be absolute. */
1372 static int
1373 get_long_basename (char * name, char * buf, int size)
1375 WIN32_FIND_DATA find_data;
1376 HANDLE dir_handle;
1377 int len = 0;
1379 /* must be valid filename, no wild cards or other invalid characters */
1380 if (_mbspbrk (name, "*?|<>\""))
1381 return 0;
1383 dir_handle = FindFirstFile (name, &find_data);
1384 if (dir_handle != INVALID_HANDLE_VALUE)
1386 if ((len = strlen (find_data.cFileName)) < size)
1387 memcpy (buf, find_data.cFileName, len + 1);
1388 else
1389 len = 0;
1390 FindClose (dir_handle);
1392 return len;
1395 /* Get long name for file, if possible (assumed to be absolute). */
1396 BOOL
1397 w32_get_long_filename (char * name, char * buf, int size)
1399 char * o = buf;
1400 char * p;
1401 char * q;
1402 char full[ MAX_PATH ];
1403 int len;
1405 len = strlen (name);
1406 if (len >= MAX_PATH)
1407 return FALSE;
1409 /* Use local copy for destructive modification. */
1410 memcpy (full, name, len+1);
1411 unixtodos_filename (full);
1413 /* Copy root part verbatim. */
1414 len = parse_root (full, &p);
1415 memcpy (o, full, len);
1416 o += len;
1417 *o = '\0';
1418 size -= len;
1420 while (p != NULL && *p)
1422 q = p;
1423 p = strchr (q, '\\');
1424 if (p) *p = '\0';
1425 len = get_long_basename (full, o, size);
1426 if (len > 0)
1428 o += len;
1429 size -= len;
1430 if (p != NULL)
1432 *p++ = '\\';
1433 if (size < 2)
1434 return FALSE;
1435 *o++ = '\\';
1436 size--;
1437 *o = '\0';
1440 else
1441 return FALSE;
1444 return TRUE;
1448 is_unc_volume (const char *filename)
1450 const char *ptr = filename;
1452 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1453 return 0;
1455 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1456 return 0;
1458 return 1;
1461 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1464 sigsetmask (int signal_mask)
1466 return 0;
1470 sigmask (int sig)
1472 return 0;
1476 sigblock (int sig)
1478 return 0;
1482 sigunblock (int sig)
1484 return 0;
1488 setpgrp (int pid, int gid)
1490 return 0;
1494 alarm (int seconds)
1496 return 0;
1499 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1501 LPBYTE
1502 w32_get_resource (key, lpdwtype)
1503 char *key;
1504 LPDWORD lpdwtype;
1506 LPBYTE lpvalue;
1507 HKEY hrootkey = NULL;
1508 DWORD cbData;
1510 /* Check both the current user and the local machine to see if
1511 we have any resources. */
1513 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1515 lpvalue = NULL;
1517 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1518 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1519 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1521 RegCloseKey (hrootkey);
1522 return (lpvalue);
1525 xfree (lpvalue);
1527 RegCloseKey (hrootkey);
1530 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1532 lpvalue = NULL;
1534 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1535 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1536 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1538 RegCloseKey (hrootkey);
1539 return (lpvalue);
1542 xfree (lpvalue);
1544 RegCloseKey (hrootkey);
1547 return (NULL);
1550 char *get_emacs_configuration (void);
1551 extern Lisp_Object Vsystem_configuration;
1553 void
1554 init_environment (char ** argv)
1556 static const char * const tempdirs[] = {
1557 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1560 int i;
1562 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1564 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1565 temporary files and assume "/tmp" if $TMPDIR is unset, which
1566 will break on DOS/Windows. Refuse to work if we cannot find
1567 a directory, not even "c:/", usable for that purpose. */
1568 for (i = 0; i < imax ; i++)
1570 const char *tmp = tempdirs[i];
1572 if (*tmp == '$')
1573 tmp = getenv (tmp + 1);
1574 /* Note that `access' can lie to us if the directory resides on a
1575 read-only filesystem, like CD-ROM or a write-protected floppy.
1576 The only way to be really sure is to actually create a file and
1577 see if it succeeds. But I think that's too much to ask. */
1578 if (tmp && _access (tmp, D_OK) == 0)
1580 char * var = alloca (strlen (tmp) + 8);
1581 sprintf (var, "TMPDIR=%s", tmp);
1582 _putenv (strdup (var));
1583 break;
1586 if (i >= imax)
1587 cmd_error_internal
1588 (Fcons (Qerror,
1589 Fcons (build_string ("no usable temporary directories found!!"),
1590 Qnil)),
1591 "While setting TMPDIR: ");
1593 /* Check for environment variables and use registry settings if they
1594 don't exist. Fallback on default values where applicable. */
1596 int i;
1597 LPBYTE lpval;
1598 DWORD dwType;
1599 char locale_name[32];
1600 struct stat ignored;
1601 char default_home[MAX_PATH];
1603 static const struct env_entry
1605 char * name;
1606 char * def_value;
1607 } dflt_envvars[] =
1609 {"HOME", "C:/"},
1610 {"PRELOAD_WINSOCK", NULL},
1611 {"emacs_dir", "C:/emacs"},
1612 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1613 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1614 {"EMACSDATA", "%emacs_dir%/etc"},
1615 {"EMACSPATH", "%emacs_dir%/bin"},
1616 /* We no longer set INFOPATH because Info-default-directory-list
1617 is then ignored. */
1618 /* {"INFOPATH", "%emacs_dir%/info"}, */
1619 {"EMACSDOC", "%emacs_dir%/etc"},
1620 {"TERM", "cmd"},
1621 {"LANG", NULL},
1624 #define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1626 /* We need to copy dflt_envvars[] and work on the copy because we
1627 don't want the dumped Emacs to inherit the values of
1628 environment variables we saw during dumping (which could be on
1629 a different system). The defaults above must be left intact. */
1630 struct env_entry env_vars[N_ENV_VARS];
1632 for (i = 0; i < N_ENV_VARS; i++)
1633 env_vars[i] = dflt_envvars[i];
1635 /* For backwards compatibility, check if a .emacs file exists in C:/
1636 If not, then we can try to default to the appdata directory under the
1637 user's profile, which is more likely to be writable. */
1638 if (stat ("C:/.emacs", &ignored) < 0)
1640 HRESULT profile_result;
1641 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1642 of Windows 95 and NT4 that have not been updated to include
1643 MSIE 5. */
1644 ShGetFolderPath_fn get_folder_path;
1645 get_folder_path = (ShGetFolderPath_fn)
1646 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1648 if (get_folder_path != NULL)
1650 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1651 0, default_home);
1653 /* If we can't get the appdata dir, revert to old behavior. */
1654 if (profile_result == S_OK)
1655 env_vars[0].def_value = default_home;
1659 /* Get default locale info and use it for LANG. */
1660 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1661 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1662 locale_name, sizeof (locale_name)))
1664 for (i = 0; i < N_ENV_VARS; i++)
1666 if (strcmp (env_vars[i].name, "LANG") == 0)
1668 env_vars[i].def_value = locale_name;
1669 break;
1674 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1676 /* Treat emacs_dir specially: set it unconditionally based on our
1677 location, if it appears that we are running from the bin subdir
1678 of a standard installation. */
1680 char *p;
1681 char modname[MAX_PATH];
1683 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1684 abort ();
1685 if ((p = strrchr (modname, '\\')) == NULL)
1686 abort ();
1687 *p = 0;
1689 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1691 char buf[SET_ENV_BUF_SIZE];
1693 *p = 0;
1694 for (p = modname; *p; p++)
1695 if (*p == '\\') *p = '/';
1697 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1698 _putenv (strdup (buf));
1700 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1702 /* FIXME: should use substring of get_emacs_configuration ().
1703 But I don't think the Windows build supports alpha, mips etc
1704 anymore, so have taken the easy option for now. */
1705 else if (p && xstrcasecmp (p, "\\i386") == 0)
1707 *p = 0;
1708 p = strrchr (modname, '\\');
1709 if (p != NULL)
1711 *p = 0;
1712 p = strrchr (modname, '\\');
1713 if (p && xstrcasecmp (p, "\\src") == 0)
1715 char buf[SET_ENV_BUF_SIZE];
1717 *p = 0;
1718 for (p = modname; *p; p++)
1719 if (*p == '\\') *p = '/';
1721 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1722 _putenv (strdup (buf));
1728 for (i = 0; i < N_ENV_VARS; i++)
1730 if (!getenv (env_vars[i].name))
1732 int dont_free = 0;
1734 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1735 /* Also ignore empty environment variables. */
1736 || *lpval == 0)
1738 xfree (lpval);
1739 lpval = env_vars[i].def_value;
1740 dwType = REG_EXPAND_SZ;
1741 dont_free = 1;
1744 if (lpval)
1746 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1748 if (dwType == REG_EXPAND_SZ)
1749 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
1750 else if (dwType == REG_SZ)
1751 strcpy (buf1, lpval);
1752 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1754 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
1755 buf1);
1756 _putenv (strdup (buf2));
1759 if (!dont_free)
1760 xfree (lpval);
1766 /* Rebuild system configuration to reflect invoking system. */
1767 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1769 /* Another special case: on NT, the PATH variable is actually named
1770 "Path" although cmd.exe (perhaps NT itself) arranges for
1771 environment variable lookup and setting to be case insensitive.
1772 However, Emacs assumes a fully case sensitive environment, so we
1773 need to change "Path" to "PATH" to match the expectations of
1774 various elisp packages. We do this by the sneaky method of
1775 modifying the string in the C runtime environ entry.
1777 The same applies to COMSPEC. */
1779 char ** envp;
1781 for (envp = environ; *envp; envp++)
1782 if (_strnicmp (*envp, "PATH=", 5) == 0)
1783 memcpy (*envp, "PATH=", 5);
1784 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1785 memcpy (*envp, "COMSPEC=", 8);
1788 /* Remember the initial working directory for getwd, then make the
1789 real wd be the location of emacs.exe to avoid conflicts when
1790 renaming or deleting directories. (We also don't call chdir when
1791 running subprocesses for the same reason.) */
1792 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1793 abort ();
1796 char *p;
1797 static char modname[MAX_PATH];
1799 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1800 abort ();
1801 if ((p = strrchr (modname, '\\')) == NULL)
1802 abort ();
1803 *p = 0;
1805 SetCurrentDirectory (modname);
1807 /* Ensure argv[0] has the full path to Emacs. */
1808 *p = '\\';
1809 argv[0] = modname;
1812 /* Determine if there is a middle mouse button, to allow parse_button
1813 to decide whether right mouse events should be mouse-2 or
1814 mouse-3. */
1815 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1817 init_user_info ();
1820 char *
1821 emacs_root_dir (void)
1823 static char root_dir[FILENAME_MAX];
1824 const char *p;
1826 p = getenv ("emacs_dir");
1827 if (p == NULL)
1828 abort ();
1829 strcpy (root_dir, p);
1830 root_dir[parse_root (root_dir, NULL)] = '\0';
1831 dostounix_filename (root_dir);
1832 return root_dir;
1835 /* We don't have scripts to automatically determine the system configuration
1836 for Emacs before it's compiled, and we don't want to have to make the
1837 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1838 routine. */
1840 char *
1841 get_emacs_configuration (void)
1843 char *arch, *oem, *os;
1844 int build_num;
1845 static char configuration_buffer[32];
1847 /* Determine the processor type. */
1848 switch (get_processor_type ())
1851 #ifdef PROCESSOR_INTEL_386
1852 case PROCESSOR_INTEL_386:
1853 case PROCESSOR_INTEL_486:
1854 case PROCESSOR_INTEL_PENTIUM:
1855 arch = "i386";
1856 break;
1857 #endif
1859 #ifdef PROCESSOR_MIPS_R2000
1860 case PROCESSOR_MIPS_R2000:
1861 case PROCESSOR_MIPS_R3000:
1862 case PROCESSOR_MIPS_R4000:
1863 arch = "mips";
1864 break;
1865 #endif
1867 #ifdef PROCESSOR_ALPHA_21064
1868 case PROCESSOR_ALPHA_21064:
1869 arch = "alpha";
1870 break;
1871 #endif
1873 default:
1874 arch = "unknown";
1875 break;
1878 /* Use the OEM field to reflect the compiler/library combination. */
1879 #ifdef _MSC_VER
1880 #define COMPILER_NAME "msvc"
1881 #else
1882 #ifdef __GNUC__
1883 #define COMPILER_NAME "mingw"
1884 #else
1885 #define COMPILER_NAME "unknown"
1886 #endif
1887 #endif
1888 oem = COMPILER_NAME;
1890 switch (osinfo_cache.dwPlatformId) {
1891 case VER_PLATFORM_WIN32_NT:
1892 os = "nt";
1893 build_num = osinfo_cache.dwBuildNumber;
1894 break;
1895 case VER_PLATFORM_WIN32_WINDOWS:
1896 if (osinfo_cache.dwMinorVersion == 0) {
1897 os = "windows95";
1898 } else {
1899 os = "windows98";
1901 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1902 break;
1903 case VER_PLATFORM_WIN32s:
1904 /* Not supported, should not happen. */
1905 os = "windows32s";
1906 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1907 break;
1908 default:
1909 os = "unknown";
1910 build_num = 0;
1911 break;
1914 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1915 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1916 get_w32_major_version (), get_w32_minor_version (), build_num);
1917 } else {
1918 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1921 return configuration_buffer;
1924 char *
1925 get_emacs_configuration_options (void)
1927 static char options_buffer[256];
1929 /* Work out the effective configure options for this build. */
1930 #ifdef _MSC_VER
1931 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1932 #else
1933 #ifdef __GNUC__
1934 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1935 #else
1936 #define COMPILER_VERSION ""
1937 #endif
1938 #endif
1940 sprintf (options_buffer, COMPILER_VERSION);
1941 #ifdef EMACSDEBUG
1942 strcat (options_buffer, " --no-opt");
1943 #endif
1944 #ifdef USER_CFLAGS
1945 strcat (options_buffer, " --cflags");
1946 strcat (options_buffer, USER_CFLAGS);
1947 #endif
1948 #ifdef USER_LDFLAGS
1949 strcat (options_buffer, " --ldflags");
1950 strcat (options_buffer, USER_LDFLAGS);
1951 #endif
1952 return options_buffer;
1956 #include <sys/timeb.h>
1958 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1959 void
1960 gettimeofday (struct timeval *tv, struct timezone *tz)
1962 struct _timeb tb;
1963 _ftime (&tb);
1965 tv->tv_sec = tb.time;
1966 tv->tv_usec = tb.millitm * 1000L;
1967 /* Implementation note: _ftime sometimes doesn't update the dstflag
1968 according to the new timezone when the system timezone is
1969 changed. We could fix that by using GetSystemTime and
1970 GetTimeZoneInformation, but that doesn't seem necessary, since
1971 Emacs always calls gettimeofday with the 2nd argument NULL (see
1972 EMACS_GET_TIME). */
1973 if (tz)
1975 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
1976 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
1980 /* ------------------------------------------------------------------------- */
1981 /* IO support and wrapper functions for W32 API. */
1982 /* ------------------------------------------------------------------------- */
1984 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1985 on network directories, so we handle that case here.
1986 (Ulrich Leodolter, 1/11/95). */
1987 char *
1988 sys_ctime (const time_t *t)
1990 char *str = (char *) ctime (t);
1991 return (str ? str : "Sun Jan 01 00:00:00 1970");
1994 /* Emulate sleep...we could have done this with a define, but that
1995 would necessitate including windows.h in the files that used it.
1996 This is much easier. */
1997 void
1998 sys_sleep (int seconds)
2000 Sleep (seconds * 1000);
2003 /* Internal MSVC functions for low-level descriptor munging */
2004 extern int __cdecl _set_osfhnd (int fd, long h);
2005 extern int __cdecl _free_osfhnd (int fd);
2007 /* parallel array of private info on file handles */
2008 filedesc fd_info [ MAXDESC ];
2010 typedef struct volume_info_data {
2011 struct volume_info_data * next;
2013 /* time when info was obtained */
2014 DWORD timestamp;
2016 /* actual volume info */
2017 char * root_dir;
2018 DWORD serialnum;
2019 DWORD maxcomp;
2020 DWORD flags;
2021 char * name;
2022 char * type;
2023 } volume_info_data;
2025 /* Global referenced by various functions. */
2026 static volume_info_data volume_info;
2028 /* Vector to indicate which drives are local and fixed (for which cached
2029 data never expires). */
2030 static BOOL fixed_drives[26];
2032 /* Consider cached volume information to be stale if older than 10s,
2033 at least for non-local drives. Info for fixed drives is never stale. */
2034 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2035 #define VOLINFO_STILL_VALID( root_dir, info ) \
2036 ( ( isalpha (root_dir[0]) && \
2037 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2038 || GetTickCount () - info->timestamp < 10000 )
2040 /* Cache support functions. */
2042 /* Simple linked list with linear search is sufficient. */
2043 static volume_info_data *volume_cache = NULL;
2045 static volume_info_data *
2046 lookup_volume_info (char * root_dir)
2048 volume_info_data * info;
2050 for (info = volume_cache; info; info = info->next)
2051 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2052 break;
2053 return info;
2056 static void
2057 add_volume_info (char * root_dir, volume_info_data * info)
2059 info->root_dir = xstrdup (root_dir);
2060 info->next = volume_cache;
2061 volume_cache = info;
2065 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2066 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2067 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2068 volume_info_data *
2069 GetCachedVolumeInformation (char * root_dir)
2071 volume_info_data * info;
2072 char default_root[ MAX_PATH ];
2074 /* NULL for root_dir means use root from current directory. */
2075 if (root_dir == NULL)
2077 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
2078 return NULL;
2079 parse_root (default_root, &root_dir);
2080 *root_dir = 0;
2081 root_dir = default_root;
2084 /* Local fixed drives can be cached permanently. Removable drives
2085 cannot be cached permanently, since the volume name and serial
2086 number (if nothing else) can change. Remote drives should be
2087 treated as if they are removable, since there is no sure way to
2088 tell whether they are or not. Also, the UNC association of drive
2089 letters mapped to remote volumes can be changed at any time (even
2090 by other processes) without notice.
2092 As a compromise, so we can benefit from caching info for remote
2093 volumes, we use a simple expiry mechanism to invalidate cache
2094 entries that are more than ten seconds old. */
2096 #if 0
2097 /* No point doing this, because WNetGetConnection is even slower than
2098 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2099 GetDriveType is about the only call of this type which does not
2100 involve network access, and so is extremely quick). */
2102 /* Map drive letter to UNC if remote. */
2103 if ( isalpha (root_dir[0]) && !fixed[ DRIVE_INDEX (root_dir[0]) ] )
2105 char remote_name[ 256 ];
2106 char drive[3] = { root_dir[0], ':' };
2108 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2109 == NO_ERROR)
2110 /* do something */ ;
2112 #endif
2114 info = lookup_volume_info (root_dir);
2116 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2118 char name[ 256 ];
2119 DWORD serialnum;
2120 DWORD maxcomp;
2121 DWORD flags;
2122 char type[ 256 ];
2124 /* Info is not cached, or is stale. */
2125 if (!GetVolumeInformation (root_dir,
2126 name, sizeof (name),
2127 &serialnum,
2128 &maxcomp,
2129 &flags,
2130 type, sizeof (type)))
2131 return NULL;
2133 /* Cache the volume information for future use, overwriting existing
2134 entry if present. */
2135 if (info == NULL)
2137 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
2138 add_volume_info (root_dir, info);
2140 else
2142 xfree (info->name);
2143 xfree (info->type);
2146 info->name = xstrdup (name);
2147 info->serialnum = serialnum;
2148 info->maxcomp = maxcomp;
2149 info->flags = flags;
2150 info->type = xstrdup (type);
2151 info->timestamp = GetTickCount ();
2154 return info;
2157 /* Get information on the volume where name is held; set path pointer to
2158 start of pathname in name (past UNC header\volume header if present). */
2160 get_volume_info (const char * name, const char ** pPath)
2162 char temp[MAX_PATH];
2163 char *rootname = NULL; /* default to current volume */
2164 volume_info_data * info;
2166 if (name == NULL)
2167 return FALSE;
2169 /* find the root name of the volume if given */
2170 if (isalpha (name[0]) && name[1] == ':')
2172 rootname = temp;
2173 temp[0] = *name++;
2174 temp[1] = *name++;
2175 temp[2] = '\\';
2176 temp[3] = 0;
2178 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2180 char *str = temp;
2181 int slashes = 4;
2182 rootname = temp;
2185 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2186 break;
2187 *str++ = *name++;
2189 while ( *name );
2191 *str++ = '\\';
2192 *str = 0;
2195 if (pPath)
2196 *pPath = name;
2198 info = GetCachedVolumeInformation (rootname);
2199 if (info != NULL)
2201 /* Set global referenced by other functions. */
2202 volume_info = *info;
2203 return TRUE;
2205 return FALSE;
2208 /* Determine if volume is FAT format (ie. only supports short 8.3
2209 names); also set path pointer to start of pathname in name. */
2211 is_fat_volume (const char * name, const char ** pPath)
2213 if (get_volume_info (name, pPath))
2214 return (volume_info.maxcomp == 12);
2215 return FALSE;
2218 /* Map filename to a valid 8.3 name if necessary. */
2219 const char *
2220 map_w32_filename (const char * name, const char ** pPath)
2222 static char shortname[MAX_PATH];
2223 char * str = shortname;
2224 char c;
2225 char * path;
2226 const char * save_name = name;
2228 if (strlen (name) >= MAX_PATH)
2230 /* Return a filename which will cause callers to fail. */
2231 strcpy (shortname, "?");
2232 return shortname;
2235 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2237 register int left = 8; /* maximum number of chars in part */
2238 register int extn = 0; /* extension added? */
2239 register int dots = 2; /* maximum number of dots allowed */
2241 while (name < path)
2242 *str++ = *name++; /* skip past UNC header */
2244 while ((c = *name++))
2246 switch ( c )
2248 case '\\':
2249 case '/':
2250 *str++ = '\\';
2251 extn = 0; /* reset extension flags */
2252 dots = 2; /* max 2 dots */
2253 left = 8; /* max length 8 for main part */
2254 break;
2255 case ':':
2256 *str++ = ':';
2257 extn = 0; /* reset extension flags */
2258 dots = 2; /* max 2 dots */
2259 left = 8; /* max length 8 for main part */
2260 break;
2261 case '.':
2262 if ( dots )
2264 /* Convert path components of the form .xxx to _xxx,
2265 but leave . and .. as they are. This allows .emacs
2266 to be read as _emacs, for example. */
2268 if (! *name ||
2269 *name == '.' ||
2270 IS_DIRECTORY_SEP (*name))
2272 *str++ = '.';
2273 dots--;
2275 else
2277 *str++ = '_';
2278 left--;
2279 dots = 0;
2282 else if ( !extn )
2284 *str++ = '.';
2285 extn = 1; /* we've got an extension */
2286 left = 3; /* 3 chars in extension */
2288 else
2290 /* any embedded dots after the first are converted to _ */
2291 *str++ = '_';
2293 break;
2294 case '~':
2295 case '#': /* don't lose these, they're important */
2296 if ( ! left )
2297 str[-1] = c; /* replace last character of part */
2298 /* FALLTHRU */
2299 default:
2300 if ( left )
2302 *str++ = tolower (c); /* map to lower case (looks nicer) */
2303 left--;
2304 dots = 0; /* started a path component */
2306 break;
2309 *str = '\0';
2311 else
2313 strcpy (shortname, name);
2314 unixtodos_filename (shortname);
2317 if (pPath)
2318 *pPath = shortname + (path - save_name);
2320 return shortname;
2323 static int
2324 is_exec (const char * name)
2326 char * p = strrchr (name, '.');
2327 return
2328 (p != NULL
2329 && (xstrcasecmp (p, ".exe") == 0 ||
2330 xstrcasecmp (p, ".com") == 0 ||
2331 xstrcasecmp (p, ".bat") == 0 ||
2332 xstrcasecmp (p, ".cmd") == 0));
2335 /* Emulate the Unix directory procedures opendir, closedir,
2336 and readdir. We can't use the procedures supplied in sysdep.c,
2337 so we provide them here. */
2339 struct direct dir_static; /* simulated directory contents */
2340 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2341 static int dir_is_fat;
2342 static char dir_pathname[MAXPATHLEN+1];
2343 static WIN32_FIND_DATA dir_find_data;
2345 /* Support shares on a network resource as subdirectories of a read-only
2346 root directory. */
2347 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2348 HANDLE open_unc_volume (const char *);
2349 char *read_unc_volume (HANDLE, char *, int);
2350 void close_unc_volume (HANDLE);
2352 DIR *
2353 opendir (char *filename)
2355 DIR *dirp;
2357 /* Opening is done by FindFirstFile. However, a read is inherent to
2358 this operation, so we defer the open until read time. */
2360 if (dir_find_handle != INVALID_HANDLE_VALUE)
2361 return NULL;
2362 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2363 return NULL;
2365 if (is_unc_volume (filename))
2367 wnet_enum_handle = open_unc_volume (filename);
2368 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2369 return NULL;
2372 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2373 return NULL;
2375 dirp->dd_fd = 0;
2376 dirp->dd_loc = 0;
2377 dirp->dd_size = 0;
2379 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2380 dir_pathname[MAXPATHLEN] = '\0';
2381 dir_is_fat = is_fat_volume (filename, NULL);
2383 return dirp;
2386 void
2387 closedir (DIR *dirp)
2389 /* If we have a find-handle open, close it. */
2390 if (dir_find_handle != INVALID_HANDLE_VALUE)
2392 FindClose (dir_find_handle);
2393 dir_find_handle = INVALID_HANDLE_VALUE;
2395 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2397 close_unc_volume (wnet_enum_handle);
2398 wnet_enum_handle = INVALID_HANDLE_VALUE;
2400 xfree ((char *) dirp);
2403 struct direct *
2404 readdir (DIR *dirp)
2406 int downcase = !NILP (Vw32_downcase_file_names);
2408 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2410 if (!read_unc_volume (wnet_enum_handle,
2411 dir_find_data.cFileName,
2412 MAX_PATH))
2413 return NULL;
2415 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2416 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2418 char filename[MAXNAMLEN + 3];
2419 int ln;
2421 strcpy (filename, dir_pathname);
2422 ln = strlen (filename) - 1;
2423 if (!IS_DIRECTORY_SEP (filename[ln]))
2424 strcat (filename, "\\");
2425 strcat (filename, "*");
2427 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2429 if (dir_find_handle == INVALID_HANDLE_VALUE)
2430 return NULL;
2432 else
2434 if (!FindNextFile (dir_find_handle, &dir_find_data))
2435 return NULL;
2438 /* Emacs never uses this value, so don't bother making it match
2439 value returned by stat(). */
2440 dir_static.d_ino = 1;
2442 strcpy (dir_static.d_name, dir_find_data.cFileName);
2444 /* If the file name in cFileName[] includes `?' characters, it means
2445 the original file name used characters that cannot be represented
2446 by the current ANSI codepage. To avoid total lossage, retrieve
2447 the short 8+3 alias of the long file name. */
2448 if (_mbspbrk (dir_static.d_name, "?"))
2450 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2451 downcase = 1; /* 8+3 aliases are returned in all caps */
2453 dir_static.d_namlen = strlen (dir_static.d_name);
2454 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
2455 dir_static.d_namlen - dir_static.d_namlen % 4;
2457 /* If the file name in cFileName[] includes `?' characters, it means
2458 the original file name used characters that cannot be represented
2459 by the current ANSI codepage. To avoid total lossage, retrieve
2460 the short 8+3 alias of the long file name. */
2461 if (_mbspbrk (dir_find_data.cFileName, "?"))
2463 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2464 /* 8+3 aliases are returned in all caps, which could break
2465 various alists that look at filenames' extensions. */
2466 downcase = 1;
2468 else
2469 strcpy (dir_static.d_name, dir_find_data.cFileName);
2470 dir_static.d_namlen = strlen (dir_static.d_name);
2471 if (dir_is_fat)
2472 _strlwr (dir_static.d_name);
2473 else if (downcase)
2475 register char *p;
2476 for (p = dir_static.d_name; *p; p++)
2477 if (*p >= 'a' && *p <= 'z')
2478 break;
2479 if (!*p)
2480 _strlwr (dir_static.d_name);
2483 return &dir_static;
2486 HANDLE
2487 open_unc_volume (const char *path)
2489 NETRESOURCE nr;
2490 HANDLE henum;
2491 int result;
2493 nr.dwScope = RESOURCE_GLOBALNET;
2494 nr.dwType = RESOURCETYPE_DISK;
2495 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2496 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2497 nr.lpLocalName = NULL;
2498 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
2499 nr.lpComment = NULL;
2500 nr.lpProvider = NULL;
2502 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2503 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2505 if (result == NO_ERROR)
2506 return henum;
2507 else
2508 return INVALID_HANDLE_VALUE;
2511 char *
2512 read_unc_volume (HANDLE henum, char *readbuf, int size)
2514 DWORD count;
2515 int result;
2516 DWORD bufsize = 512;
2517 char *buffer;
2518 char *ptr;
2520 count = 1;
2521 buffer = alloca (bufsize);
2522 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
2523 if (result != NO_ERROR)
2524 return NULL;
2526 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2527 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2528 ptr += 2;
2529 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2530 ptr++;
2532 strncpy (readbuf, ptr, size);
2533 return readbuf;
2536 void
2537 close_unc_volume (HANDLE henum)
2539 if (henum != INVALID_HANDLE_VALUE)
2540 WNetCloseEnum (henum);
2543 DWORD
2544 unc_volume_file_attributes (const char *path)
2546 HANDLE henum;
2547 DWORD attrs;
2549 henum = open_unc_volume (path);
2550 if (henum == INVALID_HANDLE_VALUE)
2551 return -1;
2553 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2555 close_unc_volume (henum);
2557 return attrs;
2560 /* Ensure a network connection is authenticated. */
2561 static void
2562 logon_network_drive (const char *path)
2564 NETRESOURCE resource;
2565 char share[MAX_PATH];
2566 int i, n_slashes;
2567 char drive[4];
2568 UINT drvtype;
2570 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
2571 drvtype = DRIVE_REMOTE;
2572 else if (path[0] == '\0' || path[1] != ':')
2573 drvtype = GetDriveType (NULL);
2574 else
2576 drive[0] = path[0];
2577 drive[1] = ':';
2578 drive[2] = '\\';
2579 drive[3] = '\0';
2580 drvtype = GetDriveType (drive);
2583 /* Only logon to networked drives. */
2584 if (drvtype != DRIVE_REMOTE)
2585 return;
2587 n_slashes = 2;
2588 strncpy (share, path, MAX_PATH);
2589 /* Truncate to just server and share name. */
2590 for (i = 2; i < MAX_PATH; i++)
2592 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2594 share[i] = '\0';
2595 break;
2599 resource.dwType = RESOURCETYPE_DISK;
2600 resource.lpLocalName = NULL;
2601 resource.lpRemoteName = share;
2602 resource.lpProvider = NULL;
2604 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2607 /* Shadow some MSVC runtime functions to map requests for long filenames
2608 to reasonable short names if necessary. This was originally added to
2609 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2610 long file names. */
2613 sys_access (const char * path, int mode)
2615 DWORD attributes;
2617 /* MSVC implementation doesn't recognize D_OK. */
2618 path = map_w32_filename (path, NULL);
2619 if (is_unc_volume (path))
2621 attributes = unc_volume_file_attributes (path);
2622 if (attributes == -1) {
2623 errno = EACCES;
2624 return -1;
2627 else if ((attributes = GetFileAttributes (path)) == -1)
2629 /* Should try mapping GetLastError to errno; for now just indicate
2630 that path doesn't exist. */
2631 errno = EACCES;
2632 return -1;
2634 if ((mode & X_OK) != 0 && !is_exec (path))
2636 errno = EACCES;
2637 return -1;
2639 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2641 errno = EACCES;
2642 return -1;
2644 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2646 errno = EACCES;
2647 return -1;
2649 return 0;
2653 sys_chdir (const char * path)
2655 return _chdir (map_w32_filename (path, NULL));
2659 sys_chmod (const char * path, int mode)
2661 return _chmod (map_w32_filename (path, NULL), mode);
2665 sys_chown (const char *path, uid_t owner, gid_t group)
2667 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2668 return -1;
2669 return 0;
2673 sys_creat (const char * path, int mode)
2675 return _creat (map_w32_filename (path, NULL), mode);
2678 FILE *
2679 sys_fopen (const char * path, const char * mode)
2681 int fd;
2682 int oflag;
2683 const char * mode_save = mode;
2685 /* Force all file handles to be non-inheritable. This is necessary to
2686 ensure child processes don't unwittingly inherit handles that might
2687 prevent future file access. */
2689 if (mode[0] == 'r')
2690 oflag = O_RDONLY;
2691 else if (mode[0] == 'w' || mode[0] == 'a')
2692 oflag = O_WRONLY | O_CREAT | O_TRUNC;
2693 else
2694 return NULL;
2696 /* Only do simplistic option parsing. */
2697 while (*++mode)
2698 if (mode[0] == '+')
2700 oflag &= ~(O_RDONLY | O_WRONLY);
2701 oflag |= O_RDWR;
2703 else if (mode[0] == 'b')
2705 oflag &= ~O_TEXT;
2706 oflag |= O_BINARY;
2708 else if (mode[0] == 't')
2710 oflag &= ~O_BINARY;
2711 oflag |= O_TEXT;
2713 else break;
2715 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2716 if (fd < 0)
2717 return NULL;
2719 return _fdopen (fd, mode_save);
2722 /* This only works on NTFS volumes, but is useful to have. */
2724 sys_link (const char * old, const char * new)
2726 HANDLE fileh;
2727 int result = -1;
2728 char oldname[MAX_PATH], newname[MAX_PATH];
2730 if (old == NULL || new == NULL)
2732 errno = ENOENT;
2733 return -1;
2736 strcpy (oldname, map_w32_filename (old, NULL));
2737 strcpy (newname, map_w32_filename (new, NULL));
2739 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2740 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2741 if (fileh != INVALID_HANDLE_VALUE)
2743 int wlen;
2745 /* Confusingly, the "alternate" stream name field does not apply
2746 when restoring a hard link, and instead contains the actual
2747 stream data for the link (ie. the name of the link to create).
2748 The WIN32_STREAM_ID structure before the cStreamName field is
2749 the stream header, which is then immediately followed by the
2750 stream data. */
2752 struct {
2753 WIN32_STREAM_ID wid;
2754 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2755 } data;
2757 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2758 data.wid.cStreamName, MAX_PATH);
2759 if (wlen > 0)
2761 LPVOID context = NULL;
2762 DWORD wbytes = 0;
2764 data.wid.dwStreamId = BACKUP_LINK;
2765 data.wid.dwStreamAttributes = 0;
2766 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
2767 data.wid.Size.HighPart = 0;
2768 data.wid.dwStreamNameSize = 0;
2770 if (BackupWrite (fileh, (LPBYTE)&data,
2771 offsetof (WIN32_STREAM_ID, cStreamName)
2772 + data.wid.Size.LowPart,
2773 &wbytes, FALSE, FALSE, &context)
2774 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2776 /* succeeded */
2777 result = 0;
2779 else
2781 /* Should try mapping GetLastError to errno; for now just
2782 indicate a general error (eg. links not supported). */
2783 errno = EINVAL; // perhaps EMLINK?
2787 CloseHandle (fileh);
2789 else
2790 errno = ENOENT;
2792 return result;
2796 sys_mkdir (const char * path)
2798 return _mkdir (map_w32_filename (path, NULL));
2801 /* Because of long name mapping issues, we need to implement this
2802 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2803 a unique name, instead of setting the input template to an empty
2804 string.
2806 Standard algorithm seems to be use pid or tid with a letter on the
2807 front (in place of the 6 X's) and cycle through the letters to find a
2808 unique name. We extend that to allow any reasonable character as the
2809 first of the 6 X's. */
2810 char *
2811 sys_mktemp (char * template)
2813 char * p;
2814 int i;
2815 unsigned uid = GetCurrentThreadId ();
2816 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2818 if (template == NULL)
2819 return NULL;
2820 p = template + strlen (template);
2821 i = 5;
2822 /* replace up to the last 5 X's with uid in decimal */
2823 while (--p >= template && p[0] == 'X' && --i >= 0)
2825 p[0] = '0' + uid % 10;
2826 uid /= 10;
2829 if (i < 0 && p[0] == 'X')
2831 i = 0;
2834 int save_errno = errno;
2835 p[0] = first_char[i];
2836 if (sys_access (template, 0) < 0)
2838 errno = save_errno;
2839 return template;
2842 while (++i < sizeof (first_char));
2845 /* Template is badly formed or else we can't generate a unique name,
2846 so return empty string */
2847 template[0] = 0;
2848 return template;
2852 sys_open (const char * path, int oflag, int mode)
2854 const char* mpath = map_w32_filename (path, NULL);
2855 /* Try to open file without _O_CREAT, to be able to write to hidden
2856 and system files. Force all file handles to be
2857 non-inheritable. */
2858 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2859 if (res >= 0)
2860 return res;
2861 return _open (mpath, oflag | _O_NOINHERIT, mode);
2865 sys_rename (const char * oldname, const char * newname)
2867 BOOL result;
2868 char temp[MAX_PATH];
2870 /* MoveFile on Windows 95 doesn't correctly change the short file name
2871 alias in a number of circumstances (it is not easy to predict when
2872 just by looking at oldname and newname, unfortunately). In these
2873 cases, renaming through a temporary name avoids the problem.
2875 A second problem on Windows 95 is that renaming through a temp name when
2876 newname is uppercase fails (the final long name ends up in
2877 lowercase, although the short alias might be uppercase) UNLESS the
2878 long temp name is not 8.3.
2880 So, on Windows 95 we always rename through a temp name, and we make sure
2881 the temp name has a long extension to ensure correct renaming. */
2883 strcpy (temp, map_w32_filename (oldname, NULL));
2885 if (os_subtype == OS_WIN95)
2887 char * o;
2888 char * p;
2889 int i = 0;
2891 oldname = map_w32_filename (oldname, NULL);
2892 if (o = strrchr (oldname, '\\'))
2893 o++;
2894 else
2895 o = (char *) oldname;
2897 if (p = strrchr (temp, '\\'))
2898 p++;
2899 else
2900 p = temp;
2904 /* Force temp name to require a manufactured 8.3 alias - this
2905 seems to make the second rename work properly. */
2906 sprintf (p, "_.%s.%u", o, i);
2907 i++;
2908 result = rename (oldname, temp);
2910 /* This loop must surely terminate! */
2911 while (result < 0 && errno == EEXIST);
2912 if (result < 0)
2913 return -1;
2916 /* Emulate Unix behavior - newname is deleted if it already exists
2917 (at least if it is a file; don't do this for directories).
2919 Since we mustn't do this if we are just changing the case of the
2920 file name (we would end up deleting the file we are trying to
2921 rename!), we let rename detect if the destination file already
2922 exists - that way we avoid the possible pitfalls of trying to
2923 determine ourselves whether two names really refer to the same
2924 file, which is not always possible in the general case. (Consider
2925 all the permutations of shared or subst'd drives, etc.) */
2927 newname = map_w32_filename (newname, NULL);
2928 result = rename (temp, newname);
2930 if (result < 0
2931 && errno == EEXIST
2932 && _chmod (newname, 0666) == 0
2933 && _unlink (newname) == 0)
2934 result = rename (temp, newname);
2936 return result;
2940 sys_rmdir (const char * path)
2942 return _rmdir (map_w32_filename (path, NULL));
2946 sys_unlink (const char * path)
2948 path = map_w32_filename (path, NULL);
2950 /* On Unix, unlink works without write permission. */
2951 _chmod (path, 0666);
2952 return _unlink (path);
2955 static FILETIME utc_base_ft;
2956 static ULONGLONG utc_base; /* In 100ns units */
2957 static int init = 0;
2959 #define FILETIME_TO_U64(result, ft) \
2960 do { \
2961 ULARGE_INTEGER uiTemp; \
2962 uiTemp.LowPart = (ft).dwLowDateTime; \
2963 uiTemp.HighPart = (ft).dwHighDateTime; \
2964 result = uiTemp.QuadPart; \
2965 } while (0)
2967 static void
2968 initialize_utc_base ()
2970 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2971 SYSTEMTIME st;
2973 st.wYear = 1970;
2974 st.wMonth = 1;
2975 st.wDay = 1;
2976 st.wHour = 0;
2977 st.wMinute = 0;
2978 st.wSecond = 0;
2979 st.wMilliseconds = 0;
2981 SystemTimeToFileTime (&st, &utc_base_ft);
2982 FILETIME_TO_U64 (utc_base, utc_base_ft);
2985 static time_t
2986 convert_time (FILETIME ft)
2988 ULONGLONG tmp;
2990 if (!init)
2992 initialize_utc_base ();
2993 init = 1;
2996 if (CompareFileTime (&ft, &utc_base_ft) < 0)
2997 return 0;
2999 FILETIME_TO_U64 (tmp, ft);
3000 return (time_t) ((tmp - utc_base) / 10000000L);
3004 void
3005 convert_from_time_t (time_t time, FILETIME * pft)
3007 ULARGE_INTEGER tmp;
3009 if (!init)
3011 initialize_utc_base ();
3012 init = 1;
3015 /* time in 100ns units since 1-Jan-1601 */
3016 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
3017 pft->dwHighDateTime = tmp.HighPart;
3018 pft->dwLowDateTime = tmp.LowPart;
3021 #if 0
3022 /* No reason to keep this; faking inode values either by hashing or even
3023 using the file index from GetInformationByHandle, is not perfect and
3024 so by default Emacs doesn't use the inode values on Windows.
3025 Instead, we now determine file-truename correctly (except for
3026 possible drive aliasing etc). */
3028 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3029 static unsigned
3030 hashval (const unsigned char * str)
3032 unsigned h = 0;
3033 while (*str)
3035 h = (h << 4) + *str++;
3036 h ^= (h >> 28);
3038 return h;
3041 /* Return the hash value of the canonical pathname, excluding the
3042 drive/UNC header, to get a hopefully unique inode number. */
3043 static DWORD
3044 generate_inode_val (const char * name)
3046 char fullname[ MAX_PATH ];
3047 char * p;
3048 unsigned hash;
3050 /* Get the truly canonical filename, if it exists. (Note: this
3051 doesn't resolve aliasing due to subst commands, or recognise hard
3052 links. */
3053 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3054 abort ();
3056 parse_root (fullname, &p);
3057 /* Normal W32 filesystems are still case insensitive. */
3058 _strlwr (p);
3059 return hashval (p);
3062 #endif
3064 static PSECURITY_DESCRIPTOR
3065 get_file_security_desc (const char *fname)
3067 PSECURITY_DESCRIPTOR psd = NULL;
3068 DWORD sd_len, err;
3069 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3070 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3072 if (!get_file_security (fname, si, psd, 0, &sd_len))
3074 err = GetLastError ();
3075 if (err != ERROR_INSUFFICIENT_BUFFER)
3076 return NULL;
3079 psd = xmalloc (sd_len);
3080 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3082 xfree (psd);
3083 return NULL;
3086 return psd;
3089 static DWORD
3090 get_rid (PSID sid)
3092 unsigned n_subauthorities;
3094 /* Use the last sub-authority value of the RID, the relative
3095 portion of the SID, as user/group ID. */
3096 n_subauthorities = *get_sid_sub_authority_count (sid);
3097 if (n_subauthorities < 1)
3098 return 0; /* the "World" RID */
3099 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3102 /* Caching SID and account values for faster lokup. */
3104 #ifdef __GNUC__
3105 # define FLEXIBLE_ARRAY_MEMBER
3106 #else
3107 # define FLEXIBLE_ARRAY_MEMBER 1
3108 #endif
3110 struct w32_id {
3111 unsigned rid;
3112 struct w32_id *next;
3113 char name[GNLEN+1];
3114 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3117 static struct w32_id *w32_idlist;
3119 static int
3120 w32_cached_id (PSID sid, unsigned *id, char *name)
3122 struct w32_id *tail, *found;
3124 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3126 if (equal_sid ((PSID)tail->sid, sid))
3128 found = tail;
3129 break;
3132 if (found)
3134 *id = found->rid;
3135 strcpy (name, found->name);
3136 return 1;
3138 else
3139 return 0;
3142 static void
3143 w32_add_to_cache (PSID sid, unsigned id, char *name)
3145 DWORD sid_len;
3146 struct w32_id *new_entry;
3148 /* We don't want to leave behind stale cache from when Emacs was
3149 dumped. */
3150 if (initialized)
3152 sid_len = get_length_sid (sid);
3153 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3154 if (new_entry)
3156 new_entry->rid = id;
3157 strcpy (new_entry->name, name);
3158 copy_sid (sid_len, (PSID)new_entry->sid, sid);
3159 new_entry->next = w32_idlist;
3160 w32_idlist = new_entry;
3165 #define UID 1
3166 #define GID 2
3168 static int
3169 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
3170 unsigned *id, char *nm, int what)
3172 PSID sid = NULL;
3173 char machine[MAX_COMPUTERNAME_LENGTH+1];
3174 BOOL dflt;
3175 SID_NAME_USE ignore;
3176 char name[UNLEN+1];
3177 DWORD name_len = sizeof (name);
3178 char domain[1024];
3179 DWORD domain_len = sizeof (domain);
3180 char *mp = NULL;
3181 int use_dflt = 0;
3182 int result;
3184 if (what == UID)
3185 result = get_security_descriptor_owner (psd, &sid, &dflt);
3186 else if (what == GID)
3187 result = get_security_descriptor_group (psd, &sid, &dflt);
3188 else
3189 result = 0;
3191 if (!result || !is_valid_sid (sid))
3192 use_dflt = 1;
3193 else if (!w32_cached_id (sid, id, nm))
3195 /* If FNAME is a UNC, we need to lookup account on the
3196 specified machine. */
3197 if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
3198 && fname[2] != '\0')
3200 const char *s;
3201 char *p;
3203 for (s = fname + 2, p = machine;
3204 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
3205 *p = *s;
3206 *p = '\0';
3207 mp = machine;
3210 if (!lookup_account_sid (mp, sid, name, &name_len,
3211 domain, &domain_len, &ignore)
3212 || name_len > UNLEN+1)
3213 use_dflt = 1;
3214 else
3216 *id = get_rid (sid);
3217 strcpy (nm, name);
3218 w32_add_to_cache (sid, *id, name);
3221 return use_dflt;
3224 static void
3225 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd,
3226 const char *fname,
3227 struct stat *st)
3229 int dflt_usr = 0, dflt_grp = 0;
3231 if (!psd)
3233 dflt_usr = 1;
3234 dflt_grp = 1;
3236 else
3238 if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
3239 dflt_usr = 1;
3240 if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
3241 dflt_grp = 1;
3243 /* Consider files to belong to current user/group, if we cannot get
3244 more accurate information. */
3245 if (dflt_usr)
3247 st->st_uid = dflt_passwd.pw_uid;
3248 strcpy (st->st_uname, dflt_passwd.pw_name);
3250 if (dflt_grp)
3252 st->st_gid = dflt_passwd.pw_gid;
3253 strcpy (st->st_gname, dflt_group.gr_name);
3257 /* Return non-zero if NAME is a potentially slow filesystem. */
3259 is_slow_fs (const char *name)
3261 char drive_root[4];
3262 UINT devtype;
3264 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
3265 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
3266 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
3267 devtype = GetDriveType (NULL); /* use root of current drive */
3268 else
3270 /* GetDriveType needs the root directory of the drive. */
3271 strncpy (drive_root, name, 2);
3272 drive_root[2] = '\\';
3273 drive_root[3] = '\0';
3274 devtype = GetDriveType (drive_root);
3276 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
3279 /* MSVC stat function can't cope with UNC names and has other bugs, so
3280 replace it with our own. This also allows us to calculate consistent
3281 inode values without hacks in the main Emacs code. */
3283 stat (const char * path, struct stat * buf)
3285 char *name, *r;
3286 char drive_root[4];
3287 UINT devtype;
3288 WIN32_FIND_DATA wfd;
3289 HANDLE fh;
3290 unsigned __int64 fake_inode;
3291 int permission;
3292 int len;
3293 int rootdir = FALSE;
3294 PSECURITY_DESCRIPTOR psd = NULL;
3296 if (path == NULL || buf == NULL)
3298 errno = EFAULT;
3299 return -1;
3302 name = (char *) map_w32_filename (path, &path);
3303 /* Must be valid filename, no wild cards or other invalid
3304 characters. We use _mbspbrk to support multibyte strings that
3305 might look to strpbrk as if they included literal *, ?, and other
3306 characters mentioned below that are disallowed by Windows
3307 filesystems. */
3308 if (_mbspbrk (name, "*?|<>\""))
3310 errno = ENOENT;
3311 return -1;
3314 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3315 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3316 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3318 r[1] = r[2] = '\0';
3321 /* Remove trailing directory separator, unless name is the root
3322 directory of a drive or UNC volume in which case ensure there
3323 is a trailing separator. */
3324 len = strlen (name);
3325 rootdir = (path >= name + len - 1
3326 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3327 name = strcpy (alloca (len + 2), name);
3329 if (is_unc_volume (name))
3331 DWORD attrs = unc_volume_file_attributes (name);
3333 if (attrs == -1)
3334 return -1;
3336 memset (&wfd, 0, sizeof (wfd));
3337 wfd.dwFileAttributes = attrs;
3338 wfd.ftCreationTime = utc_base_ft;
3339 wfd.ftLastAccessTime = utc_base_ft;
3340 wfd.ftLastWriteTime = utc_base_ft;
3341 strcpy (wfd.cFileName, name);
3343 else if (rootdir)
3345 if (!IS_DIRECTORY_SEP (name[len-1]))
3346 strcat (name, "\\");
3347 if (GetDriveType (name) < 2)
3349 errno = ENOENT;
3350 return -1;
3352 memset (&wfd, 0, sizeof (wfd));
3353 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
3354 wfd.ftCreationTime = utc_base_ft;
3355 wfd.ftLastAccessTime = utc_base_ft;
3356 wfd.ftLastWriteTime = utc_base_ft;
3357 strcpy (wfd.cFileName, name);
3359 else
3361 if (IS_DIRECTORY_SEP (name[len-1]))
3362 name[len - 1] = 0;
3364 /* (This is hacky, but helps when doing file completions on
3365 network drives.) Optimize by using information available from
3366 active readdir if possible. */
3367 len = strlen (dir_pathname);
3368 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3369 len--;
3370 if (dir_find_handle != INVALID_HANDLE_VALUE
3371 && strnicmp (name, dir_pathname, len) == 0
3372 && IS_DIRECTORY_SEP (name[len])
3373 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3375 /* This was the last entry returned by readdir. */
3376 wfd = dir_find_data;
3378 else
3380 logon_network_drive (name);
3382 fh = FindFirstFile (name, &wfd);
3383 if (fh == INVALID_HANDLE_VALUE)
3385 errno = ENOENT;
3386 return -1;
3388 FindClose (fh);
3392 if (!(NILP (Vw32_get_true_file_attributes)
3393 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
3394 /* No access rights required to get info. */
3395 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
3396 FILE_FLAG_BACKUP_SEMANTICS, NULL))
3397 != INVALID_HANDLE_VALUE)
3399 /* This is more accurate in terms of gettting the correct number
3400 of links, but is quite slow (it is noticeable when Emacs is
3401 making a list of file name completions). */
3402 BY_HANDLE_FILE_INFORMATION info;
3404 if (GetFileInformationByHandle (fh, &info))
3406 buf->st_nlink = info.nNumberOfLinks;
3407 /* Might as well use file index to fake inode values, but this
3408 is not guaranteed to be unique unless we keep a handle open
3409 all the time (even then there are situations where it is
3410 not unique). Reputedly, there are at most 48 bits of info
3411 (on NTFS, presumably less on FAT). */
3412 fake_inode = info.nFileIndexHigh;
3413 fake_inode <<= 32;
3414 fake_inode += info.nFileIndexLow;
3416 else
3418 buf->st_nlink = 1;
3419 fake_inode = 0;
3422 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3424 buf->st_mode = S_IFDIR;
3426 else
3428 switch (GetFileType (fh))
3430 case FILE_TYPE_DISK:
3431 buf->st_mode = S_IFREG;
3432 break;
3433 case FILE_TYPE_PIPE:
3434 buf->st_mode = S_IFIFO;
3435 break;
3436 case FILE_TYPE_CHAR:
3437 case FILE_TYPE_UNKNOWN:
3438 default:
3439 buf->st_mode = S_IFCHR;
3442 CloseHandle (fh);
3443 psd = get_file_security_desc (name);
3444 get_file_owner_and_group (psd, name, buf);
3446 else
3448 /* Don't bother to make this information more accurate. */
3449 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
3450 S_IFDIR : S_IFREG;
3451 buf->st_nlink = 1;
3452 fake_inode = 0;
3454 get_file_owner_and_group (NULL, name, buf);
3456 xfree (psd);
3458 #if 0
3459 /* Not sure if there is any point in this. */
3460 if (!NILP (Vw32_generate_fake_inodes))
3461 fake_inode = generate_inode_val (name);
3462 else if (fake_inode == 0)
3464 /* For want of something better, try to make everything unique. */
3465 static DWORD gen_num = 0;
3466 fake_inode = ++gen_num;
3468 #endif
3470 /* MSVC defines _ino_t to be short; other libc's might not. */
3471 if (sizeof (buf->st_ino) == 2)
3472 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3473 else
3474 buf->st_ino = fake_inode;
3476 /* volume_info is set indirectly by map_w32_filename */
3477 buf->st_dev = volume_info.serialnum;
3478 buf->st_rdev = volume_info.serialnum;
3481 buf->st_size = wfd.nFileSizeHigh;
3482 buf->st_size <<= 32;
3483 buf->st_size += wfd.nFileSizeLow;
3485 /* Convert timestamps to Unix format. */
3486 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
3487 buf->st_atime = convert_time (wfd.ftLastAccessTime);
3488 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3489 buf->st_ctime = convert_time (wfd.ftCreationTime);
3490 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3492 /* determine rwx permissions */
3493 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3494 permission = S_IREAD;
3495 else
3496 permission = S_IREAD | S_IWRITE;
3498 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3499 permission |= S_IEXEC;
3500 else if (is_exec (name))
3501 permission |= S_IEXEC;
3503 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3505 return 0;
3508 /* Provide fstat and utime as well as stat for consistent handling of
3509 file timestamps. */
3511 fstat (int desc, struct stat * buf)
3513 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3514 BY_HANDLE_FILE_INFORMATION info;
3515 unsigned __int64 fake_inode;
3516 int permission;
3518 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3520 case FILE_TYPE_DISK:
3521 buf->st_mode = S_IFREG;
3522 if (!GetFileInformationByHandle (fh, &info))
3524 errno = EACCES;
3525 return -1;
3527 break;
3528 case FILE_TYPE_PIPE:
3529 buf->st_mode = S_IFIFO;
3530 goto non_disk;
3531 case FILE_TYPE_CHAR:
3532 case FILE_TYPE_UNKNOWN:
3533 default:
3534 buf->st_mode = S_IFCHR;
3535 non_disk:
3536 memset (&info, 0, sizeof (info));
3537 info.dwFileAttributes = 0;
3538 info.ftCreationTime = utc_base_ft;
3539 info.ftLastAccessTime = utc_base_ft;
3540 info.ftLastWriteTime = utc_base_ft;
3543 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3544 buf->st_mode = S_IFDIR;
3546 buf->st_nlink = info.nNumberOfLinks;
3547 /* Might as well use file index to fake inode values, but this
3548 is not guaranteed to be unique unless we keep a handle open
3549 all the time (even then there are situations where it is
3550 not unique). Reputedly, there are at most 48 bits of info
3551 (on NTFS, presumably less on FAT). */
3552 fake_inode = info.nFileIndexHigh;
3553 fake_inode <<= 32;
3554 fake_inode += info.nFileIndexLow;
3556 /* MSVC defines _ino_t to be short; other libc's might not. */
3557 if (sizeof (buf->st_ino) == 2)
3558 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3559 else
3560 buf->st_ino = fake_inode;
3562 /* Consider files to belong to current user.
3563 FIXME: this should use GetSecurityInfo API, but it is only
3564 available for _WIN32_WINNT >= 0x501. */
3565 buf->st_uid = dflt_passwd.pw_uid;
3566 buf->st_gid = dflt_passwd.pw_gid;
3567 strcpy (buf->st_uname, dflt_passwd.pw_name);
3568 strcpy (buf->st_gname, dflt_group.gr_name);
3570 buf->st_dev = info.dwVolumeSerialNumber;
3571 buf->st_rdev = info.dwVolumeSerialNumber;
3573 buf->st_size = info.nFileSizeHigh;
3574 buf->st_size <<= 32;
3575 buf->st_size += info.nFileSizeLow;
3577 /* Convert timestamps to Unix format. */
3578 buf->st_mtime = convert_time (info.ftLastWriteTime);
3579 buf->st_atime = convert_time (info.ftLastAccessTime);
3580 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3581 buf->st_ctime = convert_time (info.ftCreationTime);
3582 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3584 /* determine rwx permissions */
3585 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3586 permission = S_IREAD;
3587 else
3588 permission = S_IREAD | S_IWRITE;
3590 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3591 permission |= S_IEXEC;
3592 else
3594 #if 0 /* no way of knowing the filename */
3595 char * p = strrchr (name, '.');
3596 if (p != NULL &&
3597 (xstrcasecmp (p, ".exe") == 0 ||
3598 xstrcasecmp (p, ".com") == 0 ||
3599 xstrcasecmp (p, ".bat") == 0 ||
3600 xstrcasecmp (p, ".cmd") == 0))
3601 permission |= S_IEXEC;
3602 #endif
3605 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3607 return 0;
3611 utime (const char *name, struct utimbuf *times)
3613 struct utimbuf deftime;
3614 HANDLE fh;
3615 FILETIME mtime;
3616 FILETIME atime;
3618 if (times == NULL)
3620 deftime.modtime = deftime.actime = time (NULL);
3621 times = &deftime;
3624 /* Need write access to set times. */
3625 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
3626 0, OPEN_EXISTING, 0, NULL);
3627 if (fh)
3629 convert_from_time_t (times->actime, &atime);
3630 convert_from_time_t (times->modtime, &mtime);
3631 if (!SetFileTime (fh, NULL, &atime, &mtime))
3633 CloseHandle (fh);
3634 errno = EACCES;
3635 return -1;
3637 CloseHandle (fh);
3639 else
3641 errno = EINVAL;
3642 return -1;
3644 return 0;
3648 /* Support for browsing other processes and their attributes. See
3649 process.c for the Lisp bindings. */
3651 /* Helper wrapper functions. */
3653 HANDLE WINAPI
3654 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
3656 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
3658 if (g_b_init_create_toolhelp32_snapshot == 0)
3660 g_b_init_create_toolhelp32_snapshot = 1;
3661 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
3662 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3663 "CreateToolhelp32Snapshot");
3665 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
3667 return INVALID_HANDLE_VALUE;
3669 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
3672 BOOL WINAPI
3673 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
3675 static Process32First_Proc s_pfn_Process32_First = NULL;
3677 if (g_b_init_process32_first == 0)
3679 g_b_init_process32_first = 1;
3680 s_pfn_Process32_First = (Process32First_Proc)
3681 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3682 "Process32First");
3684 if (s_pfn_Process32_First == NULL)
3686 return FALSE;
3688 return (s_pfn_Process32_First (hSnapshot, lppe));
3691 BOOL WINAPI
3692 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
3694 static Process32Next_Proc s_pfn_Process32_Next = NULL;
3696 if (g_b_init_process32_next == 0)
3698 g_b_init_process32_next = 1;
3699 s_pfn_Process32_Next = (Process32Next_Proc)
3700 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3701 "Process32Next");
3703 if (s_pfn_Process32_Next == NULL)
3705 return FALSE;
3707 return (s_pfn_Process32_Next (hSnapshot, lppe));
3710 BOOL WINAPI
3711 open_thread_token (HANDLE ThreadHandle,
3712 DWORD DesiredAccess,
3713 BOOL OpenAsSelf,
3714 PHANDLE TokenHandle)
3716 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
3717 HMODULE hm_advapi32 = NULL;
3718 if (is_windows_9x () == TRUE)
3720 SetLastError (ERROR_NOT_SUPPORTED);
3721 return FALSE;
3723 if (g_b_init_open_thread_token == 0)
3725 g_b_init_open_thread_token = 1;
3726 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3727 s_pfn_Open_Thread_Token =
3728 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
3730 if (s_pfn_Open_Thread_Token == NULL)
3732 SetLastError (ERROR_NOT_SUPPORTED);
3733 return FALSE;
3735 return (
3736 s_pfn_Open_Thread_Token (
3737 ThreadHandle,
3738 DesiredAccess,
3739 OpenAsSelf,
3740 TokenHandle)
3744 BOOL WINAPI
3745 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
3747 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
3748 HMODULE hm_advapi32 = NULL;
3749 if (is_windows_9x () == TRUE)
3751 return FALSE;
3753 if (g_b_init_impersonate_self == 0)
3755 g_b_init_impersonate_self = 1;
3756 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3757 s_pfn_Impersonate_Self =
3758 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
3760 if (s_pfn_Impersonate_Self == NULL)
3762 return FALSE;
3764 return s_pfn_Impersonate_Self (ImpersonationLevel);
3767 BOOL WINAPI
3768 revert_to_self (void)
3770 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
3771 HMODULE hm_advapi32 = NULL;
3772 if (is_windows_9x () == TRUE)
3774 return FALSE;
3776 if (g_b_init_revert_to_self == 0)
3778 g_b_init_revert_to_self = 1;
3779 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3780 s_pfn_Revert_To_Self =
3781 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
3783 if (s_pfn_Revert_To_Self == NULL)
3785 return FALSE;
3787 return s_pfn_Revert_To_Self ();
3790 BOOL WINAPI
3791 get_process_memory_info (HANDLE h_proc,
3792 PPROCESS_MEMORY_COUNTERS mem_counters,
3793 DWORD bufsize)
3795 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
3796 HMODULE hm_psapi = NULL;
3797 if (is_windows_9x () == TRUE)
3799 return FALSE;
3801 if (g_b_init_get_process_memory_info == 0)
3803 g_b_init_get_process_memory_info = 1;
3804 hm_psapi = LoadLibrary ("Psapi.dll");
3805 if (hm_psapi)
3806 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
3807 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
3809 if (s_pfn_Get_Process_Memory_Info == NULL)
3811 return FALSE;
3813 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
3816 BOOL WINAPI
3817 get_process_working_set_size (HANDLE h_proc, DWORD *minrss, DWORD *maxrss)
3819 static GetProcessWorkingSetSize_Proc
3820 s_pfn_Get_Process_Working_Set_Size = NULL;
3822 if (is_windows_9x () == TRUE)
3824 return FALSE;
3826 if (g_b_init_get_process_working_set_size == 0)
3828 g_b_init_get_process_working_set_size = 1;
3829 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
3830 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3831 "GetProcessWorkingSetSize");
3833 if (s_pfn_Get_Process_Working_Set_Size == NULL)
3835 return FALSE;
3837 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
3840 BOOL WINAPI
3841 global_memory_status (MEMORYSTATUS *buf)
3843 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
3845 if (is_windows_9x () == TRUE)
3847 return FALSE;
3849 if (g_b_init_global_memory_status == 0)
3851 g_b_init_global_memory_status = 1;
3852 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
3853 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3854 "GlobalMemoryStatus");
3856 if (s_pfn_Global_Memory_Status == NULL)
3858 return FALSE;
3860 return s_pfn_Global_Memory_Status (buf);
3863 BOOL WINAPI
3864 global_memory_status_ex (MEMORY_STATUS_EX *buf)
3866 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
3868 if (is_windows_9x () == TRUE)
3870 return FALSE;
3872 if (g_b_init_global_memory_status_ex == 0)
3874 g_b_init_global_memory_status_ex = 1;
3875 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
3876 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3877 "GlobalMemoryStatusEx");
3879 if (s_pfn_Global_Memory_Status_Ex == NULL)
3881 return FALSE;
3883 return s_pfn_Global_Memory_Status_Ex (buf);
3886 Lisp_Object
3887 list_system_processes ()
3889 struct gcpro gcpro1;
3890 Lisp_Object proclist = Qnil;
3891 HANDLE h_snapshot;
3893 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
3895 if (h_snapshot != INVALID_HANDLE_VALUE)
3897 PROCESSENTRY32 proc_entry;
3898 DWORD proc_id;
3899 BOOL res;
3901 GCPRO1 (proclist);
3903 proc_entry.dwSize = sizeof (PROCESSENTRY32);
3904 for (res = process32_first (h_snapshot, &proc_entry); res;
3905 res = process32_next (h_snapshot, &proc_entry))
3907 proc_id = proc_entry.th32ProcessID;
3908 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
3911 CloseHandle (h_snapshot);
3912 UNGCPRO;
3913 proclist = Fnreverse (proclist);
3916 return proclist;
3919 static int
3920 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
3922 TOKEN_PRIVILEGES priv;
3923 DWORD priv_size = sizeof (priv);
3924 DWORD opriv_size = sizeof (*old_priv);
3925 HANDLE h_token = NULL;
3926 HANDLE h_thread = GetCurrentThread ();
3927 int ret_val = 0;
3928 BOOL res;
3930 res = open_thread_token (h_thread,
3931 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3932 FALSE, &h_token);
3933 if (!res && GetLastError () == ERROR_NO_TOKEN)
3935 if (impersonate_self (SecurityImpersonation))
3936 res = open_thread_token (h_thread,
3937 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3938 FALSE, &h_token);
3940 if (res)
3942 priv.PrivilegeCount = 1;
3943 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
3944 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
3945 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
3946 old_priv, &opriv_size)
3947 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3948 ret_val = 1;
3950 if (h_token)
3951 CloseHandle (h_token);
3953 return ret_val;
3956 static int
3957 restore_privilege (TOKEN_PRIVILEGES *priv)
3959 DWORD priv_size = sizeof (*priv);
3960 HANDLE h_token = NULL;
3961 int ret_val = 0;
3963 if (open_thread_token (GetCurrentThread (),
3964 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3965 FALSE, &h_token))
3967 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
3968 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3969 ret_val = 1;
3971 if (h_token)
3972 CloseHandle (h_token);
3974 return ret_val;
3977 static Lisp_Object
3978 ltime (time_sec, time_usec)
3979 long time_sec, time_usec;
3981 return list3 (make_number ((time_sec >> 16) & 0xffff),
3982 make_number (time_sec & 0xffff),
3983 make_number (time_usec));
3986 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
3988 static int
3989 process_times (h_proc, ctime, etime, stime, utime, ttime, pcpu)
3990 HANDLE h_proc;
3991 Lisp_Object *ctime, *etime, *stime, *utime, *ttime;
3992 double *pcpu;
3994 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
3995 ULONGLONG tem1, tem2, tem3, tem;
3997 if (!h_proc
3998 || !get_process_times_fn
3999 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
4000 &ft_kernel, &ft_user))
4001 return 0;
4003 GetSystemTimeAsFileTime (&ft_current);
4005 FILETIME_TO_U64 (tem1, ft_kernel);
4006 tem1 /= 10L;
4007 *stime = U64_TO_LISP_TIME (tem1);
4009 FILETIME_TO_U64 (tem2, ft_user);
4010 tem2 /= 10L;
4011 *utime = U64_TO_LISP_TIME (tem2);
4013 tem3 = tem1 + tem2;
4014 *ttime = U64_TO_LISP_TIME (tem3);
4016 FILETIME_TO_U64 (tem, ft_creation);
4017 /* Process no 4 (System) returns zero creation time. */
4018 if (tem)
4019 tem = (tem - utc_base) / 10L;
4020 *ctime = U64_TO_LISP_TIME (tem);
4022 if (tem)
4024 FILETIME_TO_U64 (tem3, ft_current);
4025 tem = (tem3 - utc_base) / 10L - tem;
4027 *etime = U64_TO_LISP_TIME (tem);
4029 if (tem)
4031 *pcpu = 100.0 * (tem1 + tem2) / tem;
4032 if (*pcpu > 100)
4033 *pcpu = 100.0;
4035 else
4036 *pcpu = 0;
4038 return 1;
4041 Lisp_Object
4042 system_process_attributes (pid)
4043 Lisp_Object pid;
4045 struct gcpro gcpro1, gcpro2, gcpro3;
4046 Lisp_Object attrs = Qnil;
4047 Lisp_Object cmd_str, decoded_cmd, tem;
4048 HANDLE h_snapshot, h_proc;
4049 DWORD proc_id;
4050 int found_proc = 0;
4051 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
4052 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
4053 DWORD glength = sizeof (gname);
4054 HANDLE token = NULL;
4055 SID_NAME_USE user_type;
4056 unsigned char *buf = NULL;
4057 DWORD blen = 0;
4058 TOKEN_USER user_token;
4059 TOKEN_PRIMARY_GROUP group_token;
4060 unsigned euid;
4061 unsigned egid;
4062 DWORD sess;
4063 PROCESS_MEMORY_COUNTERS mem;
4064 PROCESS_MEMORY_COUNTERS_EX mem_ex;
4065 DWORD minrss, maxrss;
4066 MEMORYSTATUS memst;
4067 MEMORY_STATUS_EX memstex;
4068 double totphys = 0.0;
4069 Lisp_Object ctime, stime, utime, etime, ttime;
4070 double pcpu;
4071 BOOL result = FALSE;
4073 CHECK_NUMBER_OR_FLOAT (pid);
4074 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
4076 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4078 GCPRO3 (attrs, decoded_cmd, tem);
4080 if (h_snapshot != INVALID_HANDLE_VALUE)
4082 PROCESSENTRY32 pe;
4083 BOOL res;
4085 pe.dwSize = sizeof (PROCESSENTRY32);
4086 for (res = process32_first (h_snapshot, &pe); res;
4087 res = process32_next (h_snapshot, &pe))
4089 if (proc_id == pe.th32ProcessID)
4091 if (proc_id == 0)
4092 decoded_cmd = build_string ("Idle");
4093 else
4095 /* Decode the command name from locale-specific
4096 encoding. */
4097 cmd_str = make_unibyte_string (pe.szExeFile,
4098 strlen (pe.szExeFile));
4099 decoded_cmd =
4100 code_convert_string_norecord (cmd_str,
4101 Vlocale_coding_system, 0);
4103 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
4104 attrs = Fcons (Fcons (Qppid,
4105 make_fixnum_or_float (pe.th32ParentProcessID)),
4106 attrs);
4107 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
4108 attrs);
4109 attrs = Fcons (Fcons (Qthcount,
4110 make_fixnum_or_float (pe.cntThreads)),
4111 attrs);
4112 found_proc = 1;
4113 break;
4117 CloseHandle (h_snapshot);
4120 if (!found_proc)
4122 UNGCPRO;
4123 return Qnil;
4126 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4127 FALSE, proc_id);
4128 /* If we were denied a handle to the process, try again after
4129 enabling the SeDebugPrivilege in our process. */
4130 if (!h_proc)
4132 TOKEN_PRIVILEGES priv_current;
4134 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
4136 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4137 FALSE, proc_id);
4138 restore_privilege (&priv_current);
4139 revert_to_self ();
4142 if (h_proc)
4144 result = open_process_token (h_proc, TOKEN_QUERY, &token);
4145 if (result)
4147 result = get_token_information (token, TokenUser, NULL, 0, &blen);
4148 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4150 buf = xmalloc (blen);
4151 result = get_token_information (token, TokenUser,
4152 (LPVOID)buf, blen, &needed);
4153 if (result)
4155 memcpy (&user_token, buf, sizeof (user_token));
4156 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
4158 euid = get_rid (user_token.User.Sid);
4159 result = lookup_account_sid (NULL, user_token.User.Sid,
4160 uname, &ulength,
4161 domain, &dlength,
4162 &user_type);
4163 if (result)
4164 w32_add_to_cache (user_token.User.Sid, euid, uname);
4165 else
4167 strcpy (uname, "unknown");
4168 result = TRUE;
4171 ulength = strlen (uname);
4175 if (result)
4177 /* Determine a reasonable euid and gid values. */
4178 if (xstrcasecmp ("administrator", uname) == 0)
4180 euid = 500; /* well-known Administrator uid */
4181 egid = 513; /* well-known None gid */
4183 else
4185 /* Get group id and name. */
4186 result = get_token_information (token, TokenPrimaryGroup,
4187 (LPVOID)buf, blen, &needed);
4188 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4190 buf = xrealloc (buf, blen = needed);
4191 result = get_token_information (token, TokenPrimaryGroup,
4192 (LPVOID)buf, blen, &needed);
4194 if (result)
4196 memcpy (&group_token, buf, sizeof (group_token));
4197 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
4199 egid = get_rid (group_token.PrimaryGroup);
4200 dlength = sizeof (domain);
4201 result =
4202 lookup_account_sid (NULL, group_token.PrimaryGroup,
4203 gname, &glength, NULL, &dlength,
4204 &user_type);
4205 if (result)
4206 w32_add_to_cache (group_token.PrimaryGroup,
4207 egid, gname);
4208 else
4210 strcpy (gname, "None");
4211 result = TRUE;
4214 glength = strlen (gname);
4218 xfree (buf);
4220 if (!result)
4222 if (!is_windows_9x ())
4224 /* We couldn't open the process token, presumably because of
4225 insufficient access rights. Assume this process is run
4226 by the system. */
4227 strcpy (uname, "SYSTEM");
4228 strcpy (gname, "None");
4229 euid = 18; /* SYSTEM */
4230 egid = 513; /* None */
4231 glength = strlen (gname);
4232 ulength = strlen (uname);
4234 /* If we are running under Windows 9X, where security calls are
4235 not supported, we assume all processes are run by the current
4236 user. */
4237 else if (GetUserName (uname, &ulength))
4239 if (xstrcasecmp ("administrator", uname) == 0)
4240 euid = 0;
4241 else
4242 euid = 123;
4243 egid = euid;
4244 strcpy (gname, "None");
4245 glength = strlen (gname);
4246 ulength = strlen (uname);
4248 else
4250 euid = 123;
4251 egid = 123;
4252 strcpy (uname, "administrator");
4253 ulength = strlen (uname);
4254 strcpy (gname, "None");
4255 glength = strlen (gname);
4257 if (token)
4258 CloseHandle (token);
4261 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
4262 tem = make_unibyte_string (uname, ulength);
4263 attrs = Fcons (Fcons (Quser,
4264 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4265 attrs);
4266 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
4267 tem = make_unibyte_string (gname, glength);
4268 attrs = Fcons (Fcons (Qgroup,
4269 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4270 attrs);
4272 if (global_memory_status_ex (&memstex))
4273 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4274 totphys = memstex.ullTotalPhys / 1024.0;
4275 #else
4276 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4277 double, so we need to do this for it... */
4279 DWORD tot_hi = memstex.ullTotalPhys >> 32;
4280 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
4281 DWORD tot_lo = memstex.ullTotalPhys % 1024;
4283 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
4285 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4286 else if (global_memory_status (&memst))
4287 totphys = memst.dwTotalPhys / 1024.0;
4289 if (h_proc
4290 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
4291 sizeof (mem_ex)))
4293 DWORD rss = mem_ex.WorkingSetSize / 1024;
4295 attrs = Fcons (Fcons (Qmajflt,
4296 make_fixnum_or_float (mem_ex.PageFaultCount)),
4297 attrs);
4298 attrs = Fcons (Fcons (Qvsize,
4299 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
4300 attrs);
4301 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4302 if (totphys)
4303 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4305 else if (h_proc
4306 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
4308 DWORD rss = mem_ex.WorkingSetSize / 1024;
4310 attrs = Fcons (Fcons (Qmajflt,
4311 make_fixnum_or_float (mem.PageFaultCount)),
4312 attrs);
4313 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4314 if (totphys)
4315 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4317 else if (h_proc
4318 && get_process_working_set_size (h_proc, &minrss, &maxrss))
4320 DWORD rss = maxrss / 1024;
4322 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
4323 if (totphys)
4324 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4327 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
4329 attrs = Fcons (Fcons (Qutime, utime), attrs);
4330 attrs = Fcons (Fcons (Qstime, stime), attrs);
4331 attrs = Fcons (Fcons (Qtime, ttime), attrs);
4332 attrs = Fcons (Fcons (Qstart, ctime), attrs);
4333 attrs = Fcons (Fcons (Qetime, etime), attrs);
4334 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
4337 /* FIXME: Retrieve command line by walking the PEB of the process. */
4339 if (h_proc)
4340 CloseHandle (h_proc);
4341 UNGCPRO;
4342 return attrs;
4346 #ifdef HAVE_SOCKETS
4348 /* Wrappers for winsock functions to map between our file descriptors
4349 and winsock's handles; also set h_errno for convenience.
4351 To allow Emacs to run on systems which don't have winsock support
4352 installed, we dynamically link to winsock on startup if present, and
4353 otherwise provide the minimum necessary functionality
4354 (eg. gethostname). */
4356 /* function pointers for relevant socket functions */
4357 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
4358 void (PASCAL *pfn_WSASetLastError) (int iError);
4359 int (PASCAL *pfn_WSAGetLastError) (void);
4360 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
4361 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
4362 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
4363 int (PASCAL *pfn_socket) (int af, int type, int protocol);
4364 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
4365 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
4366 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
4367 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
4368 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
4369 int (PASCAL *pfn_closesocket) (SOCKET s);
4370 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
4371 int (PASCAL *pfn_WSACleanup) (void);
4373 u_short (PASCAL *pfn_htons) (u_short hostshort);
4374 u_short (PASCAL *pfn_ntohs) (u_short netshort);
4375 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
4376 int (PASCAL *pfn_gethostname) (char * name, int namelen);
4377 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
4378 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
4379 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
4380 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
4381 const char * optval, int optlen);
4382 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
4383 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
4384 int * namelen);
4385 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
4386 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
4387 struct sockaddr * from, int * fromlen);
4388 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
4389 const struct sockaddr * to, int tolen);
4391 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4392 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
4393 #ifndef HANDLE_FLAG_INHERIT
4394 #define HANDLE_FLAG_INHERIT 1
4395 #endif
4397 HANDLE winsock_lib;
4398 static int winsock_inuse;
4400 BOOL
4401 term_winsock (void)
4403 if (winsock_lib != NULL && winsock_inuse == 0)
4405 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4406 after WSAStartup returns successfully, but it seems reasonable
4407 to allow unloading winsock anyway in that case. */
4408 if (pfn_WSACleanup () == 0 ||
4409 pfn_WSAGetLastError () == WSAENETDOWN)
4411 if (FreeLibrary (winsock_lib))
4412 winsock_lib = NULL;
4413 return TRUE;
4416 return FALSE;
4419 BOOL
4420 init_winsock (int load_now)
4422 WSADATA winsockData;
4424 if (winsock_lib != NULL)
4425 return TRUE;
4427 pfn_SetHandleInformation = NULL;
4428 pfn_SetHandleInformation
4429 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4430 "SetHandleInformation");
4432 winsock_lib = LoadLibrary ("Ws2_32.dll");
4434 if (winsock_lib != NULL)
4436 /* dynamically link to socket functions */
4438 #define LOAD_PROC(fn) \
4439 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4440 goto fail;
4442 LOAD_PROC (WSAStartup);
4443 LOAD_PROC (WSASetLastError);
4444 LOAD_PROC (WSAGetLastError);
4445 LOAD_PROC (WSAEventSelect);
4446 LOAD_PROC (WSACreateEvent);
4447 LOAD_PROC (WSACloseEvent);
4448 LOAD_PROC (socket);
4449 LOAD_PROC (bind);
4450 LOAD_PROC (connect);
4451 LOAD_PROC (ioctlsocket);
4452 LOAD_PROC (recv);
4453 LOAD_PROC (send);
4454 LOAD_PROC (closesocket);
4455 LOAD_PROC (shutdown);
4456 LOAD_PROC (htons);
4457 LOAD_PROC (ntohs);
4458 LOAD_PROC (inet_addr);
4459 LOAD_PROC (gethostname);
4460 LOAD_PROC (gethostbyname);
4461 LOAD_PROC (getservbyname);
4462 LOAD_PROC (getpeername);
4463 LOAD_PROC (WSACleanup);
4464 LOAD_PROC (setsockopt);
4465 LOAD_PROC (listen);
4466 LOAD_PROC (getsockname);
4467 LOAD_PROC (accept);
4468 LOAD_PROC (recvfrom);
4469 LOAD_PROC (sendto);
4470 #undef LOAD_PROC
4472 /* specify version 1.1 of winsock */
4473 if (pfn_WSAStartup (0x101, &winsockData) == 0)
4475 if (winsockData.wVersion != 0x101)
4476 goto fail;
4478 if (!load_now)
4480 /* Report that winsock exists and is usable, but leave
4481 socket functions disabled. I am assuming that calling
4482 WSAStartup does not require any network interaction,
4483 and in particular does not cause or require a dial-up
4484 connection to be established. */
4486 pfn_WSACleanup ();
4487 FreeLibrary (winsock_lib);
4488 winsock_lib = NULL;
4490 winsock_inuse = 0;
4491 return TRUE;
4494 fail:
4495 FreeLibrary (winsock_lib);
4496 winsock_lib = NULL;
4499 return FALSE;
4503 int h_errno = 0;
4505 /* function to set h_errno for compatibility; map winsock error codes to
4506 normal system codes where they overlap (non-overlapping definitions
4507 are already in <sys/socket.h> */
4508 static void
4509 set_errno ()
4511 if (winsock_lib == NULL)
4512 h_errno = EINVAL;
4513 else
4514 h_errno = pfn_WSAGetLastError ();
4516 switch (h_errno)
4518 case WSAEACCES: h_errno = EACCES; break;
4519 case WSAEBADF: h_errno = EBADF; break;
4520 case WSAEFAULT: h_errno = EFAULT; break;
4521 case WSAEINTR: h_errno = EINTR; break;
4522 case WSAEINVAL: h_errno = EINVAL; break;
4523 case WSAEMFILE: h_errno = EMFILE; break;
4524 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
4525 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
4527 errno = h_errno;
4530 static void
4531 check_errno ()
4533 if (h_errno == 0 && winsock_lib != NULL)
4534 pfn_WSASetLastError (0);
4537 /* Extend strerror to handle the winsock-specific error codes. */
4538 struct {
4539 int errnum;
4540 char * msg;
4541 } _wsa_errlist[] = {
4542 WSAEINTR , "Interrupted function call",
4543 WSAEBADF , "Bad file descriptor",
4544 WSAEACCES , "Permission denied",
4545 WSAEFAULT , "Bad address",
4546 WSAEINVAL , "Invalid argument",
4547 WSAEMFILE , "Too many open files",
4549 WSAEWOULDBLOCK , "Resource temporarily unavailable",
4550 WSAEINPROGRESS , "Operation now in progress",
4551 WSAEALREADY , "Operation already in progress",
4552 WSAENOTSOCK , "Socket operation on non-socket",
4553 WSAEDESTADDRREQ , "Destination address required",
4554 WSAEMSGSIZE , "Message too long",
4555 WSAEPROTOTYPE , "Protocol wrong type for socket",
4556 WSAENOPROTOOPT , "Bad protocol option",
4557 WSAEPROTONOSUPPORT , "Protocol not supported",
4558 WSAESOCKTNOSUPPORT , "Socket type not supported",
4559 WSAEOPNOTSUPP , "Operation not supported",
4560 WSAEPFNOSUPPORT , "Protocol family not supported",
4561 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
4562 WSAEADDRINUSE , "Address already in use",
4563 WSAEADDRNOTAVAIL , "Cannot assign requested address",
4564 WSAENETDOWN , "Network is down",
4565 WSAENETUNREACH , "Network is unreachable",
4566 WSAENETRESET , "Network dropped connection on reset",
4567 WSAECONNABORTED , "Software caused connection abort",
4568 WSAECONNRESET , "Connection reset by peer",
4569 WSAENOBUFS , "No buffer space available",
4570 WSAEISCONN , "Socket is already connected",
4571 WSAENOTCONN , "Socket is not connected",
4572 WSAESHUTDOWN , "Cannot send after socket shutdown",
4573 WSAETOOMANYREFS , "Too many references", /* not sure */
4574 WSAETIMEDOUT , "Connection timed out",
4575 WSAECONNREFUSED , "Connection refused",
4576 WSAELOOP , "Network loop", /* not sure */
4577 WSAENAMETOOLONG , "Name is too long",
4578 WSAEHOSTDOWN , "Host is down",
4579 WSAEHOSTUNREACH , "No route to host",
4580 WSAENOTEMPTY , "Buffer not empty", /* not sure */
4581 WSAEPROCLIM , "Too many processes",
4582 WSAEUSERS , "Too many users", /* not sure */
4583 WSAEDQUOT , "Double quote in host name", /* really not sure */
4584 WSAESTALE , "Data is stale", /* not sure */
4585 WSAEREMOTE , "Remote error", /* not sure */
4587 WSASYSNOTREADY , "Network subsystem is unavailable",
4588 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
4589 WSANOTINITIALISED , "Winsock not initialized successfully",
4590 WSAEDISCON , "Graceful shutdown in progress",
4591 #ifdef WSAENOMORE
4592 WSAENOMORE , "No more operations allowed", /* not sure */
4593 WSAECANCELLED , "Operation cancelled", /* not sure */
4594 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
4595 WSAEINVALIDPROVIDER , "Invalid service provider version number",
4596 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
4597 WSASYSCALLFAILURE , "System call failure",
4598 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
4599 WSATYPE_NOT_FOUND , "Class type not found",
4600 WSA_E_NO_MORE , "No more resources available", /* really not sure */
4601 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
4602 WSAEREFUSED , "Operation refused", /* not sure */
4603 #endif
4605 WSAHOST_NOT_FOUND , "Host not found",
4606 WSATRY_AGAIN , "Authoritative host not found during name lookup",
4607 WSANO_RECOVERY , "Non-recoverable error during name lookup",
4608 WSANO_DATA , "Valid name, no data record of requested type",
4610 -1, NULL
4613 char *
4614 sys_strerror (int error_no)
4616 int i;
4617 static char unknown_msg[40];
4619 if (error_no >= 0 && error_no < sys_nerr)
4620 return sys_errlist[error_no];
4622 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
4623 if (_wsa_errlist[i].errnum == error_no)
4624 return _wsa_errlist[i].msg;
4626 sprintf (unknown_msg, "Unidentified error: %d", error_no);
4627 return unknown_msg;
4630 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4631 but I believe the method of keeping the socket handle separate (and
4632 insuring it is not inheritable) is the correct one. */
4634 //#define SOCK_REPLACE_HANDLE
4636 #ifdef SOCK_REPLACE_HANDLE
4637 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
4638 #else
4639 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4640 #endif
4642 int socket_to_fd (SOCKET s);
4645 sys_socket (int af, int type, int protocol)
4647 SOCKET s;
4649 if (winsock_lib == NULL)
4651 h_errno = ENETDOWN;
4652 return INVALID_SOCKET;
4655 check_errno ();
4657 /* call the real socket function */
4658 s = pfn_socket (af, type, protocol);
4660 if (s != INVALID_SOCKET)
4661 return socket_to_fd (s);
4663 set_errno ();
4664 return -1;
4667 /* Convert a SOCKET to a file descriptor. */
4669 socket_to_fd (SOCKET s)
4671 int fd;
4672 child_process * cp;
4674 /* Although under NT 3.5 _open_osfhandle will accept a socket
4675 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4676 that does not work under NT 3.1. However, we can get the same
4677 effect by using a backdoor function to replace an existing
4678 descriptor handle with the one we want. */
4680 /* allocate a file descriptor (with appropriate flags) */
4681 fd = _open ("NUL:", _O_RDWR);
4682 if (fd >= 0)
4684 #ifdef SOCK_REPLACE_HANDLE
4685 /* now replace handle to NUL with our socket handle */
4686 CloseHandle ((HANDLE) _get_osfhandle (fd));
4687 _free_osfhnd (fd);
4688 _set_osfhnd (fd, s);
4689 /* setmode (fd, _O_BINARY); */
4690 #else
4691 /* Make a non-inheritable copy of the socket handle. Note
4692 that it is possible that sockets aren't actually kernel
4693 handles, which appears to be the case on Windows 9x when
4694 the MS Proxy winsock client is installed. */
4696 /* Apparently there is a bug in NT 3.51 with some service
4697 packs, which prevents using DuplicateHandle to make a
4698 socket handle non-inheritable (causes WSACleanup to
4699 hang). The work-around is to use SetHandleInformation
4700 instead if it is available and implemented. */
4701 if (pfn_SetHandleInformation)
4703 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
4705 else
4707 HANDLE parent = GetCurrentProcess ();
4708 HANDLE new_s = INVALID_HANDLE_VALUE;
4710 if (DuplicateHandle (parent,
4711 (HANDLE) s,
4712 parent,
4713 &new_s,
4715 FALSE,
4716 DUPLICATE_SAME_ACCESS))
4718 /* It is possible that DuplicateHandle succeeds even
4719 though the socket wasn't really a kernel handle,
4720 because a real handle has the same value. So
4721 test whether the new handle really is a socket. */
4722 long nonblocking = 0;
4723 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
4725 pfn_closesocket (s);
4726 s = (SOCKET) new_s;
4728 else
4730 CloseHandle (new_s);
4735 fd_info[fd].hnd = (HANDLE) s;
4736 #endif
4738 /* set our own internal flags */
4739 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
4741 cp = new_child ();
4742 if (cp)
4744 cp->fd = fd;
4745 cp->status = STATUS_READ_ACKNOWLEDGED;
4747 /* attach child_process to fd_info */
4748 if (fd_info[ fd ].cp != NULL)
4750 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
4751 abort ();
4754 fd_info[ fd ].cp = cp;
4756 /* success! */
4757 winsock_inuse++; /* count open sockets */
4758 return fd;
4761 /* clean up */
4762 _close (fd);
4764 pfn_closesocket (s);
4765 h_errno = EMFILE;
4766 return -1;
4771 sys_bind (int s, const struct sockaddr * addr, int namelen)
4773 if (winsock_lib == NULL)
4775 h_errno = ENOTSOCK;
4776 return SOCKET_ERROR;
4779 check_errno ();
4780 if (fd_info[s].flags & FILE_SOCKET)
4782 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
4783 if (rc == SOCKET_ERROR)
4784 set_errno ();
4785 return rc;
4787 h_errno = ENOTSOCK;
4788 return SOCKET_ERROR;
4793 sys_connect (int s, const struct sockaddr * name, int namelen)
4795 if (winsock_lib == NULL)
4797 h_errno = ENOTSOCK;
4798 return SOCKET_ERROR;
4801 check_errno ();
4802 if (fd_info[s].flags & FILE_SOCKET)
4804 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
4805 if (rc == SOCKET_ERROR)
4806 set_errno ();
4807 return rc;
4809 h_errno = ENOTSOCK;
4810 return SOCKET_ERROR;
4813 u_short
4814 sys_htons (u_short hostshort)
4816 return (winsock_lib != NULL) ?
4817 pfn_htons (hostshort) : hostshort;
4820 u_short
4821 sys_ntohs (u_short netshort)
4823 return (winsock_lib != NULL) ?
4824 pfn_ntohs (netshort) : netshort;
4827 unsigned long
4828 sys_inet_addr (const char * cp)
4830 return (winsock_lib != NULL) ?
4831 pfn_inet_addr (cp) : INADDR_NONE;
4835 sys_gethostname (char * name, int namelen)
4837 if (winsock_lib != NULL)
4838 return pfn_gethostname (name, namelen);
4840 if (namelen > MAX_COMPUTERNAME_LENGTH)
4841 return !GetComputerName (name, (DWORD *)&namelen);
4843 h_errno = EFAULT;
4844 return SOCKET_ERROR;
4847 struct hostent *
4848 sys_gethostbyname (const char * name)
4850 struct hostent * host;
4852 if (winsock_lib == NULL)
4854 h_errno = ENETDOWN;
4855 return NULL;
4858 check_errno ();
4859 host = pfn_gethostbyname (name);
4860 if (!host)
4861 set_errno ();
4862 return host;
4865 struct servent *
4866 sys_getservbyname (const char * name, const char * proto)
4868 struct servent * serv;
4870 if (winsock_lib == NULL)
4872 h_errno = ENETDOWN;
4873 return NULL;
4876 check_errno ();
4877 serv = pfn_getservbyname (name, proto);
4878 if (!serv)
4879 set_errno ();
4880 return serv;
4884 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
4886 if (winsock_lib == NULL)
4888 h_errno = ENETDOWN;
4889 return SOCKET_ERROR;
4892 check_errno ();
4893 if (fd_info[s].flags & FILE_SOCKET)
4895 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
4896 if (rc == SOCKET_ERROR)
4897 set_errno ();
4898 return rc;
4900 h_errno = ENOTSOCK;
4901 return SOCKET_ERROR;
4906 sys_shutdown (int s, int how)
4908 if (winsock_lib == NULL)
4910 h_errno = ENETDOWN;
4911 return SOCKET_ERROR;
4914 check_errno ();
4915 if (fd_info[s].flags & FILE_SOCKET)
4917 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
4918 if (rc == SOCKET_ERROR)
4919 set_errno ();
4920 return rc;
4922 h_errno = ENOTSOCK;
4923 return SOCKET_ERROR;
4927 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
4929 if (winsock_lib == NULL)
4931 h_errno = ENETDOWN;
4932 return SOCKET_ERROR;
4935 check_errno ();
4936 if (fd_info[s].flags & FILE_SOCKET)
4938 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
4939 (const char *)optval, optlen);
4940 if (rc == SOCKET_ERROR)
4941 set_errno ();
4942 return rc;
4944 h_errno = ENOTSOCK;
4945 return SOCKET_ERROR;
4949 sys_listen (int s, int backlog)
4951 if (winsock_lib == NULL)
4953 h_errno = ENETDOWN;
4954 return SOCKET_ERROR;
4957 check_errno ();
4958 if (fd_info[s].flags & FILE_SOCKET)
4960 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
4961 if (rc == SOCKET_ERROR)
4962 set_errno ();
4963 else
4964 fd_info[s].flags |= FILE_LISTEN;
4965 return rc;
4967 h_errno = ENOTSOCK;
4968 return SOCKET_ERROR;
4972 sys_getsockname (int s, struct sockaddr * name, int * namelen)
4974 if (winsock_lib == NULL)
4976 h_errno = ENETDOWN;
4977 return SOCKET_ERROR;
4980 check_errno ();
4981 if (fd_info[s].flags & FILE_SOCKET)
4983 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
4984 if (rc == SOCKET_ERROR)
4985 set_errno ();
4986 return rc;
4988 h_errno = ENOTSOCK;
4989 return SOCKET_ERROR;
4993 sys_accept (int s, struct sockaddr * addr, int * addrlen)
4995 if (winsock_lib == NULL)
4997 h_errno = ENETDOWN;
4998 return -1;
5001 check_errno ();
5002 if (fd_info[s].flags & FILE_LISTEN)
5004 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
5005 int fd = -1;
5006 if (t == INVALID_SOCKET)
5007 set_errno ();
5008 else
5009 fd = socket_to_fd (t);
5011 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
5012 ResetEvent (fd_info[s].cp->char_avail);
5013 return fd;
5015 h_errno = ENOTSOCK;
5016 return -1;
5020 sys_recvfrom (int s, char * buf, int len, int flags,
5021 struct sockaddr * from, int * fromlen)
5023 if (winsock_lib == NULL)
5025 h_errno = ENETDOWN;
5026 return SOCKET_ERROR;
5029 check_errno ();
5030 if (fd_info[s].flags & FILE_SOCKET)
5032 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
5033 if (rc == SOCKET_ERROR)
5034 set_errno ();
5035 return rc;
5037 h_errno = ENOTSOCK;
5038 return SOCKET_ERROR;
5042 sys_sendto (int s, const char * buf, int len, int flags,
5043 const struct sockaddr * to, int tolen)
5045 if (winsock_lib == NULL)
5047 h_errno = ENETDOWN;
5048 return SOCKET_ERROR;
5051 check_errno ();
5052 if (fd_info[s].flags & FILE_SOCKET)
5054 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
5055 if (rc == SOCKET_ERROR)
5056 set_errno ();
5057 return rc;
5059 h_errno = ENOTSOCK;
5060 return SOCKET_ERROR;
5063 /* Windows does not have an fcntl function. Provide an implementation
5064 solely for making sockets non-blocking. */
5066 fcntl (int s, int cmd, int options)
5068 if (winsock_lib == NULL)
5070 h_errno = ENETDOWN;
5071 return -1;
5074 check_errno ();
5075 if (fd_info[s].flags & FILE_SOCKET)
5077 if (cmd == F_SETFL && options == O_NDELAY)
5079 unsigned long nblock = 1;
5080 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
5081 if (rc == SOCKET_ERROR)
5082 set_errno ();
5083 /* Keep track of the fact that we set this to non-blocking. */
5084 fd_info[s].flags |= FILE_NDELAY;
5085 return rc;
5087 else
5089 h_errno = EINVAL;
5090 return SOCKET_ERROR;
5093 h_errno = ENOTSOCK;
5094 return SOCKET_ERROR;
5097 #endif /* HAVE_SOCKETS */
5100 /* Shadow main io functions: we need to handle pipes and sockets more
5101 intelligently, and implement non-blocking mode as well. */
5104 sys_close (int fd)
5106 int rc;
5108 if (fd < 0)
5110 errno = EBADF;
5111 return -1;
5114 if (fd < MAXDESC && fd_info[fd].cp)
5116 child_process * cp = fd_info[fd].cp;
5118 fd_info[fd].cp = NULL;
5120 if (CHILD_ACTIVE (cp))
5122 /* if last descriptor to active child_process then cleanup */
5123 int i;
5124 for (i = 0; i < MAXDESC; i++)
5126 if (i == fd)
5127 continue;
5128 if (fd_info[i].cp == cp)
5129 break;
5131 if (i == MAXDESC)
5133 #ifdef HAVE_SOCKETS
5134 if (fd_info[fd].flags & FILE_SOCKET)
5136 #ifndef SOCK_REPLACE_HANDLE
5137 if (winsock_lib == NULL) abort ();
5139 pfn_shutdown (SOCK_HANDLE (fd), 2);
5140 rc = pfn_closesocket (SOCK_HANDLE (fd));
5141 #endif
5142 winsock_inuse--; /* count open sockets */
5144 #endif
5145 delete_child (cp);
5150 /* Note that sockets do not need special treatment here (at least on
5151 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5152 closesocket is equivalent to CloseHandle, which is to be expected
5153 because socket handles are fully fledged kernel handles. */
5154 rc = _close (fd);
5156 if (rc == 0 && fd < MAXDESC)
5157 fd_info[fd].flags = 0;
5159 return rc;
5163 sys_dup (int fd)
5165 int new_fd;
5167 new_fd = _dup (fd);
5168 if (new_fd >= 0 && new_fd < MAXDESC)
5170 /* duplicate our internal info as well */
5171 fd_info[new_fd] = fd_info[fd];
5173 return new_fd;
5178 sys_dup2 (int src, int dst)
5180 int rc;
5182 if (dst < 0 || dst >= MAXDESC)
5184 errno = EBADF;
5185 return -1;
5188 /* make sure we close the destination first if it's a pipe or socket */
5189 if (src != dst && fd_info[dst].flags != 0)
5190 sys_close (dst);
5192 rc = _dup2 (src, dst);
5193 if (rc == 0)
5195 /* duplicate our internal info as well */
5196 fd_info[dst] = fd_info[src];
5198 return rc;
5201 /* Unix pipe() has only one arg */
5203 sys_pipe (int * phandles)
5205 int rc;
5206 unsigned flags;
5208 /* make pipe handles non-inheritable; when we spawn a child, we
5209 replace the relevant handle with an inheritable one. Also put
5210 pipes into binary mode; we will do text mode translation ourselves
5211 if required. */
5212 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
5214 if (rc == 0)
5216 /* Protect against overflow, since Windows can open more handles than
5217 our fd_info array has room for. */
5218 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
5220 _close (phandles[0]);
5221 _close (phandles[1]);
5222 rc = -1;
5224 else
5226 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
5227 fd_info[phandles[0]].flags = flags;
5229 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
5230 fd_info[phandles[1]].flags = flags;
5234 return rc;
5237 /* From ntproc.c */
5238 extern int w32_pipe_read_delay;
5240 /* Function to do blocking read of one byte, needed to implement
5241 select. It is only allowed on sockets and pipes. */
5243 _sys_read_ahead (int fd)
5245 child_process * cp;
5246 int rc;
5248 if (fd < 0 || fd >= MAXDESC)
5249 return STATUS_READ_ERROR;
5251 cp = fd_info[fd].cp;
5253 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5254 return STATUS_READ_ERROR;
5256 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
5257 || (fd_info[fd].flags & FILE_READ) == 0)
5259 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
5260 abort ();
5263 cp->status = STATUS_READ_IN_PROGRESS;
5265 if (fd_info[fd].flags & FILE_PIPE)
5267 rc = _read (fd, &cp->chr, sizeof (char));
5269 /* Give subprocess time to buffer some more output for us before
5270 reporting that input is available; we need this because Windows 95
5271 connects DOS programs to pipes by making the pipe appear to be
5272 the normal console stdout - as a result most DOS programs will
5273 write to stdout without buffering, ie. one character at a
5274 time. Even some W32 programs do this - "dir" in a command
5275 shell on NT is very slow if we don't do this. */
5276 if (rc > 0)
5278 int wait = w32_pipe_read_delay;
5280 if (wait > 0)
5281 Sleep (wait);
5282 else if (wait < 0)
5283 while (++wait <= 0)
5284 /* Yield remainder of our time slice, effectively giving a
5285 temporary priority boost to the child process. */
5286 Sleep (0);
5289 else if (fd_info[fd].flags & FILE_SERIAL)
5291 HANDLE hnd = fd_info[fd].hnd;
5292 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5293 COMMTIMEOUTS ct;
5295 /* Configure timeouts for blocking read. */
5296 if (!GetCommTimeouts (hnd, &ct))
5297 return STATUS_READ_ERROR;
5298 ct.ReadIntervalTimeout = 0;
5299 ct.ReadTotalTimeoutMultiplier = 0;
5300 ct.ReadTotalTimeoutConstant = 0;
5301 if (!SetCommTimeouts (hnd, &ct))
5302 return STATUS_READ_ERROR;
5304 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
5306 if (GetLastError () != ERROR_IO_PENDING)
5307 return STATUS_READ_ERROR;
5308 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5309 return STATUS_READ_ERROR;
5312 #ifdef HAVE_SOCKETS
5313 else if (fd_info[fd].flags & FILE_SOCKET)
5315 unsigned long nblock = 0;
5316 /* We always want this to block, so temporarily disable NDELAY. */
5317 if (fd_info[fd].flags & FILE_NDELAY)
5318 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5320 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
5322 if (fd_info[fd].flags & FILE_NDELAY)
5324 nblock = 1;
5325 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5328 #endif
5330 if (rc == sizeof (char))
5331 cp->status = STATUS_READ_SUCCEEDED;
5332 else
5333 cp->status = STATUS_READ_FAILED;
5335 return cp->status;
5339 _sys_wait_accept (int fd)
5341 HANDLE hEv;
5342 child_process * cp;
5343 int rc;
5345 if (fd < 0 || fd >= MAXDESC)
5346 return STATUS_READ_ERROR;
5348 cp = fd_info[fd].cp;
5350 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5351 return STATUS_READ_ERROR;
5353 cp->status = STATUS_READ_FAILED;
5355 hEv = pfn_WSACreateEvent ();
5356 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
5357 if (rc != SOCKET_ERROR)
5359 rc = WaitForSingleObject (hEv, INFINITE);
5360 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
5361 if (rc == WAIT_OBJECT_0)
5362 cp->status = STATUS_READ_SUCCEEDED;
5364 pfn_WSACloseEvent (hEv);
5366 return cp->status;
5370 sys_read (int fd, char * buffer, unsigned int count)
5372 int nchars;
5373 int to_read;
5374 DWORD waiting;
5375 char * orig_buffer = buffer;
5377 if (fd < 0)
5379 errno = EBADF;
5380 return -1;
5383 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5385 child_process *cp = fd_info[fd].cp;
5387 if ((fd_info[fd].flags & FILE_READ) == 0)
5389 errno = EBADF;
5390 return -1;
5393 nchars = 0;
5395 /* re-read CR carried over from last read */
5396 if (fd_info[fd].flags & FILE_LAST_CR)
5398 if (fd_info[fd].flags & FILE_BINARY) abort ();
5399 *buffer++ = 0x0d;
5400 count--;
5401 nchars++;
5402 fd_info[fd].flags &= ~FILE_LAST_CR;
5405 /* presence of a child_process structure means we are operating in
5406 non-blocking mode - otherwise we just call _read directly.
5407 Note that the child_process structure might be missing because
5408 reap_subprocess has been called; in this case the pipe is
5409 already broken, so calling _read on it is okay. */
5410 if (cp)
5412 int current_status = cp->status;
5414 switch (current_status)
5416 case STATUS_READ_FAILED:
5417 case STATUS_READ_ERROR:
5418 /* report normal EOF if nothing in buffer */
5419 if (nchars <= 0)
5420 fd_info[fd].flags |= FILE_AT_EOF;
5421 return nchars;
5423 case STATUS_READ_READY:
5424 case STATUS_READ_IN_PROGRESS:
5425 DebPrint (("sys_read called when read is in progress\n"));
5426 errno = EWOULDBLOCK;
5427 return -1;
5429 case STATUS_READ_SUCCEEDED:
5430 /* consume read-ahead char */
5431 *buffer++ = cp->chr;
5432 count--;
5433 nchars++;
5434 cp->status = STATUS_READ_ACKNOWLEDGED;
5435 ResetEvent (cp->char_avail);
5437 case STATUS_READ_ACKNOWLEDGED:
5438 break;
5440 default:
5441 DebPrint (("sys_read: bad status %d\n", current_status));
5442 errno = EBADF;
5443 return -1;
5446 if (fd_info[fd].flags & FILE_PIPE)
5448 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
5449 to_read = min (waiting, (DWORD) count);
5451 if (to_read > 0)
5452 nchars += _read (fd, buffer, to_read);
5454 else if (fd_info[fd].flags & FILE_SERIAL)
5456 HANDLE hnd = fd_info[fd].hnd;
5457 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5458 DWORD err = 0;
5459 int rc = 0;
5460 COMMTIMEOUTS ct;
5462 if (count > 0)
5464 /* Configure timeouts for non-blocking read. */
5465 if (!GetCommTimeouts (hnd, &ct))
5467 errno = EIO;
5468 return -1;
5470 ct.ReadIntervalTimeout = MAXDWORD;
5471 ct.ReadTotalTimeoutMultiplier = 0;
5472 ct.ReadTotalTimeoutConstant = 0;
5473 if (!SetCommTimeouts (hnd, &ct))
5475 errno = EIO;
5476 return -1;
5479 if (!ResetEvent (ovl->hEvent))
5481 errno = EIO;
5482 return -1;
5484 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
5486 if (GetLastError () != ERROR_IO_PENDING)
5488 errno = EIO;
5489 return -1;
5491 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5493 errno = EIO;
5494 return -1;
5497 nchars += rc;
5500 #ifdef HAVE_SOCKETS
5501 else /* FILE_SOCKET */
5503 if (winsock_lib == NULL) abort ();
5505 /* do the equivalent of a non-blocking read */
5506 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
5507 if (waiting == 0 && nchars == 0)
5509 h_errno = errno = EWOULDBLOCK;
5510 return -1;
5513 if (waiting)
5515 /* always use binary mode for sockets */
5516 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
5517 if (res == SOCKET_ERROR)
5519 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5520 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5521 set_errno ();
5522 return -1;
5524 nchars += res;
5527 #endif
5529 else
5531 int nread = _read (fd, buffer, count);
5532 if (nread >= 0)
5533 nchars += nread;
5534 else if (nchars == 0)
5535 nchars = nread;
5538 if (nchars <= 0)
5539 fd_info[fd].flags |= FILE_AT_EOF;
5540 /* Perform text mode translation if required. */
5541 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
5543 nchars = crlf_to_lf (nchars, orig_buffer);
5544 /* If buffer contains only CR, return that. To be absolutely
5545 sure we should attempt to read the next char, but in
5546 practice a CR to be followed by LF would not appear by
5547 itself in the buffer. */
5548 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
5550 fd_info[fd].flags |= FILE_LAST_CR;
5551 nchars--;
5555 else
5556 nchars = _read (fd, buffer, count);
5558 return nchars;
5561 /* From w32xfns.c */
5562 extern HANDLE interrupt_handle;
5564 /* For now, don't bother with a non-blocking mode */
5566 sys_write (int fd, const void * buffer, unsigned int count)
5568 int nchars;
5570 if (fd < 0)
5572 errno = EBADF;
5573 return -1;
5576 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5578 if ((fd_info[fd].flags & FILE_WRITE) == 0)
5580 errno = EBADF;
5581 return -1;
5584 /* Perform text mode translation if required. */
5585 if ((fd_info[fd].flags & FILE_BINARY) == 0)
5587 char * tmpbuf = alloca (count * 2);
5588 unsigned char * src = (void *)buffer;
5589 unsigned char * dst = tmpbuf;
5590 int nbytes = count;
5592 while (1)
5594 unsigned char *next;
5595 /* copy next line or remaining bytes */
5596 next = _memccpy (dst, src, '\n', nbytes);
5597 if (next)
5599 /* copied one line ending with '\n' */
5600 int copied = next - dst;
5601 nbytes -= copied;
5602 src += copied;
5603 /* insert '\r' before '\n' */
5604 next[-1] = '\r';
5605 next[0] = '\n';
5606 dst = next + 1;
5607 count++;
5609 else
5610 /* copied remaining partial line -> now finished */
5611 break;
5613 buffer = tmpbuf;
5617 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
5619 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
5620 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
5621 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
5622 DWORD active = 0;
5624 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
5626 if (GetLastError () != ERROR_IO_PENDING)
5628 errno = EIO;
5629 return -1;
5631 if (detect_input_pending ())
5632 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
5633 QS_ALLINPUT);
5634 else
5635 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
5636 if (active == WAIT_OBJECT_0)
5637 { /* User pressed C-g, cancel write, then leave. Don't bother
5638 cleaning up as we may only get stuck in buggy drivers. */
5639 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
5640 CancelIo (hnd);
5641 errno = EIO;
5642 return -1;
5644 if (active == WAIT_OBJECT_0 + 1
5645 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
5647 errno = EIO;
5648 return -1;
5652 else
5653 #ifdef HAVE_SOCKETS
5654 if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
5656 unsigned long nblock = 0;
5657 if (winsock_lib == NULL) abort ();
5659 /* TODO: implement select() properly so non-blocking I/O works. */
5660 /* For now, make sure the write blocks. */
5661 if (fd_info[fd].flags & FILE_NDELAY)
5662 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5664 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
5666 /* Set the socket back to non-blocking if it was before,
5667 for other operations that support it. */
5668 if (fd_info[fd].flags & FILE_NDELAY)
5670 nblock = 1;
5671 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5674 if (nchars == SOCKET_ERROR)
5676 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5677 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5678 set_errno ();
5681 else
5682 #endif
5683 nchars = _write (fd, buffer, count);
5685 return nchars;
5688 /* The Windows CRT functions are "optimized for speed", so they don't
5689 check for timezone and DST changes if they were last called less
5690 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
5691 all Emacs features that repeatedly call time functions (e.g.,
5692 display-time) are in real danger of missing timezone and DST
5693 changes. Calling tzset before each localtime call fixes that. */
5694 struct tm *
5695 sys_localtime (const time_t *t)
5697 tzset ();
5698 return localtime (t);
5701 static void
5702 check_windows_init_file ()
5704 extern int noninteractive, inhibit_window_system;
5706 /* A common indication that Emacs is not installed properly is when
5707 it cannot find the Windows installation file. If this file does
5708 not exist in the expected place, tell the user. */
5710 if (!noninteractive && !inhibit_window_system)
5712 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
5713 Lisp_Object objs[2];
5714 Lisp_Object full_load_path;
5715 Lisp_Object init_file;
5716 int fd;
5718 objs[0] = Vload_path;
5719 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5720 full_load_path = Fappend (2, objs);
5721 init_file = build_string ("term/w32-win");
5722 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
5723 if (fd < 0)
5725 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
5726 char *init_file_name = SDATA (init_file);
5727 char *load_path = SDATA (load_path_print);
5728 char *buffer = alloca (1024
5729 + strlen (init_file_name)
5730 + strlen (load_path));
5732 sprintf (buffer,
5733 "The Emacs Windows initialization file \"%s.el\" "
5734 "could not be found in your Emacs installation. "
5735 "Emacs checked the following directories for this file:\n"
5736 "\n%s\n\n"
5737 "When Emacs cannot find this file, it usually means that it "
5738 "was not installed properly, or its distribution file was "
5739 "not unpacked properly.\nSee the README.W32 file in the "
5740 "top-level Emacs directory for more information.",
5741 init_file_name, load_path);
5742 MessageBox (NULL,
5743 buffer,
5744 "Emacs Abort Dialog",
5745 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
5746 /* Use the low-level Emacs abort. */
5747 #undef abort
5748 abort ();
5750 else
5752 _close (fd);
5757 void
5758 term_ntproc ()
5760 #ifdef HAVE_SOCKETS
5761 /* shutdown the socket interface if necessary */
5762 term_winsock ();
5763 #endif
5765 term_w32select ();
5768 void
5769 init_ntproc ()
5771 #ifdef HAVE_SOCKETS
5772 /* Initialise the socket interface now if available and requested by
5773 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5774 delayed until open-network-stream is called (w32-has-winsock can
5775 also be used to dynamically load or reload winsock).
5777 Conveniently, init_environment is called before us, so
5778 PRELOAD_WINSOCK can be set in the registry. */
5780 /* Always initialize this correctly. */
5781 winsock_lib = NULL;
5783 if (getenv ("PRELOAD_WINSOCK") != NULL)
5784 init_winsock (TRUE);
5785 #endif
5787 /* Initial preparation for subprocess support: replace our standard
5788 handles with non-inheritable versions. */
5790 HANDLE parent;
5791 HANDLE stdin_save = INVALID_HANDLE_VALUE;
5792 HANDLE stdout_save = INVALID_HANDLE_VALUE;
5793 HANDLE stderr_save = INVALID_HANDLE_VALUE;
5795 parent = GetCurrentProcess ();
5797 /* ignore errors when duplicating and closing; typically the
5798 handles will be invalid when running as a gui program. */
5799 DuplicateHandle (parent,
5800 GetStdHandle (STD_INPUT_HANDLE),
5801 parent,
5802 &stdin_save,
5804 FALSE,
5805 DUPLICATE_SAME_ACCESS);
5807 DuplicateHandle (parent,
5808 GetStdHandle (STD_OUTPUT_HANDLE),
5809 parent,
5810 &stdout_save,
5812 FALSE,
5813 DUPLICATE_SAME_ACCESS);
5815 DuplicateHandle (parent,
5816 GetStdHandle (STD_ERROR_HANDLE),
5817 parent,
5818 &stderr_save,
5820 FALSE,
5821 DUPLICATE_SAME_ACCESS);
5823 fclose (stdin);
5824 fclose (stdout);
5825 fclose (stderr);
5827 if (stdin_save != INVALID_HANDLE_VALUE)
5828 _open_osfhandle ((long) stdin_save, O_TEXT);
5829 else
5830 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
5831 _fdopen (0, "r");
5833 if (stdout_save != INVALID_HANDLE_VALUE)
5834 _open_osfhandle ((long) stdout_save, O_TEXT);
5835 else
5836 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5837 _fdopen (1, "w");
5839 if (stderr_save != INVALID_HANDLE_VALUE)
5840 _open_osfhandle ((long) stderr_save, O_TEXT);
5841 else
5842 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5843 _fdopen (2, "w");
5846 /* unfortunately, atexit depends on implementation of malloc */
5847 /* atexit (term_ntproc); */
5848 signal (SIGABRT, term_ntproc);
5850 /* determine which drives are fixed, for GetCachedVolumeInformation */
5852 /* GetDriveType must have trailing backslash. */
5853 char drive[] = "A:\\";
5855 /* Loop over all possible drive letters */
5856 while (*drive <= 'Z')
5858 /* Record if this drive letter refers to a fixed drive. */
5859 fixed_drives[DRIVE_INDEX (*drive)] =
5860 (GetDriveType (drive) == DRIVE_FIXED);
5862 (*drive)++;
5865 /* Reset the volume info cache. */
5866 volume_cache = NULL;
5869 /* Check to see if Emacs has been installed correctly. */
5870 check_windows_init_file ();
5874 shutdown_handler ensures that buffers' autosave files are
5875 up to date when the user logs off, or the system shuts down.
5877 BOOL WINAPI
5878 shutdown_handler (DWORD type)
5880 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5881 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
5882 || type == CTRL_LOGOFF_EVENT /* User logs off. */
5883 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
5885 /* Shut down cleanly, making sure autosave files are up to date. */
5886 shut_down_emacs (0, 0, Qnil);
5889 /* Allow other handlers to handle this signal. */
5890 return FALSE;
5894 globals_of_w32 is used to initialize those global variables that
5895 must always be initialized on startup even when the global variable
5896 initialized is non zero (see the function main in emacs.c).
5898 void
5899 globals_of_w32 ()
5901 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
5903 get_process_times_fn = (GetProcessTimes_Proc)
5904 GetProcAddress (kernel32, "GetProcessTimes");
5906 g_b_init_is_windows_9x = 0;
5907 g_b_init_open_process_token = 0;
5908 g_b_init_get_token_information = 0;
5909 g_b_init_lookup_account_sid = 0;
5910 g_b_init_get_sid_identifier_authority = 0;
5911 g_b_init_get_sid_sub_authority = 0;
5912 g_b_init_get_sid_sub_authority_count = 0;
5913 g_b_init_get_file_security = 0;
5914 g_b_init_get_security_descriptor_owner = 0;
5915 g_b_init_get_security_descriptor_group = 0;
5916 g_b_init_is_valid_sid = 0;
5917 g_b_init_create_toolhelp32_snapshot = 0;
5918 g_b_init_process32_first = 0;
5919 g_b_init_process32_next = 0;
5920 g_b_init_open_thread_token = 0;
5921 g_b_init_impersonate_self = 0;
5922 g_b_init_revert_to_self = 0;
5923 g_b_init_get_process_memory_info = 0;
5924 g_b_init_get_process_working_set_size = 0;
5925 g_b_init_global_memory_status = 0;
5926 g_b_init_global_memory_status_ex = 0;
5927 g_b_init_equal_sid = 0;
5928 g_b_init_copy_sid = 0;
5929 g_b_init_get_length_sid = 0;
5930 g_b_init_get_native_system_info = 0;
5931 g_b_init_get_system_times = 0;
5932 num_of_processors = 0;
5933 /* The following sets a handler for shutdown notifications for
5934 console apps. This actually applies to Emacs in both console and
5935 GUI modes, since we had to fool windows into thinking emacs is a
5936 console application to get console mode to work. */
5937 SetConsoleCtrlHandler (shutdown_handler, TRUE);
5939 /* "None" is the default group name on standalone workstations. */
5940 strcpy (dflt_group_name, "None");
5943 /* For make-serial-process */
5945 serial_open (char *port)
5947 HANDLE hnd;
5948 child_process *cp;
5949 int fd = -1;
5951 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
5952 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
5953 if (hnd == INVALID_HANDLE_VALUE)
5954 error ("Could not open %s", port);
5955 fd = (int) _open_osfhandle ((int) hnd, 0);
5956 if (fd == -1)
5957 error ("Could not open %s", port);
5959 cp = new_child ();
5960 if (!cp)
5961 error ("Could not create child process");
5962 cp->fd = fd;
5963 cp->status = STATUS_READ_ACKNOWLEDGED;
5964 fd_info[ fd ].hnd = hnd;
5965 fd_info[ fd ].flags |=
5966 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
5967 if (fd_info[ fd ].cp != NULL)
5969 error ("fd_info[fd = %d] is already in use", fd);
5971 fd_info[ fd ].cp = cp;
5972 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5973 if (cp->ovl_read.hEvent == NULL)
5974 error ("Could not create read event");
5975 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5976 if (cp->ovl_write.hEvent == NULL)
5977 error ("Could not create write event");
5979 return fd;
5982 /* For serial-process-configure */
5983 void
5984 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
5986 Lisp_Object childp2 = Qnil;
5987 Lisp_Object tem = Qnil;
5988 HANDLE hnd;
5989 DCB dcb;
5990 COMMTIMEOUTS ct;
5991 char summary[4] = "???"; /* This usually becomes "8N1". */
5993 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
5994 error ("Not a serial process");
5995 hnd = fd_info[ p->outfd ].hnd;
5997 childp2 = Fcopy_sequence (p->childp);
5999 /* Initialize timeouts for blocking read and blocking write. */
6000 if (!GetCommTimeouts (hnd, &ct))
6001 error ("GetCommTimeouts() failed");
6002 ct.ReadIntervalTimeout = 0;
6003 ct.ReadTotalTimeoutMultiplier = 0;
6004 ct.ReadTotalTimeoutConstant = 0;
6005 ct.WriteTotalTimeoutMultiplier = 0;
6006 ct.WriteTotalTimeoutConstant = 0;
6007 if (!SetCommTimeouts (hnd, &ct))
6008 error ("SetCommTimeouts() failed");
6009 /* Read port attributes and prepare default configuration. */
6010 memset (&dcb, 0, sizeof (dcb));
6011 dcb.DCBlength = sizeof (DCB);
6012 if (!GetCommState (hnd, &dcb))
6013 error ("GetCommState() failed");
6014 dcb.fBinary = TRUE;
6015 dcb.fNull = FALSE;
6016 dcb.fAbortOnError = FALSE;
6017 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6018 dcb.ErrorChar = 0;
6019 dcb.EofChar = 0;
6020 dcb.EvtChar = 0;
6022 /* Configure speed. */
6023 if (!NILP (Fplist_member (contact, QCspeed)))
6024 tem = Fplist_get (contact, QCspeed);
6025 else
6026 tem = Fplist_get (p->childp, QCspeed);
6027 CHECK_NUMBER (tem);
6028 dcb.BaudRate = XINT (tem);
6029 childp2 = Fplist_put (childp2, QCspeed, tem);
6031 /* Configure bytesize. */
6032 if (!NILP (Fplist_member (contact, QCbytesize)))
6033 tem = Fplist_get (contact, QCbytesize);
6034 else
6035 tem = Fplist_get (p->childp, QCbytesize);
6036 if (NILP (tem))
6037 tem = make_number (8);
6038 CHECK_NUMBER (tem);
6039 if (XINT (tem) != 7 && XINT (tem) != 8)
6040 error (":bytesize must be nil (8), 7, or 8");
6041 dcb.ByteSize = XINT (tem);
6042 summary[0] = XINT (tem) + '0';
6043 childp2 = Fplist_put (childp2, QCbytesize, tem);
6045 /* Configure parity. */
6046 if (!NILP (Fplist_member (contact, QCparity)))
6047 tem = Fplist_get (contact, QCparity);
6048 else
6049 tem = Fplist_get (p->childp, QCparity);
6050 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
6051 error (":parity must be nil (no parity), `even', or `odd'");
6052 dcb.fParity = FALSE;
6053 dcb.Parity = NOPARITY;
6054 dcb.fErrorChar = FALSE;
6055 if (NILP (tem))
6057 summary[1] = 'N';
6059 else if (EQ (tem, Qeven))
6061 summary[1] = 'E';
6062 dcb.fParity = TRUE;
6063 dcb.Parity = EVENPARITY;
6064 dcb.fErrorChar = TRUE;
6066 else if (EQ (tem, Qodd))
6068 summary[1] = 'O';
6069 dcb.fParity = TRUE;
6070 dcb.Parity = ODDPARITY;
6071 dcb.fErrorChar = TRUE;
6073 childp2 = Fplist_put (childp2, QCparity, tem);
6075 /* Configure stopbits. */
6076 if (!NILP (Fplist_member (contact, QCstopbits)))
6077 tem = Fplist_get (contact, QCstopbits);
6078 else
6079 tem = Fplist_get (p->childp, QCstopbits);
6080 if (NILP (tem))
6081 tem = make_number (1);
6082 CHECK_NUMBER (tem);
6083 if (XINT (tem) != 1 && XINT (tem) != 2)
6084 error (":stopbits must be nil (1 stopbit), 1, or 2");
6085 summary[2] = XINT (tem) + '0';
6086 if (XINT (tem) == 1)
6087 dcb.StopBits = ONESTOPBIT;
6088 else if (XINT (tem) == 2)
6089 dcb.StopBits = TWOSTOPBITS;
6090 childp2 = Fplist_put (childp2, QCstopbits, tem);
6092 /* Configure flowcontrol. */
6093 if (!NILP (Fplist_member (contact, QCflowcontrol)))
6094 tem = Fplist_get (contact, QCflowcontrol);
6095 else
6096 tem = Fplist_get (p->childp, QCflowcontrol);
6097 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
6098 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6099 dcb.fOutxCtsFlow = FALSE;
6100 dcb.fOutxDsrFlow = FALSE;
6101 dcb.fDtrControl = DTR_CONTROL_DISABLE;
6102 dcb.fDsrSensitivity = FALSE;
6103 dcb.fTXContinueOnXoff = FALSE;
6104 dcb.fOutX = FALSE;
6105 dcb.fInX = FALSE;
6106 dcb.fRtsControl = RTS_CONTROL_DISABLE;
6107 dcb.XonChar = 17; /* Control-Q */
6108 dcb.XoffChar = 19; /* Control-S */
6109 if (NILP (tem))
6111 /* Already configured. */
6113 else if (EQ (tem, Qhw))
6115 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
6116 dcb.fOutxCtsFlow = TRUE;
6118 else if (EQ (tem, Qsw))
6120 dcb.fOutX = TRUE;
6121 dcb.fInX = TRUE;
6123 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
6125 /* Activate configuration. */
6126 if (!SetCommState (hnd, &dcb))
6127 error ("SetCommState() failed");
6129 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
6130 p->childp = childp2;
6133 /* end of w32.c */
6135 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
6136 (do not change this comment) */