* s/netbsd.h (AMPERSAND_FULL_NAME): Remove (defined in AH_BOTTOM).
[emacs.git] / src / w32.c
blob0f2d8b54e6b458fa90029392ced6a7730737c38a
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 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
23 #include <stddef.h> /* for offsetof */
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <float.h> /* for DBL_EPSILON */
27 #include <io.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <ctype.h>
31 #include <signal.h>
32 #include <sys/file.h>
33 #include <sys/time.h>
34 #include <sys/utime.h>
35 #include <mbstring.h> /* for _mbspbrk */
36 #include <math.h>
37 #include <setjmp.h>
39 /* must include CRT headers *before* config.h */
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
45 #undef access
46 #undef chdir
47 #undef chmod
48 #undef creat
49 #undef ctime
50 #undef fopen
51 #undef link
52 #undef mkdir
53 #undef mktemp
54 #undef open
55 #undef rename
56 #undef rmdir
57 #undef unlink
59 #undef close
60 #undef dup
61 #undef dup2
62 #undef pipe
63 #undef read
64 #undef write
66 #undef strerror
68 #include "lisp.h"
70 #include <pwd.h>
71 #include <grp.h>
73 #ifdef __GNUC__
74 #define _ANONYMOUS_UNION
75 #define _ANONYMOUS_STRUCT
76 #endif
77 #include <windows.h>
78 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
79 use a different name to avoid compilation problems. */
80 typedef struct _MEMORY_STATUS_EX {
81 DWORD dwLength;
82 DWORD dwMemoryLoad;
83 DWORDLONG ullTotalPhys;
84 DWORDLONG ullAvailPhys;
85 DWORDLONG ullTotalPageFile;
86 DWORDLONG ullAvailPageFile;
87 DWORDLONG ullTotalVirtual;
88 DWORDLONG ullAvailVirtual;
89 DWORDLONG ullAvailExtendedVirtual;
90 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
92 #include <lmcons.h>
93 #include <shlobj.h>
95 #include <tlhelp32.h>
96 #include <psapi.h>
97 /* This either is not in psapi.h or guarded by higher value of
98 _WIN32_WINNT than what we use. */
99 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
100 DWORD cb;
101 DWORD PageFaultCount;
102 DWORD PeakWorkingSetSize;
103 DWORD WorkingSetSize;
104 DWORD QuotaPeakPagedPoolUsage;
105 DWORD QuotaPagedPoolUsage;
106 DWORD QuotaPeakNonPagedPoolUsage;
107 DWORD QuotaNonPagedPoolUsage;
108 DWORD PagefileUsage;
109 DWORD PeakPagefileUsage;
110 DWORD PrivateUsage;
111 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
113 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
114 #include <sys/socket.h>
115 #undef socket
116 #undef bind
117 #undef connect
118 #undef htons
119 #undef ntohs
120 #undef inet_addr
121 #undef gethostname
122 #undef gethostbyname
123 #undef getservbyname
124 #undef getpeername
125 #undef shutdown
126 #undef setsockopt
127 #undef listen
128 #undef getsockname
129 #undef accept
130 #undef recvfrom
131 #undef sendto
132 #endif
134 #include "w32.h"
135 #include "ndir.h"
136 #include "w32heap.h"
137 #include "systime.h"
138 #include "dispextern.h" /* for xstrcasecmp */
139 #include "coding.h" /* for Vlocale_coding_system */
141 /* For serial_configure and serial_open. */
142 #include "process.h"
143 /* From process.c */
144 extern Lisp_Object QCport, QCspeed, QCprocess;
145 extern Lisp_Object QCbytesize, QCstopbits, QCparity, Qodd, Qeven;
146 extern Lisp_Object QCflowcontrol, Qhw, Qsw, QCsummary;
148 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
149 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
151 void globals_of_w32 ();
152 static DWORD get_rid (PSID);
154 extern Lisp_Object Vw32_downcase_file_names;
155 extern Lisp_Object Vw32_generate_fake_inodes;
156 extern Lisp_Object Vw32_get_true_file_attributes;
157 /* Defined in process.c for its own purpose. */
158 extern Lisp_Object Qlocal;
160 extern int w32_num_mouse_buttons;
163 /* Initialization states.
165 WARNING: If you add any more such variables for additional APIs,
166 you MUST add initialization for them to globals_of_w32
167 below. This is because these variables might get set
168 to non-NULL values during dumping, but the dumped Emacs
169 cannot reuse those values, because it could be run on a
170 different version of the OS, where API addresses are
171 different. */
172 static BOOL g_b_init_is_windows_9x;
173 static BOOL g_b_init_open_process_token;
174 static BOOL g_b_init_get_token_information;
175 static BOOL g_b_init_lookup_account_sid;
176 static BOOL g_b_init_get_sid_identifier_authority;
177 static BOOL g_b_init_get_sid_sub_authority;
178 static BOOL g_b_init_get_sid_sub_authority_count;
179 static BOOL g_b_init_get_file_security;
180 static BOOL g_b_init_get_security_descriptor_owner;
181 static BOOL g_b_init_get_security_descriptor_group;
182 static BOOL g_b_init_is_valid_sid;
183 static BOOL g_b_init_create_toolhelp32_snapshot;
184 static BOOL g_b_init_process32_first;
185 static BOOL g_b_init_process32_next;
186 static BOOL g_b_init_open_thread_token;
187 static BOOL g_b_init_impersonate_self;
188 static BOOL g_b_init_revert_to_self;
189 static BOOL g_b_init_get_process_memory_info;
190 static BOOL g_b_init_get_process_working_set_size;
191 static BOOL g_b_init_global_memory_status;
192 static BOOL g_b_init_global_memory_status_ex;
193 static BOOL g_b_init_get_length_sid;
194 static BOOL g_b_init_equal_sid;
195 static BOOL g_b_init_copy_sid;
196 static BOOL g_b_init_get_native_system_info;
197 static BOOL g_b_init_get_system_times;
200 BEGIN: Wrapper functions around OpenProcessToken
201 and other functions in advapi32.dll that are only
202 supported in Windows NT / 2k / XP
204 /* ** Function pointer typedefs ** */
205 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
206 HANDLE ProcessHandle,
207 DWORD DesiredAccess,
208 PHANDLE TokenHandle);
209 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
210 HANDLE TokenHandle,
211 TOKEN_INFORMATION_CLASS TokenInformationClass,
212 LPVOID TokenInformation,
213 DWORD TokenInformationLength,
214 PDWORD ReturnLength);
215 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
216 HANDLE process_handle,
217 LPFILETIME creation_time,
218 LPFILETIME exit_time,
219 LPFILETIME kernel_time,
220 LPFILETIME user_time);
222 GetProcessTimes_Proc get_process_times_fn = NULL;
224 #ifdef _UNICODE
225 const char * const LookupAccountSid_Name = "LookupAccountSidW";
226 const char * const GetFileSecurity_Name = "GetFileSecurityW";
227 #else
228 const char * const LookupAccountSid_Name = "LookupAccountSidA";
229 const char * const GetFileSecurity_Name = "GetFileSecurityA";
230 #endif
231 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
232 LPCTSTR lpSystemName,
233 PSID Sid,
234 LPTSTR Name,
235 LPDWORD cbName,
236 LPTSTR DomainName,
237 LPDWORD cbDomainName,
238 PSID_NAME_USE peUse);
239 typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) (
240 PSID pSid);
241 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
242 PSID pSid,
243 DWORD n);
244 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
245 PSID pSid);
246 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
247 LPCTSTR lpFileName,
248 SECURITY_INFORMATION RequestedInformation,
249 PSECURITY_DESCRIPTOR pSecurityDescriptor,
250 DWORD nLength,
251 LPDWORD lpnLengthNeeded);
252 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
253 PSECURITY_DESCRIPTOR pSecurityDescriptor,
254 PSID *pOwner,
255 LPBOOL lpbOwnerDefaulted);
256 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
257 PSECURITY_DESCRIPTOR pSecurityDescriptor,
258 PSID *pGroup,
259 LPBOOL lpbGroupDefaulted);
260 typedef BOOL (WINAPI * IsValidSid_Proc) (
261 PSID sid);
262 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
263 DWORD dwFlags,
264 DWORD th32ProcessID);
265 typedef BOOL (WINAPI * Process32First_Proc) (
266 HANDLE hSnapshot,
267 LPPROCESSENTRY32 lppe);
268 typedef BOOL (WINAPI * Process32Next_Proc) (
269 HANDLE hSnapshot,
270 LPPROCESSENTRY32 lppe);
271 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
272 HANDLE ThreadHandle,
273 DWORD DesiredAccess,
274 BOOL OpenAsSelf,
275 PHANDLE TokenHandle);
276 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
277 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
278 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
279 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
280 HANDLE Process,
281 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
282 DWORD cb);
283 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
284 HANDLE hProcess,
285 DWORD * lpMinimumWorkingSetSize,
286 DWORD * lpMaximumWorkingSetSize);
287 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
288 LPMEMORYSTATUS lpBuffer);
289 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
290 LPMEMORY_STATUS_EX lpBuffer);
291 typedef BOOL (WINAPI * CopySid_Proc) (
292 DWORD nDestinationSidLength,
293 PSID pDestinationSid,
294 PSID pSourceSid);
295 typedef BOOL (WINAPI * EqualSid_Proc) (
296 PSID pSid1,
297 PSID pSid2);
298 typedef DWORD (WINAPI * GetLengthSid_Proc) (
299 PSID pSid);
300 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
301 LPSYSTEM_INFO lpSystemInfo);
302 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
303 LPFILETIME lpIdleTime,
304 LPFILETIME lpKernelTime,
305 LPFILETIME lpUserTime);
309 /* ** A utility function ** */
310 static BOOL
311 is_windows_9x ()
313 static BOOL s_b_ret=0;
314 OSVERSIONINFO os_ver;
315 if (g_b_init_is_windows_9x == 0)
317 g_b_init_is_windows_9x = 1;
318 ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
319 os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
320 if (GetVersionEx (&os_ver))
322 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
325 return s_b_ret;
328 /* Get total user and system times for get-internal-run-time.
329 Returns a list of three integers if the times are provided by the OS
330 (NT derivatives), otherwise it returns the result of current-time. */
331 Lisp_Object
332 w32_get_internal_run_time ()
334 if (get_process_times_fn)
336 FILETIME create, exit, kernel, user;
337 HANDLE proc = GetCurrentProcess();
338 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
340 LARGE_INTEGER user_int, kernel_int, total;
341 int microseconds;
342 user_int.LowPart = user.dwLowDateTime;
343 user_int.HighPart = user.dwHighDateTime;
344 kernel_int.LowPart = kernel.dwLowDateTime;
345 kernel_int.HighPart = kernel.dwHighDateTime;
346 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
347 /* FILETIME is 100 nanosecond increments, Emacs only wants
348 microsecond resolution. */
349 total.QuadPart /= 10;
350 microseconds = total.QuadPart % 1000000;
351 total.QuadPart /= 1000000;
353 /* Sanity check to make sure we can represent the result. */
354 if (total.HighPart == 0)
356 int secs = total.LowPart;
358 return list3 (make_number ((secs >> 16) & 0xffff),
359 make_number (secs & 0xffff),
360 make_number (microseconds));
365 return Fcurrent_time ();
368 /* ** The wrapper functions ** */
370 BOOL WINAPI open_process_token (
371 HANDLE ProcessHandle,
372 DWORD DesiredAccess,
373 PHANDLE TokenHandle)
375 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
376 HMODULE hm_advapi32 = NULL;
377 if (is_windows_9x () == TRUE)
379 return FALSE;
381 if (g_b_init_open_process_token == 0)
383 g_b_init_open_process_token = 1;
384 hm_advapi32 = LoadLibrary ("Advapi32.dll");
385 s_pfn_Open_Process_Token =
386 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
388 if (s_pfn_Open_Process_Token == NULL)
390 return FALSE;
392 return (
393 s_pfn_Open_Process_Token (
394 ProcessHandle,
395 DesiredAccess,
396 TokenHandle)
400 BOOL WINAPI get_token_information (
401 HANDLE TokenHandle,
402 TOKEN_INFORMATION_CLASS TokenInformationClass,
403 LPVOID TokenInformation,
404 DWORD TokenInformationLength,
405 PDWORD ReturnLength)
407 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
408 HMODULE hm_advapi32 = NULL;
409 if (is_windows_9x () == TRUE)
411 return FALSE;
413 if (g_b_init_get_token_information == 0)
415 g_b_init_get_token_information = 1;
416 hm_advapi32 = LoadLibrary ("Advapi32.dll");
417 s_pfn_Get_Token_Information =
418 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
420 if (s_pfn_Get_Token_Information == NULL)
422 return FALSE;
424 return (
425 s_pfn_Get_Token_Information (
426 TokenHandle,
427 TokenInformationClass,
428 TokenInformation,
429 TokenInformationLength,
430 ReturnLength)
434 BOOL WINAPI lookup_account_sid (
435 LPCTSTR lpSystemName,
436 PSID Sid,
437 LPTSTR Name,
438 LPDWORD cbName,
439 LPTSTR DomainName,
440 LPDWORD cbDomainName,
441 PSID_NAME_USE peUse)
443 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
444 HMODULE hm_advapi32 = NULL;
445 if (is_windows_9x () == TRUE)
447 return FALSE;
449 if (g_b_init_lookup_account_sid == 0)
451 g_b_init_lookup_account_sid = 1;
452 hm_advapi32 = LoadLibrary ("Advapi32.dll");
453 s_pfn_Lookup_Account_Sid =
454 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
456 if (s_pfn_Lookup_Account_Sid == NULL)
458 return FALSE;
460 return (
461 s_pfn_Lookup_Account_Sid (
462 lpSystemName,
463 Sid,
464 Name,
465 cbName,
466 DomainName,
467 cbDomainName,
468 peUse)
472 PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority (
473 PSID pSid)
475 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority = NULL;
476 HMODULE hm_advapi32 = NULL;
477 if (is_windows_9x () == TRUE)
479 return NULL;
481 if (g_b_init_get_sid_identifier_authority == 0)
483 g_b_init_get_sid_identifier_authority = 1;
484 hm_advapi32 = LoadLibrary ("Advapi32.dll");
485 s_pfn_Get_Sid_Identifier_Authority =
486 (GetSidIdentifierAuthority_Proc) GetProcAddress (
487 hm_advapi32, "GetSidIdentifierAuthority");
489 if (s_pfn_Get_Sid_Identifier_Authority == NULL)
491 return NULL;
493 return (s_pfn_Get_Sid_Identifier_Authority (pSid));
496 PDWORD WINAPI get_sid_sub_authority (
497 PSID pSid,
498 DWORD n)
500 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
501 static DWORD zero = 0U;
502 HMODULE hm_advapi32 = NULL;
503 if (is_windows_9x () == TRUE)
505 return &zero;
507 if (g_b_init_get_sid_sub_authority == 0)
509 g_b_init_get_sid_sub_authority = 1;
510 hm_advapi32 = LoadLibrary ("Advapi32.dll");
511 s_pfn_Get_Sid_Sub_Authority =
512 (GetSidSubAuthority_Proc) GetProcAddress (
513 hm_advapi32, "GetSidSubAuthority");
515 if (s_pfn_Get_Sid_Sub_Authority == NULL)
517 return &zero;
519 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
522 PUCHAR WINAPI get_sid_sub_authority_count (
523 PSID pSid)
525 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
526 static UCHAR zero = 0U;
527 HMODULE hm_advapi32 = NULL;
528 if (is_windows_9x () == TRUE)
530 return &zero;
532 if (g_b_init_get_sid_sub_authority_count == 0)
534 g_b_init_get_sid_sub_authority_count = 1;
535 hm_advapi32 = LoadLibrary ("Advapi32.dll");
536 s_pfn_Get_Sid_Sub_Authority_Count =
537 (GetSidSubAuthorityCount_Proc) GetProcAddress (
538 hm_advapi32, "GetSidSubAuthorityCount");
540 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
542 return &zero;
544 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
547 BOOL WINAPI get_file_security (
548 LPCTSTR lpFileName,
549 SECURITY_INFORMATION RequestedInformation,
550 PSECURITY_DESCRIPTOR pSecurityDescriptor,
551 DWORD nLength,
552 LPDWORD lpnLengthNeeded)
554 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
555 HMODULE hm_advapi32 = NULL;
556 if (is_windows_9x () == TRUE)
558 return FALSE;
560 if (g_b_init_get_file_security == 0)
562 g_b_init_get_file_security = 1;
563 hm_advapi32 = LoadLibrary ("Advapi32.dll");
564 s_pfn_Get_File_Security =
565 (GetFileSecurity_Proc) GetProcAddress (
566 hm_advapi32, GetFileSecurity_Name);
568 if (s_pfn_Get_File_Security == NULL)
570 return FALSE;
572 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
573 pSecurityDescriptor, nLength,
574 lpnLengthNeeded));
577 BOOL WINAPI get_security_descriptor_owner (
578 PSECURITY_DESCRIPTOR pSecurityDescriptor,
579 PSID *pOwner,
580 LPBOOL lpbOwnerDefaulted)
582 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
583 HMODULE hm_advapi32 = NULL;
584 if (is_windows_9x () == TRUE)
586 return FALSE;
588 if (g_b_init_get_security_descriptor_owner == 0)
590 g_b_init_get_security_descriptor_owner = 1;
591 hm_advapi32 = LoadLibrary ("Advapi32.dll");
592 s_pfn_Get_Security_Descriptor_Owner =
593 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
594 hm_advapi32, "GetSecurityDescriptorOwner");
596 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
598 return FALSE;
600 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
601 lpbOwnerDefaulted));
604 BOOL WINAPI get_security_descriptor_group (
605 PSECURITY_DESCRIPTOR pSecurityDescriptor,
606 PSID *pGroup,
607 LPBOOL lpbGroupDefaulted)
609 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
610 HMODULE hm_advapi32 = NULL;
611 if (is_windows_9x () == TRUE)
613 return FALSE;
615 if (g_b_init_get_security_descriptor_group == 0)
617 g_b_init_get_security_descriptor_group = 1;
618 hm_advapi32 = LoadLibrary ("Advapi32.dll");
619 s_pfn_Get_Security_Descriptor_Group =
620 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
621 hm_advapi32, "GetSecurityDescriptorGroup");
623 if (s_pfn_Get_Security_Descriptor_Group == NULL)
625 return FALSE;
627 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
628 lpbGroupDefaulted));
631 BOOL WINAPI is_valid_sid (
632 PSID sid)
634 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
635 HMODULE hm_advapi32 = NULL;
636 if (is_windows_9x () == TRUE)
638 return FALSE;
640 if (g_b_init_is_valid_sid == 0)
642 g_b_init_is_valid_sid = 1;
643 hm_advapi32 = LoadLibrary ("Advapi32.dll");
644 s_pfn_Is_Valid_Sid =
645 (IsValidSid_Proc) GetProcAddress (
646 hm_advapi32, "IsValidSid");
648 if (s_pfn_Is_Valid_Sid == NULL)
650 return FALSE;
652 return (s_pfn_Is_Valid_Sid (sid));
655 BOOL WINAPI equal_sid (
656 PSID sid1,
657 PSID sid2)
659 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
660 HMODULE hm_advapi32 = NULL;
661 if (is_windows_9x () == TRUE)
663 return FALSE;
665 if (g_b_init_equal_sid == 0)
667 g_b_init_equal_sid = 1;
668 hm_advapi32 = LoadLibrary ("Advapi32.dll");
669 s_pfn_Equal_Sid =
670 (EqualSid_Proc) GetProcAddress (
671 hm_advapi32, "EqualSid");
673 if (s_pfn_Equal_Sid == NULL)
675 return FALSE;
677 return (s_pfn_Equal_Sid (sid1, sid2));
680 DWORD WINAPI get_length_sid (
681 PSID sid)
683 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
684 HMODULE hm_advapi32 = NULL;
685 if (is_windows_9x () == TRUE)
687 return 0;
689 if (g_b_init_get_length_sid == 0)
691 g_b_init_get_length_sid = 1;
692 hm_advapi32 = LoadLibrary ("Advapi32.dll");
693 s_pfn_Get_Length_Sid =
694 (GetLengthSid_Proc) GetProcAddress (
695 hm_advapi32, "GetLengthSid");
697 if (s_pfn_Get_Length_Sid == NULL)
699 return 0;
701 return (s_pfn_Get_Length_Sid (sid));
704 BOOL WINAPI copy_sid (
705 DWORD destlen,
706 PSID dest,
707 PSID src)
709 static CopySid_Proc s_pfn_Copy_Sid = NULL;
710 HMODULE hm_advapi32 = NULL;
711 if (is_windows_9x () == TRUE)
713 return FALSE;
715 if (g_b_init_copy_sid == 0)
717 g_b_init_copy_sid = 1;
718 hm_advapi32 = LoadLibrary ("Advapi32.dll");
719 s_pfn_Copy_Sid =
720 (CopySid_Proc) GetProcAddress (
721 hm_advapi32, "CopySid");
723 if (s_pfn_Copy_Sid == NULL)
725 return FALSE;
727 return (s_pfn_Copy_Sid (destlen, dest, src));
731 END: Wrapper functions around OpenProcessToken
732 and other functions in advapi32.dll that are only
733 supported in Windows NT / 2k / XP
736 void WINAPI get_native_system_info (
737 LPSYSTEM_INFO lpSystemInfo)
739 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
740 if (is_windows_9x () != TRUE)
742 if (g_b_init_get_native_system_info == 0)
744 g_b_init_get_native_system_info = 1;
745 s_pfn_Get_Native_System_Info =
746 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
747 "GetNativeSystemInfo");
749 if (s_pfn_Get_Native_System_Info != NULL)
750 s_pfn_Get_Native_System_Info (lpSystemInfo);
752 else
753 lpSystemInfo->dwNumberOfProcessors = -1;
756 BOOL WINAPI get_system_times(
757 LPFILETIME lpIdleTime,
758 LPFILETIME lpKernelTime,
759 LPFILETIME lpUserTime)
761 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
762 if (is_windows_9x () == TRUE)
764 return FALSE;
766 if (g_b_init_get_system_times == 0)
768 g_b_init_get_system_times = 1;
769 s_pfn_Get_System_times =
770 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
771 "GetSystemTimes");
773 if (s_pfn_Get_System_times == NULL)
774 return FALSE;
775 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
778 /* Equivalent of strerror for W32 error codes. */
779 char *
780 w32_strerror (int error_no)
782 static char buf[500];
784 if (error_no == 0)
785 error_no = GetLastError ();
787 buf[0] = '\0';
788 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
789 error_no,
790 0, /* choose most suitable language */
791 buf, sizeof (buf), NULL))
792 sprintf (buf, "w32 error %u", error_no);
793 return buf;
796 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
797 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
799 This is called from alloc.c:valid_pointer_p. */
801 w32_valid_pointer_p (void *p, int size)
803 SIZE_T done;
804 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
806 if (h)
808 unsigned char *buf = alloca (size);
809 int retval = ReadProcessMemory (h, p, buf, size, &done);
811 CloseHandle (h);
812 return retval;
814 else
815 return -1;
818 static char startup_dir[MAXPATHLEN];
820 /* Get the current working directory. */
821 char *
822 getwd (char *dir)
824 #if 0
825 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
826 return dir;
827 return NULL;
828 #else
829 /* Emacs doesn't actually change directory itself, and we want to
830 force our real wd to be where emacs.exe is to avoid unnecessary
831 conflicts when trying to rename or delete directories. */
832 strcpy (dir, startup_dir);
833 return dir;
834 #endif
837 #ifndef HAVE_SOCKETS
838 /* Emulate gethostname. */
840 gethostname (char *buffer, int size)
842 /* NT only allows small host names, so the buffer is
843 certainly large enough. */
844 return !GetComputerName (buffer, &size);
846 #endif /* HAVE_SOCKETS */
848 /* Emulate getloadavg. */
850 struct load_sample {
851 time_t sample_time;
852 ULONGLONG idle;
853 ULONGLONG kernel;
854 ULONGLONG user;
857 /* Number of processors on this machine. */
858 static unsigned num_of_processors;
860 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
861 static struct load_sample samples[16*60];
862 static int first_idx = -1, last_idx = -1;
863 static int max_idx = sizeof (samples) / sizeof (samples[0]);
865 static int
866 buf_next (int from)
868 int next_idx = from + 1;
870 if (next_idx >= max_idx)
871 next_idx = 0;
873 return next_idx;
876 static int
877 buf_prev (int from)
879 int prev_idx = from - 1;
881 if (prev_idx < 0)
882 prev_idx = max_idx - 1;
884 return prev_idx;
887 static void
888 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
890 SYSTEM_INFO sysinfo;
891 FILETIME ft_idle, ft_user, ft_kernel;
893 /* Initialize the number of processors on this machine. */
894 if (num_of_processors <= 0)
896 get_native_system_info (&sysinfo);
897 num_of_processors = sysinfo.dwNumberOfProcessors;
898 if (num_of_processors <= 0)
900 GetSystemInfo (&sysinfo);
901 num_of_processors = sysinfo.dwNumberOfProcessors;
903 if (num_of_processors <= 0)
904 num_of_processors = 1;
907 /* TODO: Take into account threads that are ready to run, by
908 sampling the "\System\Processor Queue Length" performance
909 counter. The code below accounts only for threads that are
910 actually running. */
912 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
914 ULARGE_INTEGER uidle, ukernel, uuser;
916 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
917 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
918 memcpy (&uuser, &ft_user, sizeof (ft_user));
919 *idle = uidle.QuadPart;
920 *kernel = ukernel.QuadPart;
921 *user = uuser.QuadPart;
923 else
925 *idle = 0;
926 *kernel = 0;
927 *user = 0;
931 /* Produce the load average for a given time interval, using the
932 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
933 1-minute, 5-minute, or 15-minute average, respectively. */
934 static double
935 getavg (int which)
937 double retval = -1.0;
938 double tdiff;
939 int idx;
940 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
941 time_t now = samples[last_idx].sample_time;
943 if (first_idx != last_idx)
945 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
947 tdiff = difftime (now, samples[idx].sample_time);
948 if (tdiff >= span - 2*DBL_EPSILON*now)
950 long double sys =
951 samples[last_idx].kernel + samples[last_idx].user
952 - (samples[idx].kernel + samples[idx].user);
953 long double idl = samples[last_idx].idle - samples[idx].idle;
955 retval = (1.0 - idl / sys) * num_of_processors;
956 break;
958 if (idx == first_idx)
959 break;
963 return retval;
967 getloadavg (double loadavg[], int nelem)
969 int elem;
970 ULONGLONG idle, kernel, user;
971 time_t now = time (NULL);
973 /* Store another sample. We ignore samples that are less than 1 sec
974 apart. */
975 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
977 sample_system_load (&idle, &kernel, &user);
978 last_idx = buf_next (last_idx);
979 samples[last_idx].sample_time = now;
980 samples[last_idx].idle = idle;
981 samples[last_idx].kernel = kernel;
982 samples[last_idx].user = user;
983 /* If the buffer has more that 15 min worth of samples, discard
984 the old ones. */
985 if (first_idx == -1)
986 first_idx = last_idx;
987 while (first_idx != last_idx
988 && (difftime (now, samples[first_idx].sample_time)
989 >= 15.0*60 + 2*DBL_EPSILON*now))
990 first_idx = buf_next (first_idx);
993 for (elem = 0; elem < nelem; elem++)
995 double avg = getavg (elem);
997 if (avg < 0)
998 break;
999 loadavg[elem] = avg;
1002 return elem;
1005 /* Emulate getpwuid, getpwnam and others. */
1007 #define PASSWD_FIELD_SIZE 256
1009 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1010 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1011 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1012 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
1013 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
1015 static struct passwd dflt_passwd =
1017 dflt_passwd_name,
1018 dflt_passwd_passwd,
1022 dflt_passwd_gecos,
1023 dflt_passwd_dir,
1024 dflt_passwd_shell,
1027 static char dflt_group_name[GNLEN+1];
1029 static struct group dflt_group =
1031 /* When group information is not available, we return this as the
1032 group for all files. */
1033 dflt_group_name,
1037 unsigned
1038 getuid ()
1040 return dflt_passwd.pw_uid;
1043 unsigned
1044 geteuid ()
1046 /* I could imagine arguing for checking to see whether the user is
1047 in the Administrators group and returning a UID of 0 for that
1048 case, but I don't know how wise that would be in the long run. */
1049 return getuid ();
1052 unsigned
1053 getgid ()
1055 return dflt_passwd.pw_gid;
1058 unsigned
1059 getegid ()
1061 return getgid ();
1064 struct passwd *
1065 getpwuid (unsigned uid)
1067 if (uid == dflt_passwd.pw_uid)
1068 return &dflt_passwd;
1069 return NULL;
1072 struct group *
1073 getgrgid (gid_t gid)
1075 return &dflt_group;
1078 struct passwd *
1079 getpwnam (char *name)
1081 struct passwd *pw;
1083 pw = getpwuid (getuid ());
1084 if (!pw)
1085 return pw;
1087 if (xstrcasecmp (name, pw->pw_name))
1088 return NULL;
1090 return pw;
1093 void
1094 init_user_info ()
1096 /* Find the user's real name by opening the process token and
1097 looking up the name associated with the user-sid in that token.
1099 Use the relative portion of the identifier authority value from
1100 the user-sid as the user id value (same for group id using the
1101 primary group sid from the process token). */
1103 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1104 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1105 DWORD glength = sizeof (gname);
1106 HANDLE token = NULL;
1107 SID_NAME_USE user_type;
1108 unsigned char *buf = NULL;
1109 DWORD blen = 0;
1110 TOKEN_USER user_token;
1111 TOKEN_PRIMARY_GROUP group_token;
1112 BOOL result;
1114 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1115 if (result)
1117 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1118 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1120 buf = xmalloc (blen);
1121 result = get_token_information (token, TokenUser,
1122 (LPVOID)buf, blen, &needed);
1123 if (result)
1125 memcpy (&user_token, buf, sizeof (user_token));
1126 result = lookup_account_sid (NULL, user_token.User.Sid,
1127 uname, &ulength,
1128 domain, &dlength, &user_type);
1131 else
1132 result = FALSE;
1134 if (result)
1136 strcpy (dflt_passwd.pw_name, uname);
1137 /* Determine a reasonable uid value. */
1138 if (xstrcasecmp ("administrator", uname) == 0)
1140 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1141 dflt_passwd.pw_gid = 513; /* well-known None gid */
1143 else
1145 /* Use the last sub-authority value of the RID, the relative
1146 portion of the SID, as user/group ID. */
1147 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1149 /* Get group id and name. */
1150 result = get_token_information (token, TokenPrimaryGroup,
1151 (LPVOID)buf, blen, &needed);
1152 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1154 buf = xrealloc (buf, blen = needed);
1155 result = get_token_information (token, TokenPrimaryGroup,
1156 (LPVOID)buf, blen, &needed);
1158 if (result)
1160 memcpy (&group_token, buf, sizeof (group_token));
1161 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1162 dlength = sizeof (domain);
1163 /* If we can get at the real Primary Group name, use that.
1164 Otherwise, the default group name was already set to
1165 "None" in globals_of_w32. */
1166 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1167 gname, &glength, NULL, &dlength,
1168 &user_type))
1169 strcpy (dflt_group_name, gname);
1171 else
1172 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1175 /* If security calls are not supported (presumably because we
1176 are running under Windows 9X), fallback to this: */
1177 else if (GetUserName (uname, &ulength))
1179 strcpy (dflt_passwd.pw_name, uname);
1180 if (xstrcasecmp ("administrator", uname) == 0)
1181 dflt_passwd.pw_uid = 0;
1182 else
1183 dflt_passwd.pw_uid = 123;
1184 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1186 else
1188 strcpy (dflt_passwd.pw_name, "unknown");
1189 dflt_passwd.pw_uid = 123;
1190 dflt_passwd.pw_gid = 123;
1192 dflt_group.gr_gid = dflt_passwd.pw_gid;
1194 /* Ensure HOME and SHELL are defined. */
1195 if (getenv ("HOME") == NULL)
1196 abort ();
1197 if (getenv ("SHELL") == NULL)
1198 abort ();
1200 /* Set dir and shell from environment variables. */
1201 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1202 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1204 xfree (buf);
1205 if (token)
1206 CloseHandle (token);
1210 random ()
1212 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1213 return ((rand () << 15) | rand ());
1216 void
1217 srandom (int seed)
1219 srand (seed);
1223 /* Normalize filename by converting all path separators to
1224 the specified separator. Also conditionally convert upper
1225 case path name components to lower case. */
1227 static void
1228 normalize_filename (fp, path_sep)
1229 register char *fp;
1230 char path_sep;
1232 char sep;
1233 char *elem;
1235 /* Always lower-case drive letters a-z, even if the filesystem
1236 preserves case in filenames.
1237 This is so filenames can be compared by string comparison
1238 functions that are case-sensitive. Even case-preserving filesystems
1239 do not distinguish case in drive letters. */
1240 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
1242 *fp += 'a' - 'A';
1243 fp += 2;
1246 if (NILP (Vw32_downcase_file_names))
1248 while (*fp)
1250 if (*fp == '/' || *fp == '\\')
1251 *fp = path_sep;
1252 fp++;
1254 return;
1257 sep = path_sep; /* convert to this path separator */
1258 elem = fp; /* start of current path element */
1260 do {
1261 if (*fp >= 'a' && *fp <= 'z')
1262 elem = 0; /* don't convert this element */
1264 if (*fp == 0 || *fp == ':')
1266 sep = *fp; /* restore current separator (or 0) */
1267 *fp = '/'; /* after conversion of this element */
1270 if (*fp == '/' || *fp == '\\')
1272 if (elem && elem != fp)
1274 *fp = 0; /* temporary end of string */
1275 _strlwr (elem); /* while we convert to lower case */
1277 *fp = sep; /* convert (or restore) path separator */
1278 elem = fp + 1; /* next element starts after separator */
1279 sep = path_sep;
1281 } while (*fp++);
1284 /* Destructively turn backslashes into slashes. */
1285 void
1286 dostounix_filename (p)
1287 register char *p;
1289 normalize_filename (p, '/');
1292 /* Destructively turn slashes into backslashes. */
1293 void
1294 unixtodos_filename (p)
1295 register char *p;
1297 normalize_filename (p, '\\');
1300 /* Remove all CR's that are followed by a LF.
1301 (From msdos.c...probably should figure out a way to share it,
1302 although this code isn't going to ever change.) */
1304 crlf_to_lf (n, buf)
1305 register int n;
1306 register unsigned char *buf;
1308 unsigned char *np = buf;
1309 unsigned char *startp = buf;
1310 unsigned char *endp = buf + n;
1312 if (n == 0)
1313 return n;
1314 while (buf < endp - 1)
1316 if (*buf == 0x0d)
1318 if (*(++buf) != 0x0a)
1319 *np++ = 0x0d;
1321 else
1322 *np++ = *buf++;
1324 if (buf < endp)
1325 *np++ = *buf++;
1326 return np - startp;
1329 /* Parse the root part of file name, if present. Return length and
1330 optionally store pointer to char after root. */
1331 static int
1332 parse_root (char * name, char ** pPath)
1334 char * start = name;
1336 if (name == NULL)
1337 return 0;
1339 /* find the root name of the volume if given */
1340 if (isalpha (name[0]) && name[1] == ':')
1342 /* skip past drive specifier */
1343 name += 2;
1344 if (IS_DIRECTORY_SEP (name[0]))
1345 name++;
1347 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1349 int slashes = 2;
1350 name += 2;
1353 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1354 break;
1355 name++;
1357 while ( *name );
1358 if (IS_DIRECTORY_SEP (name[0]))
1359 name++;
1362 if (pPath)
1363 *pPath = name;
1365 return name - start;
1368 /* Get long base name for name; name is assumed to be absolute. */
1369 static int
1370 get_long_basename (char * name, char * buf, int size)
1372 WIN32_FIND_DATA find_data;
1373 HANDLE dir_handle;
1374 int len = 0;
1376 /* must be valid filename, no wild cards or other invalid characters */
1377 if (_mbspbrk (name, "*?|<>\""))
1378 return 0;
1380 dir_handle = FindFirstFile (name, &find_data);
1381 if (dir_handle != INVALID_HANDLE_VALUE)
1383 if ((len = strlen (find_data.cFileName)) < size)
1384 memcpy (buf, find_data.cFileName, len + 1);
1385 else
1386 len = 0;
1387 FindClose (dir_handle);
1389 return len;
1392 /* Get long name for file, if possible (assumed to be absolute). */
1393 BOOL
1394 w32_get_long_filename (char * name, char * buf, int size)
1396 char * o = buf;
1397 char * p;
1398 char * q;
1399 char full[ MAX_PATH ];
1400 int len;
1402 len = strlen (name);
1403 if (len >= MAX_PATH)
1404 return FALSE;
1406 /* Use local copy for destructive modification. */
1407 memcpy (full, name, len+1);
1408 unixtodos_filename (full);
1410 /* Copy root part verbatim. */
1411 len = parse_root (full, &p);
1412 memcpy (o, full, len);
1413 o += len;
1414 *o = '\0';
1415 size -= len;
1417 while (p != NULL && *p)
1419 q = p;
1420 p = strchr (q, '\\');
1421 if (p) *p = '\0';
1422 len = get_long_basename (full, o, size);
1423 if (len > 0)
1425 o += len;
1426 size -= len;
1427 if (p != NULL)
1429 *p++ = '\\';
1430 if (size < 2)
1431 return FALSE;
1432 *o++ = '\\';
1433 size--;
1434 *o = '\0';
1437 else
1438 return FALSE;
1441 return TRUE;
1445 is_unc_volume (const char *filename)
1447 const char *ptr = filename;
1449 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1450 return 0;
1452 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1453 return 0;
1455 return 1;
1458 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1461 sigsetmask (int signal_mask)
1463 return 0;
1467 sigmask (int sig)
1469 return 0;
1473 sigblock (int sig)
1475 return 0;
1479 sigunblock (int sig)
1481 return 0;
1485 sigemptyset (sigset_t *set)
1487 return 0;
1491 sigaddset (sigset_t *set, int signo)
1493 return 0;
1497 sigfillset (sigset_t *set)
1499 return 0;
1503 sigprocmask (int how, const sigset_t *set, sigset_t *oset)
1505 return 0;
1509 setpgrp (int pid, int gid)
1511 return 0;
1515 alarm (int seconds)
1517 return 0;
1520 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1522 LPBYTE
1523 w32_get_resource (key, lpdwtype)
1524 char *key;
1525 LPDWORD lpdwtype;
1527 LPBYTE lpvalue;
1528 HKEY hrootkey = NULL;
1529 DWORD cbData;
1531 /* Check both the current user and the local machine to see if
1532 we have any resources. */
1534 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1536 lpvalue = NULL;
1538 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1539 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1540 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1542 RegCloseKey (hrootkey);
1543 return (lpvalue);
1546 xfree (lpvalue);
1548 RegCloseKey (hrootkey);
1551 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1553 lpvalue = NULL;
1555 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1556 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1557 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1559 RegCloseKey (hrootkey);
1560 return (lpvalue);
1563 xfree (lpvalue);
1565 RegCloseKey (hrootkey);
1568 return (NULL);
1571 char *get_emacs_configuration (void);
1572 extern Lisp_Object Vsystem_configuration;
1574 void
1575 init_environment (char ** argv)
1577 static const char * const tempdirs[] = {
1578 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1581 int i;
1583 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1585 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1586 temporary files and assume "/tmp" if $TMPDIR is unset, which
1587 will break on DOS/Windows. Refuse to work if we cannot find
1588 a directory, not even "c:/", usable for that purpose. */
1589 for (i = 0; i < imax ; i++)
1591 const char *tmp = tempdirs[i];
1593 if (*tmp == '$')
1594 tmp = getenv (tmp + 1);
1595 /* Note that `access' can lie to us if the directory resides on a
1596 read-only filesystem, like CD-ROM or a write-protected floppy.
1597 The only way to be really sure is to actually create a file and
1598 see if it succeeds. But I think that's too much to ask. */
1599 if (tmp && _access (tmp, D_OK) == 0)
1601 char * var = alloca (strlen (tmp) + 8);
1602 sprintf (var, "TMPDIR=%s", tmp);
1603 _putenv (strdup (var));
1604 break;
1607 if (i >= imax)
1608 cmd_error_internal
1609 (Fcons (Qerror,
1610 Fcons (build_string ("no usable temporary directories found!!"),
1611 Qnil)),
1612 "While setting TMPDIR: ");
1614 /* Check for environment variables and use registry settings if they
1615 don't exist. Fallback on default values where applicable. */
1617 int i;
1618 LPBYTE lpval;
1619 DWORD dwType;
1620 char locale_name[32];
1621 struct stat ignored;
1622 char default_home[MAX_PATH];
1624 static const struct env_entry
1626 char * name;
1627 char * def_value;
1628 } dflt_envvars[] =
1630 {"HOME", "C:/"},
1631 {"PRELOAD_WINSOCK", NULL},
1632 {"emacs_dir", "C:/emacs"},
1633 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1634 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1635 {"EMACSDATA", "%emacs_dir%/etc"},
1636 {"EMACSPATH", "%emacs_dir%/bin"},
1637 /* We no longer set INFOPATH because Info-default-directory-list
1638 is then ignored. */
1639 /* {"INFOPATH", "%emacs_dir%/info"}, */
1640 {"EMACSDOC", "%emacs_dir%/etc"},
1641 {"TERM", "cmd"},
1642 {"LANG", NULL},
1645 #define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1647 /* We need to copy dflt_envvars[] and work on the copy because we
1648 don't want the dumped Emacs to inherit the values of
1649 environment variables we saw during dumping (which could be on
1650 a different system). The defaults above must be left intact. */
1651 struct env_entry env_vars[N_ENV_VARS];
1653 for (i = 0; i < N_ENV_VARS; i++)
1654 env_vars[i] = dflt_envvars[i];
1656 /* For backwards compatibility, check if a .emacs file exists in C:/
1657 If not, then we can try to default to the appdata directory under the
1658 user's profile, which is more likely to be writable. */
1659 if (stat ("C:/.emacs", &ignored) < 0)
1661 HRESULT profile_result;
1662 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1663 of Windows 95 and NT4 that have not been updated to include
1664 MSIE 5. */
1665 ShGetFolderPath_fn get_folder_path;
1666 get_folder_path = (ShGetFolderPath_fn)
1667 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1669 if (get_folder_path != NULL)
1671 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1672 0, default_home);
1674 /* If we can't get the appdata dir, revert to old behavior. */
1675 if (profile_result == S_OK)
1676 env_vars[0].def_value = default_home;
1680 /* Get default locale info and use it for LANG. */
1681 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1682 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1683 locale_name, sizeof (locale_name)))
1685 for (i = 0; i < N_ENV_VARS; i++)
1687 if (strcmp (env_vars[i].name, "LANG") == 0)
1689 env_vars[i].def_value = locale_name;
1690 break;
1695 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1697 /* Treat emacs_dir specially: set it unconditionally based on our
1698 location, if it appears that we are running from the bin subdir
1699 of a standard installation. */
1701 char *p;
1702 char modname[MAX_PATH];
1704 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1705 abort ();
1706 if ((p = strrchr (modname, '\\')) == NULL)
1707 abort ();
1708 *p = 0;
1710 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1712 char buf[SET_ENV_BUF_SIZE];
1714 *p = 0;
1715 for (p = modname; *p; p++)
1716 if (*p == '\\') *p = '/';
1718 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
1719 _putenv (strdup (buf));
1721 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1723 /* FIXME: should use substring of get_emacs_configuration ().
1724 But I don't think the Windows build supports alpha, mips etc
1725 anymore, so have taken the easy option for now. */
1726 else if (p && xstrcasecmp (p, "\\i386") == 0)
1728 *p = 0;
1729 p = strrchr (modname, '\\');
1730 if (p != NULL)
1732 *p = 0;
1733 p = strrchr (modname, '\\');
1734 if (p && xstrcasecmp (p, "\\src") == 0)
1736 char buf[SET_ENV_BUF_SIZE];
1738 *p = 0;
1739 for (p = modname; *p; p++)
1740 if (*p == '\\') *p = '/';
1742 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
1743 _putenv (strdup (buf));
1749 for (i = 0; i < N_ENV_VARS; i++)
1751 if (!getenv (env_vars[i].name))
1753 int dont_free = 0;
1755 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1756 /* Also ignore empty environment variables. */
1757 || *lpval == 0)
1759 xfree (lpval);
1760 lpval = env_vars[i].def_value;
1761 dwType = REG_EXPAND_SZ;
1762 dont_free = 1;
1765 if (lpval)
1767 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1769 if (dwType == REG_EXPAND_SZ)
1770 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
1771 else if (dwType == REG_SZ)
1772 strcpy (buf1, lpval);
1773 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1775 _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name,
1776 buf1);
1777 _putenv (strdup (buf2));
1780 if (!dont_free)
1781 xfree (lpval);
1787 /* Rebuild system configuration to reflect invoking system. */
1788 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1790 /* Another special case: on NT, the PATH variable is actually named
1791 "Path" although cmd.exe (perhaps NT itself) arranges for
1792 environment variable lookup and setting to be case insensitive.
1793 However, Emacs assumes a fully case sensitive environment, so we
1794 need to change "Path" to "PATH" to match the expectations of
1795 various elisp packages. We do this by the sneaky method of
1796 modifying the string in the C runtime environ entry.
1798 The same applies to COMSPEC. */
1800 char ** envp;
1802 for (envp = environ; *envp; envp++)
1803 if (_strnicmp (*envp, "PATH=", 5) == 0)
1804 memcpy (*envp, "PATH=", 5);
1805 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1806 memcpy (*envp, "COMSPEC=", 8);
1809 /* Remember the initial working directory for getwd, then make the
1810 real wd be the location of emacs.exe to avoid conflicts when
1811 renaming or deleting directories. (We also don't call chdir when
1812 running subprocesses for the same reason.) */
1813 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1814 abort ();
1817 char *p;
1818 static char modname[MAX_PATH];
1820 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1821 abort ();
1822 if ((p = strrchr (modname, '\\')) == NULL)
1823 abort ();
1824 *p = 0;
1826 SetCurrentDirectory (modname);
1828 /* Ensure argv[0] has the full path to Emacs. */
1829 *p = '\\';
1830 argv[0] = modname;
1833 /* Determine if there is a middle mouse button, to allow parse_button
1834 to decide whether right mouse events should be mouse-2 or
1835 mouse-3. */
1836 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1838 init_user_info ();
1841 char *
1842 emacs_root_dir (void)
1844 static char root_dir[FILENAME_MAX];
1845 const char *p;
1847 p = getenv ("emacs_dir");
1848 if (p == NULL)
1849 abort ();
1850 strcpy (root_dir, p);
1851 root_dir[parse_root (root_dir, NULL)] = '\0';
1852 dostounix_filename (root_dir);
1853 return root_dir;
1856 /* We don't have scripts to automatically determine the system configuration
1857 for Emacs before it's compiled, and we don't want to have to make the
1858 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1859 routine. */
1861 char *
1862 get_emacs_configuration (void)
1864 char *arch, *oem, *os;
1865 int build_num;
1866 static char configuration_buffer[32];
1868 /* Determine the processor type. */
1869 switch (get_processor_type ())
1872 #ifdef PROCESSOR_INTEL_386
1873 case PROCESSOR_INTEL_386:
1874 case PROCESSOR_INTEL_486:
1875 case PROCESSOR_INTEL_PENTIUM:
1876 arch = "i386";
1877 break;
1878 #endif
1880 #ifdef PROCESSOR_MIPS_R2000
1881 case PROCESSOR_MIPS_R2000:
1882 case PROCESSOR_MIPS_R3000:
1883 case PROCESSOR_MIPS_R4000:
1884 arch = "mips";
1885 break;
1886 #endif
1888 #ifdef PROCESSOR_ALPHA_21064
1889 case PROCESSOR_ALPHA_21064:
1890 arch = "alpha";
1891 break;
1892 #endif
1894 default:
1895 arch = "unknown";
1896 break;
1899 /* Use the OEM field to reflect the compiler/library combination. */
1900 #ifdef _MSC_VER
1901 #define COMPILER_NAME "msvc"
1902 #else
1903 #ifdef __GNUC__
1904 #define COMPILER_NAME "mingw"
1905 #else
1906 #define COMPILER_NAME "unknown"
1907 #endif
1908 #endif
1909 oem = COMPILER_NAME;
1911 switch (osinfo_cache.dwPlatformId) {
1912 case VER_PLATFORM_WIN32_NT:
1913 os = "nt";
1914 build_num = osinfo_cache.dwBuildNumber;
1915 break;
1916 case VER_PLATFORM_WIN32_WINDOWS:
1917 if (osinfo_cache.dwMinorVersion == 0) {
1918 os = "windows95";
1919 } else {
1920 os = "windows98";
1922 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1923 break;
1924 case VER_PLATFORM_WIN32s:
1925 /* Not supported, should not happen. */
1926 os = "windows32s";
1927 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1928 break;
1929 default:
1930 os = "unknown";
1931 build_num = 0;
1932 break;
1935 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1936 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1937 get_w32_major_version (), get_w32_minor_version (), build_num);
1938 } else {
1939 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1942 return configuration_buffer;
1945 char *
1946 get_emacs_configuration_options (void)
1948 static char options_buffer[256];
1950 /* Work out the effective configure options for this build. */
1951 #ifdef _MSC_VER
1952 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1953 #else
1954 #ifdef __GNUC__
1955 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1956 #else
1957 #define COMPILER_VERSION ""
1958 #endif
1959 #endif
1961 sprintf (options_buffer, COMPILER_VERSION);
1962 #ifdef EMACSDEBUG
1963 strcat (options_buffer, " --no-opt");
1964 #endif
1965 #ifdef USER_CFLAGS
1966 strcat (options_buffer, " --cflags");
1967 strcat (options_buffer, USER_CFLAGS);
1968 #endif
1969 #ifdef USER_LDFLAGS
1970 strcat (options_buffer, " --ldflags");
1971 strcat (options_buffer, USER_LDFLAGS);
1972 #endif
1973 return options_buffer;
1977 #include <sys/timeb.h>
1979 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1980 void
1981 gettimeofday (struct timeval *tv, struct timezone *tz)
1983 struct _timeb tb;
1984 _ftime (&tb);
1986 tv->tv_sec = tb.time;
1987 tv->tv_usec = tb.millitm * 1000L;
1988 if (tz)
1990 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
1991 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
1995 /* ------------------------------------------------------------------------- */
1996 /* IO support and wrapper functions for W32 API. */
1997 /* ------------------------------------------------------------------------- */
1999 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2000 on network directories, so we handle that case here.
2001 (Ulrich Leodolter, 1/11/95). */
2002 char *
2003 sys_ctime (const time_t *t)
2005 char *str = (char *) ctime (t);
2006 return (str ? str : "Sun Jan 01 00:00:00 1970");
2009 /* Emulate sleep...we could have done this with a define, but that
2010 would necessitate including windows.h in the files that used it.
2011 This is much easier. */
2012 void
2013 sys_sleep (int seconds)
2015 Sleep (seconds * 1000);
2018 /* Internal MSVC functions for low-level descriptor munging */
2019 extern int __cdecl _set_osfhnd (int fd, long h);
2020 extern int __cdecl _free_osfhnd (int fd);
2022 /* parallel array of private info on file handles */
2023 filedesc fd_info [ MAXDESC ];
2025 typedef struct volume_info_data {
2026 struct volume_info_data * next;
2028 /* time when info was obtained */
2029 DWORD timestamp;
2031 /* actual volume info */
2032 char * root_dir;
2033 DWORD serialnum;
2034 DWORD maxcomp;
2035 DWORD flags;
2036 char * name;
2037 char * type;
2038 } volume_info_data;
2040 /* Global referenced by various functions. */
2041 static volume_info_data volume_info;
2043 /* Vector to indicate which drives are local and fixed (for which cached
2044 data never expires). */
2045 static BOOL fixed_drives[26];
2047 /* Consider cached volume information to be stale if older than 10s,
2048 at least for non-local drives. Info for fixed drives is never stale. */
2049 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2050 #define VOLINFO_STILL_VALID( root_dir, info ) \
2051 ( ( isalpha (root_dir[0]) && \
2052 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2053 || GetTickCount () - info->timestamp < 10000 )
2055 /* Cache support functions. */
2057 /* Simple linked list with linear search is sufficient. */
2058 static volume_info_data *volume_cache = NULL;
2060 static volume_info_data *
2061 lookup_volume_info (char * root_dir)
2063 volume_info_data * info;
2065 for (info = volume_cache; info; info = info->next)
2066 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2067 break;
2068 return info;
2071 static void
2072 add_volume_info (char * root_dir, volume_info_data * info)
2074 info->root_dir = xstrdup (root_dir);
2075 info->next = volume_cache;
2076 volume_cache = info;
2080 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2081 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2082 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2083 volume_info_data *
2084 GetCachedVolumeInformation (char * root_dir)
2086 volume_info_data * info;
2087 char default_root[ MAX_PATH ];
2089 /* NULL for root_dir means use root from current directory. */
2090 if (root_dir == NULL)
2092 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
2093 return NULL;
2094 parse_root (default_root, &root_dir);
2095 *root_dir = 0;
2096 root_dir = default_root;
2099 /* Local fixed drives can be cached permanently. Removable drives
2100 cannot be cached permanently, since the volume name and serial
2101 number (if nothing else) can change. Remote drives should be
2102 treated as if they are removable, since there is no sure way to
2103 tell whether they are or not. Also, the UNC association of drive
2104 letters mapped to remote volumes can be changed at any time (even
2105 by other processes) without notice.
2107 As a compromise, so we can benefit from caching info for remote
2108 volumes, we use a simple expiry mechanism to invalidate cache
2109 entries that are more than ten seconds old. */
2111 #if 0
2112 /* No point doing this, because WNetGetConnection is even slower than
2113 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2114 GetDriveType is about the only call of this type which does not
2115 involve network access, and so is extremely quick). */
2117 /* Map drive letter to UNC if remote. */
2118 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
2120 char remote_name[ 256 ];
2121 char drive[3] = { root_dir[0], ':' };
2123 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2124 == NO_ERROR)
2125 /* do something */ ;
2127 #endif
2129 info = lookup_volume_info (root_dir);
2131 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2133 char name[ 256 ];
2134 DWORD serialnum;
2135 DWORD maxcomp;
2136 DWORD flags;
2137 char type[ 256 ];
2139 /* Info is not cached, or is stale. */
2140 if (!GetVolumeInformation (root_dir,
2141 name, sizeof (name),
2142 &serialnum,
2143 &maxcomp,
2144 &flags,
2145 type, sizeof (type)))
2146 return NULL;
2148 /* Cache the volume information for future use, overwriting existing
2149 entry if present. */
2150 if (info == NULL)
2152 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
2153 add_volume_info (root_dir, info);
2155 else
2157 xfree (info->name);
2158 xfree (info->type);
2161 info->name = xstrdup (name);
2162 info->serialnum = serialnum;
2163 info->maxcomp = maxcomp;
2164 info->flags = flags;
2165 info->type = xstrdup (type);
2166 info->timestamp = GetTickCount ();
2169 return info;
2172 /* Get information on the volume where name is held; set path pointer to
2173 start of pathname in name (past UNC header\volume header if present). */
2175 get_volume_info (const char * name, const char ** pPath)
2177 char temp[MAX_PATH];
2178 char *rootname = NULL; /* default to current volume */
2179 volume_info_data * info;
2181 if (name == NULL)
2182 return FALSE;
2184 /* find the root name of the volume if given */
2185 if (isalpha (name[0]) && name[1] == ':')
2187 rootname = temp;
2188 temp[0] = *name++;
2189 temp[1] = *name++;
2190 temp[2] = '\\';
2191 temp[3] = 0;
2193 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2195 char *str = temp;
2196 int slashes = 4;
2197 rootname = temp;
2200 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2201 break;
2202 *str++ = *name++;
2204 while ( *name );
2206 *str++ = '\\';
2207 *str = 0;
2210 if (pPath)
2211 *pPath = name;
2213 info = GetCachedVolumeInformation (rootname);
2214 if (info != NULL)
2216 /* Set global referenced by other functions. */
2217 volume_info = *info;
2218 return TRUE;
2220 return FALSE;
2223 /* Determine if volume is FAT format (ie. only supports short 8.3
2224 names); also set path pointer to start of pathname in name. */
2226 is_fat_volume (const char * name, const char ** pPath)
2228 if (get_volume_info (name, pPath))
2229 return (volume_info.maxcomp == 12);
2230 return FALSE;
2233 /* Map filename to a valid 8.3 name if necessary. */
2234 const char *
2235 map_w32_filename (const char * name, const char ** pPath)
2237 static char shortname[MAX_PATH];
2238 char * str = shortname;
2239 char c;
2240 char * path;
2241 const char * save_name = name;
2243 if (strlen (name) >= MAX_PATH)
2245 /* Return a filename which will cause callers to fail. */
2246 strcpy (shortname, "?");
2247 return shortname;
2250 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2252 register int left = 8; /* maximum number of chars in part */
2253 register int extn = 0; /* extension added? */
2254 register int dots = 2; /* maximum number of dots allowed */
2256 while (name < path)
2257 *str++ = *name++; /* skip past UNC header */
2259 while ((c = *name++))
2261 switch ( c )
2263 case '\\':
2264 case '/':
2265 *str++ = '\\';
2266 extn = 0; /* reset extension flags */
2267 dots = 2; /* max 2 dots */
2268 left = 8; /* max length 8 for main part */
2269 break;
2270 case ':':
2271 *str++ = ':';
2272 extn = 0; /* reset extension flags */
2273 dots = 2; /* max 2 dots */
2274 left = 8; /* max length 8 for main part */
2275 break;
2276 case '.':
2277 if ( dots )
2279 /* Convert path components of the form .xxx to _xxx,
2280 but leave . and .. as they are. This allows .emacs
2281 to be read as _emacs, for example. */
2283 if (! *name ||
2284 *name == '.' ||
2285 IS_DIRECTORY_SEP (*name))
2287 *str++ = '.';
2288 dots--;
2290 else
2292 *str++ = '_';
2293 left--;
2294 dots = 0;
2297 else if ( !extn )
2299 *str++ = '.';
2300 extn = 1; /* we've got an extension */
2301 left = 3; /* 3 chars in extension */
2303 else
2305 /* any embedded dots after the first are converted to _ */
2306 *str++ = '_';
2308 break;
2309 case '~':
2310 case '#': /* don't lose these, they're important */
2311 if ( ! left )
2312 str[-1] = c; /* replace last character of part */
2313 /* FALLTHRU */
2314 default:
2315 if ( left )
2317 *str++ = tolower (c); /* map to lower case (looks nicer) */
2318 left--;
2319 dots = 0; /* started a path component */
2321 break;
2324 *str = '\0';
2326 else
2328 strcpy (shortname, name);
2329 unixtodos_filename (shortname);
2332 if (pPath)
2333 *pPath = shortname + (path - save_name);
2335 return shortname;
2338 static int
2339 is_exec (const char * name)
2341 char * p = strrchr (name, '.');
2342 return
2343 (p != NULL
2344 && (xstrcasecmp (p, ".exe") == 0 ||
2345 xstrcasecmp (p, ".com") == 0 ||
2346 xstrcasecmp (p, ".bat") == 0 ||
2347 xstrcasecmp (p, ".cmd") == 0));
2350 /* Emulate the Unix directory procedures opendir, closedir,
2351 and readdir. We can't use the procedures supplied in sysdep.c,
2352 so we provide them here. */
2354 struct direct dir_static; /* simulated directory contents */
2355 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2356 static int dir_is_fat;
2357 static char dir_pathname[MAXPATHLEN+1];
2358 static WIN32_FIND_DATA dir_find_data;
2360 /* Support shares on a network resource as subdirectories of a read-only
2361 root directory. */
2362 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2363 HANDLE open_unc_volume (const char *);
2364 char *read_unc_volume (HANDLE, char *, int);
2365 void close_unc_volume (HANDLE);
2367 DIR *
2368 opendir (char *filename)
2370 DIR *dirp;
2372 /* Opening is done by FindFirstFile. However, a read is inherent to
2373 this operation, so we defer the open until read time. */
2375 if (dir_find_handle != INVALID_HANDLE_VALUE)
2376 return NULL;
2377 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2378 return NULL;
2380 if (is_unc_volume (filename))
2382 wnet_enum_handle = open_unc_volume (filename);
2383 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2384 return NULL;
2387 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2388 return NULL;
2390 dirp->dd_fd = 0;
2391 dirp->dd_loc = 0;
2392 dirp->dd_size = 0;
2394 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2395 dir_pathname[MAXPATHLEN] = '\0';
2396 dir_is_fat = is_fat_volume (filename, NULL);
2398 return dirp;
2401 void
2402 closedir (DIR *dirp)
2404 /* If we have a find-handle open, close it. */
2405 if (dir_find_handle != INVALID_HANDLE_VALUE)
2407 FindClose (dir_find_handle);
2408 dir_find_handle = INVALID_HANDLE_VALUE;
2410 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2412 close_unc_volume (wnet_enum_handle);
2413 wnet_enum_handle = INVALID_HANDLE_VALUE;
2415 xfree ((char *) dirp);
2418 struct direct *
2419 readdir (DIR *dirp)
2421 int downcase = !NILP (Vw32_downcase_file_names);
2423 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2425 if (!read_unc_volume (wnet_enum_handle,
2426 dir_find_data.cFileName,
2427 MAX_PATH))
2428 return NULL;
2430 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2431 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2433 char filename[MAXNAMLEN + 3];
2434 int ln;
2436 strcpy (filename, dir_pathname);
2437 ln = strlen (filename) - 1;
2438 if (!IS_DIRECTORY_SEP (filename[ln]))
2439 strcat (filename, "\\");
2440 strcat (filename, "*");
2442 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2444 if (dir_find_handle == INVALID_HANDLE_VALUE)
2445 return NULL;
2447 else
2449 if (!FindNextFile (dir_find_handle, &dir_find_data))
2450 return NULL;
2453 /* Emacs never uses this value, so don't bother making it match
2454 value returned by stat(). */
2455 dir_static.d_ino = 1;
2457 strcpy (dir_static.d_name, dir_find_data.cFileName);
2459 /* If the file name in cFileName[] includes `?' characters, it means
2460 the original file name used characters that cannot be represented
2461 by the current ANSI codepage. To avoid total lossage, retrieve
2462 the short 8+3 alias of the long file name. */
2463 if (_mbspbrk (dir_static.d_name, "?"))
2465 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2466 downcase = 1; /* 8+3 aliases are returned in all caps */
2468 dir_static.d_namlen = strlen (dir_static.d_name);
2469 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
2470 dir_static.d_namlen - dir_static.d_namlen % 4;
2472 /* If the file name in cFileName[] includes `?' characters, it means
2473 the original file name used characters that cannot be represented
2474 by the current ANSI codepage. To avoid total lossage, retrieve
2475 the short 8+3 alias of the long file name. */
2476 if (_mbspbrk (dir_find_data.cFileName, "?"))
2478 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2479 /* 8+3 aliases are returned in all caps, which could break
2480 various alists that look at filenames' extensions. */
2481 downcase = 1;
2483 else
2484 strcpy (dir_static.d_name, dir_find_data.cFileName);
2485 dir_static.d_namlen = strlen (dir_static.d_name);
2486 if (dir_is_fat)
2487 _strlwr (dir_static.d_name);
2488 else if (downcase)
2490 register char *p;
2491 for (p = dir_static.d_name; *p; p++)
2492 if (*p >= 'a' && *p <= 'z')
2493 break;
2494 if (!*p)
2495 _strlwr (dir_static.d_name);
2498 return &dir_static;
2501 HANDLE
2502 open_unc_volume (const char *path)
2504 NETRESOURCE nr;
2505 HANDLE henum;
2506 int result;
2508 nr.dwScope = RESOURCE_GLOBALNET;
2509 nr.dwType = RESOURCETYPE_DISK;
2510 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2511 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2512 nr.lpLocalName = NULL;
2513 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
2514 nr.lpComment = NULL;
2515 nr.lpProvider = NULL;
2517 result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2518 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2520 if (result == NO_ERROR)
2521 return henum;
2522 else
2523 return INVALID_HANDLE_VALUE;
2526 char *
2527 read_unc_volume (HANDLE henum, char *readbuf, int size)
2529 DWORD count;
2530 int result;
2531 DWORD bufsize = 512;
2532 char *buffer;
2533 char *ptr;
2535 count = 1;
2536 buffer = alloca (bufsize);
2537 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
2538 if (result != NO_ERROR)
2539 return NULL;
2541 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2542 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2543 ptr += 2;
2544 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2545 ptr++;
2547 strncpy (readbuf, ptr, size);
2548 return readbuf;
2551 void
2552 close_unc_volume (HANDLE henum)
2554 if (henum != INVALID_HANDLE_VALUE)
2555 WNetCloseEnum (henum);
2558 DWORD
2559 unc_volume_file_attributes (const char *path)
2561 HANDLE henum;
2562 DWORD attrs;
2564 henum = open_unc_volume (path);
2565 if (henum == INVALID_HANDLE_VALUE)
2566 return -1;
2568 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2570 close_unc_volume (henum);
2572 return attrs;
2575 /* Ensure a network connection is authenticated. */
2576 static void
2577 logon_network_drive (const char *path)
2579 NETRESOURCE resource;
2580 char share[MAX_PATH];
2581 int i, n_slashes;
2582 char drive[4];
2583 UINT drvtype;
2585 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
2586 drvtype = DRIVE_REMOTE;
2587 else if (path[0] == '\0' || path[1] != ':')
2588 drvtype = GetDriveType (NULL);
2589 else
2591 drive[0] = path[0];
2592 drive[1] = ':';
2593 drive[2] = '\\';
2594 drive[3] = '\0';
2595 drvtype = GetDriveType (drive);
2598 /* Only logon to networked drives. */
2599 if (drvtype != DRIVE_REMOTE)
2600 return;
2602 n_slashes = 2;
2603 strncpy (share, path, MAX_PATH);
2604 /* Truncate to just server and share name. */
2605 for (i = 2; i < MAX_PATH; i++)
2607 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2609 share[i] = '\0';
2610 break;
2614 resource.dwType = RESOURCETYPE_DISK;
2615 resource.lpLocalName = NULL;
2616 resource.lpRemoteName = share;
2617 resource.lpProvider = NULL;
2619 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2622 /* Shadow some MSVC runtime functions to map requests for long filenames
2623 to reasonable short names if necessary. This was originally added to
2624 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2625 long file names. */
2628 sys_access (const char * path, int mode)
2630 DWORD attributes;
2632 /* MSVC implementation doesn't recognize D_OK. */
2633 path = map_w32_filename (path, NULL);
2634 if (is_unc_volume (path))
2636 attributes = unc_volume_file_attributes (path);
2637 if (attributes == -1) {
2638 errno = EACCES;
2639 return -1;
2642 else if ((attributes = GetFileAttributes (path)) == -1)
2644 /* Should try mapping GetLastError to errno; for now just indicate
2645 that path doesn't exist. */
2646 errno = EACCES;
2647 return -1;
2649 if ((mode & X_OK) != 0 && !is_exec (path))
2651 errno = EACCES;
2652 return -1;
2654 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2656 errno = EACCES;
2657 return -1;
2659 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2661 errno = EACCES;
2662 return -1;
2664 return 0;
2668 sys_chdir (const char * path)
2670 return _chdir (map_w32_filename (path, NULL));
2674 sys_chmod (const char * path, int mode)
2676 return _chmod (map_w32_filename (path, NULL), mode);
2680 sys_chown (const char *path, uid_t owner, gid_t group)
2682 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2683 return -1;
2684 return 0;
2688 sys_creat (const char * path, int mode)
2690 return _creat (map_w32_filename (path, NULL), mode);
2693 FILE *
2694 sys_fopen(const char * path, const char * mode)
2696 int fd;
2697 int oflag;
2698 const char * mode_save = mode;
2700 /* Force all file handles to be non-inheritable. This is necessary to
2701 ensure child processes don't unwittingly inherit handles that might
2702 prevent future file access. */
2704 if (mode[0] == 'r')
2705 oflag = O_RDONLY;
2706 else if (mode[0] == 'w' || mode[0] == 'a')
2707 oflag = O_WRONLY | O_CREAT | O_TRUNC;
2708 else
2709 return NULL;
2711 /* Only do simplistic option parsing. */
2712 while (*++mode)
2713 if (mode[0] == '+')
2715 oflag &= ~(O_RDONLY | O_WRONLY);
2716 oflag |= O_RDWR;
2718 else if (mode[0] == 'b')
2720 oflag &= ~O_TEXT;
2721 oflag |= O_BINARY;
2723 else if (mode[0] == 't')
2725 oflag &= ~O_BINARY;
2726 oflag |= O_TEXT;
2728 else break;
2730 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2731 if (fd < 0)
2732 return NULL;
2734 return _fdopen (fd, mode_save);
2737 /* This only works on NTFS volumes, but is useful to have. */
2739 sys_link (const char * old, const char * new)
2741 HANDLE fileh;
2742 int result = -1;
2743 char oldname[MAX_PATH], newname[MAX_PATH];
2745 if (old == NULL || new == NULL)
2747 errno = ENOENT;
2748 return -1;
2751 strcpy (oldname, map_w32_filename (old, NULL));
2752 strcpy (newname, map_w32_filename (new, NULL));
2754 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2755 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2756 if (fileh != INVALID_HANDLE_VALUE)
2758 int wlen;
2760 /* Confusingly, the "alternate" stream name field does not apply
2761 when restoring a hard link, and instead contains the actual
2762 stream data for the link (ie. the name of the link to create).
2763 The WIN32_STREAM_ID structure before the cStreamName field is
2764 the stream header, which is then immediately followed by the
2765 stream data. */
2767 struct {
2768 WIN32_STREAM_ID wid;
2769 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2770 } data;
2772 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2773 data.wid.cStreamName, MAX_PATH);
2774 if (wlen > 0)
2776 LPVOID context = NULL;
2777 DWORD wbytes = 0;
2779 data.wid.dwStreamId = BACKUP_LINK;
2780 data.wid.dwStreamAttributes = 0;
2781 data.wid.Size.LowPart = wlen * sizeof(WCHAR);
2782 data.wid.Size.HighPart = 0;
2783 data.wid.dwStreamNameSize = 0;
2785 if (BackupWrite (fileh, (LPBYTE)&data,
2786 offsetof (WIN32_STREAM_ID, cStreamName)
2787 + data.wid.Size.LowPart,
2788 &wbytes, FALSE, FALSE, &context)
2789 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2791 /* succeeded */
2792 result = 0;
2794 else
2796 /* Should try mapping GetLastError to errno; for now just
2797 indicate a general error (eg. links not supported). */
2798 errno = EINVAL; // perhaps EMLINK?
2802 CloseHandle (fileh);
2804 else
2805 errno = ENOENT;
2807 return result;
2811 sys_mkdir (const char * path)
2813 return _mkdir (map_w32_filename (path, NULL));
2816 /* Because of long name mapping issues, we need to implement this
2817 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2818 a unique name, instead of setting the input template to an empty
2819 string.
2821 Standard algorithm seems to be use pid or tid with a letter on the
2822 front (in place of the 6 X's) and cycle through the letters to find a
2823 unique name. We extend that to allow any reasonable character as the
2824 first of the 6 X's. */
2825 char *
2826 sys_mktemp (char * template)
2828 char * p;
2829 int i;
2830 unsigned uid = GetCurrentThreadId ();
2831 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2833 if (template == NULL)
2834 return NULL;
2835 p = template + strlen (template);
2836 i = 5;
2837 /* replace up to the last 5 X's with uid in decimal */
2838 while (--p >= template && p[0] == 'X' && --i >= 0)
2840 p[0] = '0' + uid % 10;
2841 uid /= 10;
2844 if (i < 0 && p[0] == 'X')
2846 i = 0;
2849 int save_errno = errno;
2850 p[0] = first_char[i];
2851 if (sys_access (template, 0) < 0)
2853 errno = save_errno;
2854 return template;
2857 while (++i < sizeof (first_char));
2860 /* Template is badly formed or else we can't generate a unique name,
2861 so return empty string */
2862 template[0] = 0;
2863 return template;
2867 sys_open (const char * path, int oflag, int mode)
2869 const char* mpath = map_w32_filename (path, NULL);
2870 /* Try to open file without _O_CREAT, to be able to write to hidden
2871 and system files. Force all file handles to be
2872 non-inheritable. */
2873 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2874 if (res >= 0)
2875 return res;
2876 return _open (mpath, oflag | _O_NOINHERIT, mode);
2880 sys_rename (const char * oldname, const char * newname)
2882 BOOL result;
2883 char temp[MAX_PATH];
2885 /* MoveFile on Windows 95 doesn't correctly change the short file name
2886 alias in a number of circumstances (it is not easy to predict when
2887 just by looking at oldname and newname, unfortunately). In these
2888 cases, renaming through a temporary name avoids the problem.
2890 A second problem on Windows 95 is that renaming through a temp name when
2891 newname is uppercase fails (the final long name ends up in
2892 lowercase, although the short alias might be uppercase) UNLESS the
2893 long temp name is not 8.3.
2895 So, on Windows 95 we always rename through a temp name, and we make sure
2896 the temp name has a long extension to ensure correct renaming. */
2898 strcpy (temp, map_w32_filename (oldname, NULL));
2900 if (os_subtype == OS_WIN95)
2902 char * o;
2903 char * p;
2904 int i = 0;
2906 oldname = map_w32_filename (oldname, NULL);
2907 if (o = strrchr (oldname, '\\'))
2908 o++;
2909 else
2910 o = (char *) oldname;
2912 if (p = strrchr (temp, '\\'))
2913 p++;
2914 else
2915 p = temp;
2919 /* Force temp name to require a manufactured 8.3 alias - this
2920 seems to make the second rename work properly. */
2921 sprintf (p, "_.%s.%u", o, i);
2922 i++;
2923 result = rename (oldname, temp);
2925 /* This loop must surely terminate! */
2926 while (result < 0 && errno == EEXIST);
2927 if (result < 0)
2928 return -1;
2931 /* Emulate Unix behavior - newname is deleted if it already exists
2932 (at least if it is a file; don't do this for directories).
2934 Since we mustn't do this if we are just changing the case of the
2935 file name (we would end up deleting the file we are trying to
2936 rename!), we let rename detect if the destination file already
2937 exists - that way we avoid the possible pitfalls of trying to
2938 determine ourselves whether two names really refer to the same
2939 file, which is not always possible in the general case. (Consider
2940 all the permutations of shared or subst'd drives, etc.) */
2942 newname = map_w32_filename (newname, NULL);
2943 result = rename (temp, newname);
2945 if (result < 0
2946 && errno == EEXIST
2947 && _chmod (newname, 0666) == 0
2948 && _unlink (newname) == 0)
2949 result = rename (temp, newname);
2951 return result;
2955 sys_rmdir (const char * path)
2957 return _rmdir (map_w32_filename (path, NULL));
2961 sys_unlink (const char * path)
2963 path = map_w32_filename (path, NULL);
2965 /* On Unix, unlink works without write permission. */
2966 _chmod (path, 0666);
2967 return _unlink (path);
2970 static FILETIME utc_base_ft;
2971 static ULONGLONG utc_base; /* In 100ns units */
2972 static int init = 0;
2974 #define FILETIME_TO_U64(result, ft) \
2975 do { \
2976 ULARGE_INTEGER uiTemp; \
2977 uiTemp.LowPart = (ft).dwLowDateTime; \
2978 uiTemp.HighPart = (ft).dwHighDateTime; \
2979 result = uiTemp.QuadPart; \
2980 } while (0)
2982 static void
2983 initialize_utc_base ()
2985 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2986 SYSTEMTIME st;
2988 st.wYear = 1970;
2989 st.wMonth = 1;
2990 st.wDay = 1;
2991 st.wHour = 0;
2992 st.wMinute = 0;
2993 st.wSecond = 0;
2994 st.wMilliseconds = 0;
2996 SystemTimeToFileTime (&st, &utc_base_ft);
2997 FILETIME_TO_U64 (utc_base, utc_base_ft);
3000 static time_t
3001 convert_time (FILETIME ft)
3003 ULONGLONG tmp;
3005 if (!init)
3007 initialize_utc_base();
3008 init = 1;
3011 if (CompareFileTime (&ft, &utc_base_ft) < 0)
3012 return 0;
3014 FILETIME_TO_U64 (tmp, ft);
3015 return (time_t) ((tmp - utc_base) / 10000000L);
3019 void
3020 convert_from_time_t (time_t time, FILETIME * pft)
3022 ULARGE_INTEGER tmp;
3024 if (!init)
3026 initialize_utc_base ();
3027 init = 1;
3030 /* time in 100ns units since 1-Jan-1601 */
3031 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
3032 pft->dwHighDateTime = tmp.HighPart;
3033 pft->dwLowDateTime = tmp.LowPart;
3036 #if 0
3037 /* No reason to keep this; faking inode values either by hashing or even
3038 using the file index from GetInformationByHandle, is not perfect and
3039 so by default Emacs doesn't use the inode values on Windows.
3040 Instead, we now determine file-truename correctly (except for
3041 possible drive aliasing etc). */
3043 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3044 static unsigned
3045 hashval (const unsigned char * str)
3047 unsigned h = 0;
3048 while (*str)
3050 h = (h << 4) + *str++;
3051 h ^= (h >> 28);
3053 return h;
3056 /* Return the hash value of the canonical pathname, excluding the
3057 drive/UNC header, to get a hopefully unique inode number. */
3058 static DWORD
3059 generate_inode_val (const char * name)
3061 char fullname[ MAX_PATH ];
3062 char * p;
3063 unsigned hash;
3065 /* Get the truly canonical filename, if it exists. (Note: this
3066 doesn't resolve aliasing due to subst commands, or recognise hard
3067 links. */
3068 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3069 abort ();
3071 parse_root (fullname, &p);
3072 /* Normal W32 filesystems are still case insensitive. */
3073 _strlwr (p);
3074 return hashval (p);
3077 #endif
3079 static PSECURITY_DESCRIPTOR
3080 get_file_security_desc (const char *fname)
3082 PSECURITY_DESCRIPTOR psd = NULL;
3083 DWORD sd_len, err;
3084 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3085 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3087 if (!get_file_security (fname, si, psd, 0, &sd_len))
3089 err = GetLastError ();
3090 if (err != ERROR_INSUFFICIENT_BUFFER)
3091 return NULL;
3094 psd = xmalloc (sd_len);
3095 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3097 xfree (psd);
3098 return NULL;
3101 return psd;
3104 static DWORD
3105 get_rid (PSID sid)
3107 unsigned n_subauthorities;
3109 /* Use the last sub-authority value of the RID, the relative
3110 portion of the SID, as user/group ID. */
3111 n_subauthorities = *get_sid_sub_authority_count (sid);
3112 if (n_subauthorities < 1)
3113 return 0; /* the "World" RID */
3114 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3117 /* Caching SID and account values for faster lokup. */
3119 #ifdef __GNUC__
3120 # define FLEXIBLE_ARRAY_MEMBER
3121 #else
3122 # define FLEXIBLE_ARRAY_MEMBER 1
3123 #endif
3125 struct w32_id {
3126 unsigned rid;
3127 struct w32_id *next;
3128 char name[GNLEN+1];
3129 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3132 static struct w32_id *w32_idlist;
3134 static int
3135 w32_cached_id (PSID sid, unsigned *id, char *name)
3137 struct w32_id *tail, *found;
3139 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3141 if (equal_sid ((PSID)tail->sid, sid))
3143 found = tail;
3144 break;
3147 if (found)
3149 *id = found->rid;
3150 strcpy (name, found->name);
3151 return 1;
3153 else
3154 return 0;
3157 static void
3158 w32_add_to_cache (PSID sid, unsigned id, char *name)
3160 DWORD sid_len;
3161 struct w32_id *new_entry;
3163 /* We don't want to leave behind stale cache from when Emacs was
3164 dumped. */
3165 if (initialized)
3167 sid_len = get_length_sid (sid);
3168 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3169 if (new_entry)
3171 new_entry->rid = id;
3172 strcpy (new_entry->name, name);
3173 copy_sid (sid_len, (PSID)new_entry->sid, sid);
3174 new_entry->next = w32_idlist;
3175 w32_idlist = new_entry;
3180 #define UID 1
3181 #define GID 2
3183 static int
3184 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
3185 unsigned *id, char *nm, int what)
3187 PSID sid = NULL;
3188 char machine[MAX_COMPUTERNAME_LENGTH+1];
3189 BOOL dflt;
3190 SID_NAME_USE ignore;
3191 char name[UNLEN+1];
3192 DWORD name_len = sizeof (name);
3193 char domain[1024];
3194 DWORD domain_len = sizeof(domain);
3195 char *mp = NULL;
3196 int use_dflt = 0;
3197 int result;
3199 if (what == UID)
3200 result = get_security_descriptor_owner (psd, &sid, &dflt);
3201 else if (what == GID)
3202 result = get_security_descriptor_group (psd, &sid, &dflt);
3203 else
3204 result = 0;
3206 if (!result || !is_valid_sid (sid))
3207 use_dflt = 1;
3208 else if (!w32_cached_id (sid, id, nm))
3210 /* If FNAME is a UNC, we need to lookup account on the
3211 specified machine. */
3212 if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
3213 && fname[2] != '\0')
3215 const char *s;
3216 char *p;
3218 for (s = fname + 2, p = machine;
3219 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
3220 *p = *s;
3221 *p = '\0';
3222 mp = machine;
3225 if (!lookup_account_sid (mp, sid, name, &name_len,
3226 domain, &domain_len, &ignore)
3227 || name_len > UNLEN+1)
3228 use_dflt = 1;
3229 else
3231 *id = get_rid (sid);
3232 strcpy (nm, name);
3233 w32_add_to_cache (sid, *id, name);
3236 return use_dflt;
3239 static void
3240 get_file_owner_and_group (
3241 PSECURITY_DESCRIPTOR psd,
3242 const char *fname,
3243 struct stat *st)
3245 int dflt_usr = 0, dflt_grp = 0;
3247 if (!psd)
3249 dflt_usr = 1;
3250 dflt_grp = 1;
3252 else
3254 if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
3255 dflt_usr = 1;
3256 if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
3257 dflt_grp = 1;
3259 /* Consider files to belong to current user/group, if we cannot get
3260 more accurate information. */
3261 if (dflt_usr)
3263 st->st_uid = dflt_passwd.pw_uid;
3264 strcpy (st->st_uname, dflt_passwd.pw_name);
3266 if (dflt_grp)
3268 st->st_gid = dflt_passwd.pw_gid;
3269 strcpy (st->st_gname, dflt_group.gr_name);
3273 /* Return non-zero if NAME is a potentially slow filesystem. */
3275 is_slow_fs (const char *name)
3277 char drive_root[4];
3278 UINT devtype;
3280 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
3281 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
3282 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
3283 devtype = GetDriveType (NULL); /* use root of current drive */
3284 else
3286 /* GetDriveType needs the root directory of the drive. */
3287 strncpy (drive_root, name, 2);
3288 drive_root[2] = '\\';
3289 drive_root[3] = '\0';
3290 devtype = GetDriveType (drive_root);
3292 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
3295 /* MSVC stat function can't cope with UNC names and has other bugs, so
3296 replace it with our own. This also allows us to calculate consistent
3297 inode values without hacks in the main Emacs code. */
3299 stat (const char * path, struct stat * buf)
3301 char *name, *r;
3302 char drive_root[4];
3303 UINT devtype;
3304 WIN32_FIND_DATA wfd;
3305 HANDLE fh;
3306 unsigned __int64 fake_inode;
3307 int permission;
3308 int len;
3309 int rootdir = FALSE;
3310 PSECURITY_DESCRIPTOR psd = NULL;
3312 if (path == NULL || buf == NULL)
3314 errno = EFAULT;
3315 return -1;
3318 name = (char *) map_w32_filename (path, &path);
3319 /* Must be valid filename, no wild cards or other invalid
3320 characters. We use _mbspbrk to support multibyte strings that
3321 might look to strpbrk as if they included literal *, ?, and other
3322 characters mentioned below that are disallowed by Windows
3323 filesystems. */
3324 if (_mbspbrk (name, "*?|<>\""))
3326 errno = ENOENT;
3327 return -1;
3330 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3331 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3332 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3334 r[1] = r[2] = '\0';
3337 /* Remove trailing directory separator, unless name is the root
3338 directory of a drive or UNC volume in which case ensure there
3339 is a trailing separator. */
3340 len = strlen (name);
3341 rootdir = (path >= name + len - 1
3342 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3343 name = strcpy (alloca (len + 2), name);
3345 if (is_unc_volume (name))
3347 DWORD attrs = unc_volume_file_attributes (name);
3349 if (attrs == -1)
3350 return -1;
3352 memset (&wfd, 0, sizeof (wfd));
3353 wfd.dwFileAttributes = attrs;
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 if (rootdir)
3361 if (!IS_DIRECTORY_SEP (name[len-1]))
3362 strcat (name, "\\");
3363 if (GetDriveType (name) < 2)
3365 errno = ENOENT;
3366 return -1;
3368 memset (&wfd, 0, sizeof (wfd));
3369 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
3370 wfd.ftCreationTime = utc_base_ft;
3371 wfd.ftLastAccessTime = utc_base_ft;
3372 wfd.ftLastWriteTime = utc_base_ft;
3373 strcpy (wfd.cFileName, name);
3375 else
3377 if (IS_DIRECTORY_SEP (name[len-1]))
3378 name[len - 1] = 0;
3380 /* (This is hacky, but helps when doing file completions on
3381 network drives.) Optimize by using information available from
3382 active readdir if possible. */
3383 len = strlen (dir_pathname);
3384 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3385 len--;
3386 if (dir_find_handle != INVALID_HANDLE_VALUE
3387 && strnicmp (name, dir_pathname, len) == 0
3388 && IS_DIRECTORY_SEP (name[len])
3389 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3391 /* This was the last entry returned by readdir. */
3392 wfd = dir_find_data;
3394 else
3396 logon_network_drive (name);
3398 fh = FindFirstFile (name, &wfd);
3399 if (fh == INVALID_HANDLE_VALUE)
3401 errno = ENOENT;
3402 return -1;
3404 FindClose (fh);
3408 if (!(NILP (Vw32_get_true_file_attributes)
3409 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
3410 /* No access rights required to get info. */
3411 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
3412 FILE_FLAG_BACKUP_SEMANTICS, NULL))
3413 != INVALID_HANDLE_VALUE)
3415 /* This is more accurate in terms of gettting the correct number
3416 of links, but is quite slow (it is noticeable when Emacs is
3417 making a list of file name completions). */
3418 BY_HANDLE_FILE_INFORMATION info;
3420 if (GetFileInformationByHandle (fh, &info))
3422 buf->st_nlink = info.nNumberOfLinks;
3423 /* Might as well use file index to fake inode values, but this
3424 is not guaranteed to be unique unless we keep a handle open
3425 all the time (even then there are situations where it is
3426 not unique). Reputedly, there are at most 48 bits of info
3427 (on NTFS, presumably less on FAT). */
3428 fake_inode = info.nFileIndexHigh;
3429 fake_inode <<= 32;
3430 fake_inode += info.nFileIndexLow;
3432 else
3434 buf->st_nlink = 1;
3435 fake_inode = 0;
3438 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3440 buf->st_mode = S_IFDIR;
3442 else
3444 switch (GetFileType (fh))
3446 case FILE_TYPE_DISK:
3447 buf->st_mode = S_IFREG;
3448 break;
3449 case FILE_TYPE_PIPE:
3450 buf->st_mode = S_IFIFO;
3451 break;
3452 case FILE_TYPE_CHAR:
3453 case FILE_TYPE_UNKNOWN:
3454 default:
3455 buf->st_mode = S_IFCHR;
3458 CloseHandle (fh);
3459 psd = get_file_security_desc (name);
3460 get_file_owner_and_group (psd, name, buf);
3462 else
3464 /* Don't bother to make this information more accurate. */
3465 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
3466 S_IFDIR : S_IFREG;
3467 buf->st_nlink = 1;
3468 fake_inode = 0;
3470 get_file_owner_and_group (NULL, name, buf);
3472 xfree (psd);
3474 #if 0
3475 /* Not sure if there is any point in this. */
3476 if (!NILP (Vw32_generate_fake_inodes))
3477 fake_inode = generate_inode_val (name);
3478 else if (fake_inode == 0)
3480 /* For want of something better, try to make everything unique. */
3481 static DWORD gen_num = 0;
3482 fake_inode = ++gen_num;
3484 #endif
3486 /* MSVC defines _ino_t to be short; other libc's might not. */
3487 if (sizeof (buf->st_ino) == 2)
3488 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3489 else
3490 buf->st_ino = fake_inode;
3492 /* volume_info is set indirectly by map_w32_filename */
3493 buf->st_dev = volume_info.serialnum;
3494 buf->st_rdev = volume_info.serialnum;
3497 buf->st_size = wfd.nFileSizeHigh;
3498 buf->st_size <<= 32;
3499 buf->st_size += wfd.nFileSizeLow;
3501 /* Convert timestamps to Unix format. */
3502 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
3503 buf->st_atime = convert_time (wfd.ftLastAccessTime);
3504 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3505 buf->st_ctime = convert_time (wfd.ftCreationTime);
3506 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3508 /* determine rwx permissions */
3509 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3510 permission = S_IREAD;
3511 else
3512 permission = S_IREAD | S_IWRITE;
3514 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3515 permission |= S_IEXEC;
3516 else if (is_exec (name))
3517 permission |= S_IEXEC;
3519 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3521 return 0;
3524 /* Provide fstat and utime as well as stat for consistent handling of
3525 file timestamps. */
3527 fstat (int desc, struct stat * buf)
3529 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3530 BY_HANDLE_FILE_INFORMATION info;
3531 unsigned __int64 fake_inode;
3532 int permission;
3534 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3536 case FILE_TYPE_DISK:
3537 buf->st_mode = S_IFREG;
3538 if (!GetFileInformationByHandle (fh, &info))
3540 errno = EACCES;
3541 return -1;
3543 break;
3544 case FILE_TYPE_PIPE:
3545 buf->st_mode = S_IFIFO;
3546 goto non_disk;
3547 case FILE_TYPE_CHAR:
3548 case FILE_TYPE_UNKNOWN:
3549 default:
3550 buf->st_mode = S_IFCHR;
3551 non_disk:
3552 memset (&info, 0, sizeof (info));
3553 info.dwFileAttributes = 0;
3554 info.ftCreationTime = utc_base_ft;
3555 info.ftLastAccessTime = utc_base_ft;
3556 info.ftLastWriteTime = utc_base_ft;
3559 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3560 buf->st_mode = S_IFDIR;
3562 buf->st_nlink = info.nNumberOfLinks;
3563 /* Might as well use file index to fake inode values, but this
3564 is not guaranteed to be unique unless we keep a handle open
3565 all the time (even then there are situations where it is
3566 not unique). Reputedly, there are at most 48 bits of info
3567 (on NTFS, presumably less on FAT). */
3568 fake_inode = info.nFileIndexHigh;
3569 fake_inode <<= 32;
3570 fake_inode += info.nFileIndexLow;
3572 /* MSVC defines _ino_t to be short; other libc's might not. */
3573 if (sizeof (buf->st_ino) == 2)
3574 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3575 else
3576 buf->st_ino = fake_inode;
3578 /* Consider files to belong to current user.
3579 FIXME: this should use GetSecurityInfo API, but it is only
3580 available for _WIN32_WINNT >= 0x501. */
3581 buf->st_uid = dflt_passwd.pw_uid;
3582 buf->st_gid = dflt_passwd.pw_gid;
3583 strcpy (buf->st_uname, dflt_passwd.pw_name);
3584 strcpy (buf->st_gname, dflt_group.gr_name);
3586 buf->st_dev = info.dwVolumeSerialNumber;
3587 buf->st_rdev = info.dwVolumeSerialNumber;
3589 buf->st_size = info.nFileSizeHigh;
3590 buf->st_size <<= 32;
3591 buf->st_size += info.nFileSizeLow;
3593 /* Convert timestamps to Unix format. */
3594 buf->st_mtime = convert_time (info.ftLastWriteTime);
3595 buf->st_atime = convert_time (info.ftLastAccessTime);
3596 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3597 buf->st_ctime = convert_time (info.ftCreationTime);
3598 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3600 /* determine rwx permissions */
3601 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3602 permission = S_IREAD;
3603 else
3604 permission = S_IREAD | S_IWRITE;
3606 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3607 permission |= S_IEXEC;
3608 else
3610 #if 0 /* no way of knowing the filename */
3611 char * p = strrchr (name, '.');
3612 if (p != NULL &&
3613 (xstrcasecmp (p, ".exe") == 0 ||
3614 xstrcasecmp (p, ".com") == 0 ||
3615 xstrcasecmp (p, ".bat") == 0 ||
3616 xstrcasecmp (p, ".cmd") == 0))
3617 permission |= S_IEXEC;
3618 #endif
3621 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3623 return 0;
3627 utime (const char *name, struct utimbuf *times)
3629 struct utimbuf deftime;
3630 HANDLE fh;
3631 FILETIME mtime;
3632 FILETIME atime;
3634 if (times == NULL)
3636 deftime.modtime = deftime.actime = time (NULL);
3637 times = &deftime;
3640 /* Need write access to set times. */
3641 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
3642 0, OPEN_EXISTING, 0, NULL);
3643 if (fh)
3645 convert_from_time_t (times->actime, &atime);
3646 convert_from_time_t (times->modtime, &mtime);
3647 if (!SetFileTime (fh, NULL, &atime, &mtime))
3649 CloseHandle (fh);
3650 errno = EACCES;
3651 return -1;
3653 CloseHandle (fh);
3655 else
3657 errno = EINVAL;
3658 return -1;
3660 return 0;
3664 /* Support for browsing other processes and their attributes. See
3665 process.c for the Lisp bindings. */
3667 /* Helper wrapper functions. */
3669 HANDLE WINAPI create_toolhelp32_snapshot(
3670 DWORD Flags,
3671 DWORD Ignored)
3673 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
3675 if (g_b_init_create_toolhelp32_snapshot == 0)
3677 g_b_init_create_toolhelp32_snapshot = 1;
3678 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
3679 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3680 "CreateToolhelp32Snapshot");
3682 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
3684 return INVALID_HANDLE_VALUE;
3686 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
3689 BOOL WINAPI process32_first(
3690 HANDLE hSnapshot,
3691 LPPROCESSENTRY32 lppe)
3693 static Process32First_Proc s_pfn_Process32_First = NULL;
3695 if (g_b_init_process32_first == 0)
3697 g_b_init_process32_first = 1;
3698 s_pfn_Process32_First = (Process32First_Proc)
3699 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3700 "Process32First");
3702 if (s_pfn_Process32_First == NULL)
3704 return FALSE;
3706 return (s_pfn_Process32_First (hSnapshot, lppe));
3709 BOOL WINAPI process32_next(
3710 HANDLE hSnapshot,
3711 LPPROCESSENTRY32 lppe)
3713 static Process32Next_Proc s_pfn_Process32_Next = NULL;
3715 if (g_b_init_process32_next == 0)
3717 g_b_init_process32_next = 1;
3718 s_pfn_Process32_Next = (Process32Next_Proc)
3719 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3720 "Process32Next");
3722 if (s_pfn_Process32_Next == NULL)
3724 return FALSE;
3726 return (s_pfn_Process32_Next (hSnapshot, lppe));
3729 BOOL WINAPI open_thread_token (
3730 HANDLE ThreadHandle,
3731 DWORD DesiredAccess,
3732 BOOL OpenAsSelf,
3733 PHANDLE TokenHandle)
3735 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
3736 HMODULE hm_advapi32 = NULL;
3737 if (is_windows_9x () == TRUE)
3739 SetLastError (ERROR_NOT_SUPPORTED);
3740 return FALSE;
3742 if (g_b_init_open_thread_token == 0)
3744 g_b_init_open_thread_token = 1;
3745 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3746 s_pfn_Open_Thread_Token =
3747 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
3749 if (s_pfn_Open_Thread_Token == NULL)
3751 SetLastError (ERROR_NOT_SUPPORTED);
3752 return FALSE;
3754 return (
3755 s_pfn_Open_Thread_Token (
3756 ThreadHandle,
3757 DesiredAccess,
3758 OpenAsSelf,
3759 TokenHandle)
3763 BOOL WINAPI impersonate_self (
3764 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
3766 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
3767 HMODULE hm_advapi32 = NULL;
3768 if (is_windows_9x () == TRUE)
3770 return FALSE;
3772 if (g_b_init_impersonate_self == 0)
3774 g_b_init_impersonate_self = 1;
3775 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3776 s_pfn_Impersonate_Self =
3777 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
3779 if (s_pfn_Impersonate_Self == NULL)
3781 return FALSE;
3783 return s_pfn_Impersonate_Self (ImpersonationLevel);
3786 BOOL WINAPI revert_to_self (void)
3788 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
3789 HMODULE hm_advapi32 = NULL;
3790 if (is_windows_9x () == TRUE)
3792 return FALSE;
3794 if (g_b_init_revert_to_self == 0)
3796 g_b_init_revert_to_self = 1;
3797 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3798 s_pfn_Revert_To_Self =
3799 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
3801 if (s_pfn_Revert_To_Self == NULL)
3803 return FALSE;
3805 return s_pfn_Revert_To_Self ();
3808 BOOL WINAPI get_process_memory_info (
3809 HANDLE h_proc,
3810 PPROCESS_MEMORY_COUNTERS mem_counters,
3811 DWORD bufsize)
3813 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
3814 HMODULE hm_psapi = NULL;
3815 if (is_windows_9x () == TRUE)
3817 return FALSE;
3819 if (g_b_init_get_process_memory_info == 0)
3821 g_b_init_get_process_memory_info = 1;
3822 hm_psapi = LoadLibrary ("Psapi.dll");
3823 if (hm_psapi)
3824 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
3825 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
3827 if (s_pfn_Get_Process_Memory_Info == NULL)
3829 return FALSE;
3831 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
3834 BOOL WINAPI get_process_working_set_size (
3835 HANDLE h_proc,
3836 DWORD *minrss,
3837 DWORD *maxrss)
3839 static GetProcessWorkingSetSize_Proc
3840 s_pfn_Get_Process_Working_Set_Size = NULL;
3842 if (is_windows_9x () == TRUE)
3844 return FALSE;
3846 if (g_b_init_get_process_working_set_size == 0)
3848 g_b_init_get_process_working_set_size = 1;
3849 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
3850 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3851 "GetProcessWorkingSetSize");
3853 if (s_pfn_Get_Process_Working_Set_Size == NULL)
3855 return FALSE;
3857 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
3860 BOOL WINAPI global_memory_status (
3861 MEMORYSTATUS *buf)
3863 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
3865 if (is_windows_9x () == TRUE)
3867 return FALSE;
3869 if (g_b_init_global_memory_status == 0)
3871 g_b_init_global_memory_status = 1;
3872 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
3873 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3874 "GlobalMemoryStatus");
3876 if (s_pfn_Global_Memory_Status == NULL)
3878 return FALSE;
3880 return s_pfn_Global_Memory_Status (buf);
3883 BOOL WINAPI global_memory_status_ex (
3884 MEMORY_STATUS_EX *buf)
3886 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
3888 if (is_windows_9x () == TRUE)
3890 return FALSE;
3892 if (g_b_init_global_memory_status_ex == 0)
3894 g_b_init_global_memory_status_ex = 1;
3895 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
3896 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3897 "GlobalMemoryStatusEx");
3899 if (s_pfn_Global_Memory_Status_Ex == NULL)
3901 return FALSE;
3903 return s_pfn_Global_Memory_Status_Ex (buf);
3906 Lisp_Object
3907 list_system_processes ()
3909 struct gcpro gcpro1;
3910 Lisp_Object proclist = Qnil;
3911 HANDLE h_snapshot;
3913 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
3915 if (h_snapshot != INVALID_HANDLE_VALUE)
3917 PROCESSENTRY32 proc_entry;
3918 DWORD proc_id;
3919 BOOL res;
3921 GCPRO1 (proclist);
3923 proc_entry.dwSize = sizeof (PROCESSENTRY32);
3924 for (res = process32_first (h_snapshot, &proc_entry); res;
3925 res = process32_next (h_snapshot, &proc_entry))
3927 proc_id = proc_entry.th32ProcessID;
3928 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
3931 CloseHandle (h_snapshot);
3932 UNGCPRO;
3933 proclist = Fnreverse (proclist);
3936 return proclist;
3939 static int
3940 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
3942 TOKEN_PRIVILEGES priv;
3943 DWORD priv_size = sizeof (priv);
3944 DWORD opriv_size = sizeof (*old_priv);
3945 HANDLE h_token = NULL;
3946 HANDLE h_thread = GetCurrentThread ();
3947 int ret_val = 0;
3948 BOOL res;
3950 res = open_thread_token (h_thread,
3951 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3952 FALSE, &h_token);
3953 if (!res && GetLastError () == ERROR_NO_TOKEN)
3955 if (impersonate_self (SecurityImpersonation))
3956 res = open_thread_token (h_thread,
3957 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3958 FALSE, &h_token);
3960 if (res)
3962 priv.PrivilegeCount = 1;
3963 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
3964 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
3965 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
3966 old_priv, &opriv_size)
3967 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3968 ret_val = 1;
3970 if (h_token)
3971 CloseHandle (h_token);
3973 return ret_val;
3976 static int
3977 restore_privilege (TOKEN_PRIVILEGES *priv)
3979 DWORD priv_size = sizeof (*priv);
3980 HANDLE h_token = NULL;
3981 int ret_val = 0;
3983 if (open_thread_token (GetCurrentThread (),
3984 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3985 FALSE, &h_token))
3987 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
3988 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3989 ret_val = 1;
3991 if (h_token)
3992 CloseHandle (h_token);
3994 return ret_val;
3997 static Lisp_Object
3998 ltime (time_sec, time_usec)
3999 long time_sec, time_usec;
4001 return list3 (make_number ((time_sec >> 16) & 0xffff),
4002 make_number (time_sec & 0xffff),
4003 make_number (time_usec));
4006 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
4008 static int
4009 process_times (h_proc, ctime, etime, stime, utime, ttime, pcpu)
4010 HANDLE h_proc;
4011 Lisp_Object *ctime, *etime, *stime, *utime, *ttime;
4012 double *pcpu;
4014 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
4015 ULONGLONG tem1, tem2, tem3, tem;
4017 if (!h_proc
4018 || !get_process_times_fn
4019 || !(*get_process_times_fn)(h_proc, &ft_creation, &ft_exit,
4020 &ft_kernel, &ft_user))
4021 return 0;
4023 GetSystemTimeAsFileTime (&ft_current);
4025 FILETIME_TO_U64 (tem1, ft_kernel);
4026 tem1 /= 10L;
4027 *stime = U64_TO_LISP_TIME (tem1);
4029 FILETIME_TO_U64 (tem2, ft_user);
4030 tem2 /= 10L;
4031 *utime = U64_TO_LISP_TIME (tem2);
4033 tem3 = tem1 + tem2;
4034 *ttime = U64_TO_LISP_TIME (tem3);
4036 FILETIME_TO_U64 (tem, ft_creation);
4037 /* Process no 4 (System) returns zero creation time. */
4038 if (tem)
4039 tem = (tem - utc_base) / 10L;
4040 *ctime = U64_TO_LISP_TIME (tem);
4042 if (tem)
4044 FILETIME_TO_U64 (tem3, ft_current);
4045 tem = (tem3 - utc_base) / 10L - tem;
4047 *etime = U64_TO_LISP_TIME (tem);
4049 if (tem)
4051 *pcpu = 100.0 * (tem1 + tem2) / tem;
4052 if (*pcpu > 100)
4053 *pcpu = 100.0;
4055 else
4056 *pcpu = 0;
4058 return 1;
4061 Lisp_Object
4062 system_process_attributes (pid)
4063 Lisp_Object pid;
4065 struct gcpro gcpro1, gcpro2, gcpro3;
4066 Lisp_Object attrs = Qnil;
4067 Lisp_Object cmd_str, decoded_cmd, tem;
4068 HANDLE h_snapshot, h_proc;
4069 DWORD proc_id;
4070 int found_proc = 0;
4071 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
4072 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
4073 DWORD glength = sizeof (gname);
4074 HANDLE token = NULL;
4075 SID_NAME_USE user_type;
4076 unsigned char *buf = NULL;
4077 DWORD blen = 0;
4078 TOKEN_USER user_token;
4079 TOKEN_PRIMARY_GROUP group_token;
4080 unsigned euid;
4081 unsigned egid;
4082 DWORD sess;
4083 PROCESS_MEMORY_COUNTERS mem;
4084 PROCESS_MEMORY_COUNTERS_EX mem_ex;
4085 DWORD minrss, maxrss;
4086 MEMORYSTATUS memst;
4087 MEMORY_STATUS_EX memstex;
4088 double totphys = 0.0;
4089 Lisp_Object ctime, stime, utime, etime, ttime;
4090 double pcpu;
4091 BOOL result = FALSE;
4093 CHECK_NUMBER_OR_FLOAT (pid);
4094 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
4096 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4098 GCPRO3 (attrs, decoded_cmd, tem);
4100 if (h_snapshot != INVALID_HANDLE_VALUE)
4102 PROCESSENTRY32 pe;
4103 BOOL res;
4105 pe.dwSize = sizeof (PROCESSENTRY32);
4106 for (res = process32_first (h_snapshot, &pe); res;
4107 res = process32_next (h_snapshot, &pe))
4109 if (proc_id == pe.th32ProcessID)
4111 if (proc_id == 0)
4112 decoded_cmd = build_string ("Idle");
4113 else
4115 /* Decode the command name from locale-specific
4116 encoding. */
4117 cmd_str = make_unibyte_string (pe.szExeFile,
4118 strlen (pe.szExeFile));
4119 decoded_cmd =
4120 code_convert_string_norecord (cmd_str,
4121 Vlocale_coding_system, 0);
4123 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
4124 attrs = Fcons (Fcons (Qppid,
4125 make_fixnum_or_float (pe.th32ParentProcessID)),
4126 attrs);
4127 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
4128 attrs);
4129 attrs = Fcons (Fcons (Qthcount,
4130 make_fixnum_or_float (pe.cntThreads)),
4131 attrs);
4132 found_proc = 1;
4133 break;
4137 CloseHandle (h_snapshot);
4140 if (!found_proc)
4142 UNGCPRO;
4143 return Qnil;
4146 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4147 FALSE, proc_id);
4148 /* If we were denied a handle to the process, try again after
4149 enabling the SeDebugPrivilege in our process. */
4150 if (!h_proc)
4152 TOKEN_PRIVILEGES priv_current;
4154 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
4156 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4157 FALSE, proc_id);
4158 restore_privilege (&priv_current);
4159 revert_to_self ();
4162 if (h_proc)
4164 result = open_process_token (h_proc, TOKEN_QUERY, &token);
4165 if (result)
4167 result = get_token_information (token, TokenUser, NULL, 0, &blen);
4168 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4170 buf = xmalloc (blen);
4171 result = get_token_information (token, TokenUser,
4172 (LPVOID)buf, blen, &needed);
4173 if (result)
4175 memcpy (&user_token, buf, sizeof (user_token));
4176 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
4178 euid = get_rid (user_token.User.Sid);
4179 result = lookup_account_sid (NULL, user_token.User.Sid,
4180 uname, &ulength,
4181 domain, &dlength,
4182 &user_type);
4183 if (result)
4184 w32_add_to_cache (user_token.User.Sid, euid, uname);
4185 else
4187 strcpy (uname, "unknown");
4188 result = TRUE;
4191 ulength = strlen (uname);
4195 if (result)
4197 /* Determine a reasonable euid and gid values. */
4198 if (xstrcasecmp ("administrator", uname) == 0)
4200 euid = 500; /* well-known Administrator uid */
4201 egid = 513; /* well-known None gid */
4203 else
4205 /* Get group id and name. */
4206 result = get_token_information (token, TokenPrimaryGroup,
4207 (LPVOID)buf, blen, &needed);
4208 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4210 buf = xrealloc (buf, blen = needed);
4211 result = get_token_information (token, TokenPrimaryGroup,
4212 (LPVOID)buf, blen, &needed);
4214 if (result)
4216 memcpy (&group_token, buf, sizeof (group_token));
4217 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
4219 egid = get_rid (group_token.PrimaryGroup);
4220 dlength = sizeof (domain);
4221 result =
4222 lookup_account_sid (NULL, group_token.PrimaryGroup,
4223 gname, &glength, NULL, &dlength,
4224 &user_type);
4225 if (result)
4226 w32_add_to_cache (group_token.PrimaryGroup,
4227 egid, gname);
4228 else
4230 strcpy (gname, "None");
4231 result = TRUE;
4234 glength = strlen (gname);
4238 xfree (buf);
4240 if (!result)
4242 if (!is_windows_9x ())
4244 /* We couldn't open the process token, presumably because of
4245 insufficient access rights. Assume this process is run
4246 by the system. */
4247 strcpy (uname, "SYSTEM");
4248 strcpy (gname, "None");
4249 euid = 18; /* SYSTEM */
4250 egid = 513; /* None */
4251 glength = strlen (gname);
4252 ulength = strlen (uname);
4254 /* If we are running under Windows 9X, where security calls are
4255 not supported, we assume all processes are run by the current
4256 user. */
4257 else if (GetUserName (uname, &ulength))
4259 if (xstrcasecmp ("administrator", uname) == 0)
4260 euid = 0;
4261 else
4262 euid = 123;
4263 egid = euid;
4264 strcpy (gname, "None");
4265 glength = strlen (gname);
4266 ulength = strlen (uname);
4268 else
4270 euid = 123;
4271 egid = 123;
4272 strcpy (uname, "administrator");
4273 ulength = strlen (uname);
4274 strcpy (gname, "None");
4275 glength = strlen (gname);
4277 if (token)
4278 CloseHandle (token);
4281 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
4282 tem = make_unibyte_string (uname, ulength);
4283 attrs = Fcons (Fcons (Quser,
4284 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4285 attrs);
4286 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
4287 tem = make_unibyte_string (gname, glength);
4288 attrs = Fcons (Fcons (Qgroup,
4289 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4290 attrs);
4292 if (global_memory_status_ex (&memstex))
4293 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4294 totphys = memstex.ullTotalPhys / 1024.0;
4295 #else
4296 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4297 double, so we need to do this for it... */
4299 DWORD tot_hi = memstex.ullTotalPhys >> 32;
4300 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
4301 DWORD tot_lo = memstex.ullTotalPhys % 1024;
4303 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
4305 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4306 else if (global_memory_status (&memst))
4307 totphys = memst.dwTotalPhys / 1024.0;
4309 if (h_proc
4310 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
4311 sizeof (mem_ex)))
4313 DWORD rss = mem_ex.WorkingSetSize / 1024;
4315 attrs = Fcons (Fcons (Qmajflt,
4316 make_fixnum_or_float (mem_ex.PageFaultCount)),
4317 attrs);
4318 attrs = Fcons (Fcons (Qvsize,
4319 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
4320 attrs);
4321 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4322 if (totphys)
4323 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4325 else if (h_proc
4326 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
4328 DWORD rss = mem_ex.WorkingSetSize / 1024;
4330 attrs = Fcons (Fcons (Qmajflt,
4331 make_fixnum_or_float (mem.PageFaultCount)),
4332 attrs);
4333 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4334 if (totphys)
4335 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4337 else if (h_proc
4338 && get_process_working_set_size (h_proc, &minrss, &maxrss))
4340 DWORD rss = maxrss / 1024;
4342 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
4343 if (totphys)
4344 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4347 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
4349 attrs = Fcons (Fcons (Qutime, utime), attrs);
4350 attrs = Fcons (Fcons (Qstime, stime), attrs);
4351 attrs = Fcons (Fcons (Qtime, ttime), attrs);
4352 attrs = Fcons (Fcons (Qstart, ctime), attrs);
4353 attrs = Fcons (Fcons (Qetime, etime), attrs);
4354 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
4357 /* FIXME: Retrieve command line by walking the PEB of the process. */
4359 if (h_proc)
4360 CloseHandle (h_proc);
4361 UNGCPRO;
4362 return attrs;
4366 #ifdef HAVE_SOCKETS
4368 /* Wrappers for winsock functions to map between our file descriptors
4369 and winsock's handles; also set h_errno for convenience.
4371 To allow Emacs to run on systems which don't have winsock support
4372 installed, we dynamically link to winsock on startup if present, and
4373 otherwise provide the minimum necessary functionality
4374 (eg. gethostname). */
4376 /* function pointers for relevant socket functions */
4377 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
4378 void (PASCAL *pfn_WSASetLastError) (int iError);
4379 int (PASCAL *pfn_WSAGetLastError) (void);
4380 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
4381 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
4382 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
4383 int (PASCAL *pfn_socket) (int af, int type, int protocol);
4384 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
4385 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
4386 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
4387 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
4388 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
4389 int (PASCAL *pfn_closesocket) (SOCKET s);
4390 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
4391 int (PASCAL *pfn_WSACleanup) (void);
4393 u_short (PASCAL *pfn_htons) (u_short hostshort);
4394 u_short (PASCAL *pfn_ntohs) (u_short netshort);
4395 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
4396 int (PASCAL *pfn_gethostname) (char * name, int namelen);
4397 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
4398 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
4399 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
4400 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
4401 const char * optval, int optlen);
4402 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
4403 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
4404 int * namelen);
4405 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
4406 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
4407 struct sockaddr * from, int * fromlen);
4408 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
4409 const struct sockaddr * to, int tolen);
4411 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4412 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
4413 #ifndef HANDLE_FLAG_INHERIT
4414 #define HANDLE_FLAG_INHERIT 1
4415 #endif
4417 HANDLE winsock_lib;
4418 static int winsock_inuse;
4420 BOOL
4421 term_winsock (void)
4423 if (winsock_lib != NULL && winsock_inuse == 0)
4425 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4426 after WSAStartup returns successfully, but it seems reasonable
4427 to allow unloading winsock anyway in that case. */
4428 if (pfn_WSACleanup () == 0 ||
4429 pfn_WSAGetLastError () == WSAENETDOWN)
4431 if (FreeLibrary (winsock_lib))
4432 winsock_lib = NULL;
4433 return TRUE;
4436 return FALSE;
4439 BOOL
4440 init_winsock (int load_now)
4442 WSADATA winsockData;
4444 if (winsock_lib != NULL)
4445 return TRUE;
4447 pfn_SetHandleInformation = NULL;
4448 pfn_SetHandleInformation
4449 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4450 "SetHandleInformation");
4452 winsock_lib = LoadLibrary ("Ws2_32.dll");
4454 if (winsock_lib != NULL)
4456 /* dynamically link to socket functions */
4458 #define LOAD_PROC(fn) \
4459 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4460 goto fail;
4462 LOAD_PROC( WSAStartup );
4463 LOAD_PROC( WSASetLastError );
4464 LOAD_PROC( WSAGetLastError );
4465 LOAD_PROC( WSAEventSelect );
4466 LOAD_PROC( WSACreateEvent );
4467 LOAD_PROC( WSACloseEvent );
4468 LOAD_PROC( socket );
4469 LOAD_PROC( bind );
4470 LOAD_PROC( connect );
4471 LOAD_PROC( ioctlsocket );
4472 LOAD_PROC( recv );
4473 LOAD_PROC( send );
4474 LOAD_PROC( closesocket );
4475 LOAD_PROC( shutdown );
4476 LOAD_PROC( htons );
4477 LOAD_PROC( ntohs );
4478 LOAD_PROC( inet_addr );
4479 LOAD_PROC( gethostname );
4480 LOAD_PROC( gethostbyname );
4481 LOAD_PROC( getservbyname );
4482 LOAD_PROC( getpeername );
4483 LOAD_PROC( WSACleanup );
4484 LOAD_PROC( setsockopt );
4485 LOAD_PROC( listen );
4486 LOAD_PROC( getsockname );
4487 LOAD_PROC( accept );
4488 LOAD_PROC( recvfrom );
4489 LOAD_PROC( sendto );
4490 #undef LOAD_PROC
4492 /* specify version 1.1 of winsock */
4493 if (pfn_WSAStartup (0x101, &winsockData) == 0)
4495 if (winsockData.wVersion != 0x101)
4496 goto fail;
4498 if (!load_now)
4500 /* Report that winsock exists and is usable, but leave
4501 socket functions disabled. I am assuming that calling
4502 WSAStartup does not require any network interaction,
4503 and in particular does not cause or require a dial-up
4504 connection to be established. */
4506 pfn_WSACleanup ();
4507 FreeLibrary (winsock_lib);
4508 winsock_lib = NULL;
4510 winsock_inuse = 0;
4511 return TRUE;
4514 fail:
4515 FreeLibrary (winsock_lib);
4516 winsock_lib = NULL;
4519 return FALSE;
4523 int h_errno = 0;
4525 /* function to set h_errno for compatibility; map winsock error codes to
4526 normal system codes where they overlap (non-overlapping definitions
4527 are already in <sys/socket.h> */
4528 static void
4529 set_errno ()
4531 if (winsock_lib == NULL)
4532 h_errno = EINVAL;
4533 else
4534 h_errno = pfn_WSAGetLastError ();
4536 switch (h_errno)
4538 case WSAEACCES: h_errno = EACCES; break;
4539 case WSAEBADF: h_errno = EBADF; break;
4540 case WSAEFAULT: h_errno = EFAULT; break;
4541 case WSAEINTR: h_errno = EINTR; break;
4542 case WSAEINVAL: h_errno = EINVAL; break;
4543 case WSAEMFILE: h_errno = EMFILE; break;
4544 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
4545 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
4547 errno = h_errno;
4550 static void
4551 check_errno ()
4553 if (h_errno == 0 && winsock_lib != NULL)
4554 pfn_WSASetLastError (0);
4557 /* Extend strerror to handle the winsock-specific error codes. */
4558 struct {
4559 int errnum;
4560 char * msg;
4561 } _wsa_errlist[] = {
4562 WSAEINTR , "Interrupted function call",
4563 WSAEBADF , "Bad file descriptor",
4564 WSAEACCES , "Permission denied",
4565 WSAEFAULT , "Bad address",
4566 WSAEINVAL , "Invalid argument",
4567 WSAEMFILE , "Too many open files",
4569 WSAEWOULDBLOCK , "Resource temporarily unavailable",
4570 WSAEINPROGRESS , "Operation now in progress",
4571 WSAEALREADY , "Operation already in progress",
4572 WSAENOTSOCK , "Socket operation on non-socket",
4573 WSAEDESTADDRREQ , "Destination address required",
4574 WSAEMSGSIZE , "Message too long",
4575 WSAEPROTOTYPE , "Protocol wrong type for socket",
4576 WSAENOPROTOOPT , "Bad protocol option",
4577 WSAEPROTONOSUPPORT , "Protocol not supported",
4578 WSAESOCKTNOSUPPORT , "Socket type not supported",
4579 WSAEOPNOTSUPP , "Operation not supported",
4580 WSAEPFNOSUPPORT , "Protocol family not supported",
4581 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
4582 WSAEADDRINUSE , "Address already in use",
4583 WSAEADDRNOTAVAIL , "Cannot assign requested address",
4584 WSAENETDOWN , "Network is down",
4585 WSAENETUNREACH , "Network is unreachable",
4586 WSAENETRESET , "Network dropped connection on reset",
4587 WSAECONNABORTED , "Software caused connection abort",
4588 WSAECONNRESET , "Connection reset by peer",
4589 WSAENOBUFS , "No buffer space available",
4590 WSAEISCONN , "Socket is already connected",
4591 WSAENOTCONN , "Socket is not connected",
4592 WSAESHUTDOWN , "Cannot send after socket shutdown",
4593 WSAETOOMANYREFS , "Too many references", /* not sure */
4594 WSAETIMEDOUT , "Connection timed out",
4595 WSAECONNREFUSED , "Connection refused",
4596 WSAELOOP , "Network loop", /* not sure */
4597 WSAENAMETOOLONG , "Name is too long",
4598 WSAEHOSTDOWN , "Host is down",
4599 WSAEHOSTUNREACH , "No route to host",
4600 WSAENOTEMPTY , "Buffer not empty", /* not sure */
4601 WSAEPROCLIM , "Too many processes",
4602 WSAEUSERS , "Too many users", /* not sure */
4603 WSAEDQUOT , "Double quote in host name", /* really not sure */
4604 WSAESTALE , "Data is stale", /* not sure */
4605 WSAEREMOTE , "Remote error", /* not sure */
4607 WSASYSNOTREADY , "Network subsystem is unavailable",
4608 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
4609 WSANOTINITIALISED , "Winsock not initialized successfully",
4610 WSAEDISCON , "Graceful shutdown in progress",
4611 #ifdef WSAENOMORE
4612 WSAENOMORE , "No more operations allowed", /* not sure */
4613 WSAECANCELLED , "Operation cancelled", /* not sure */
4614 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
4615 WSAEINVALIDPROVIDER , "Invalid service provider version number",
4616 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
4617 WSASYSCALLFAILURE , "System call failure",
4618 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
4619 WSATYPE_NOT_FOUND , "Class type not found",
4620 WSA_E_NO_MORE , "No more resources available", /* really not sure */
4621 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
4622 WSAEREFUSED , "Operation refused", /* not sure */
4623 #endif
4625 WSAHOST_NOT_FOUND , "Host not found",
4626 WSATRY_AGAIN , "Authoritative host not found during name lookup",
4627 WSANO_RECOVERY , "Non-recoverable error during name lookup",
4628 WSANO_DATA , "Valid name, no data record of requested type",
4630 -1, NULL
4633 char *
4634 sys_strerror(int error_no)
4636 int i;
4637 static char unknown_msg[40];
4639 if (error_no >= 0 && error_no < sys_nerr)
4640 return sys_errlist[error_no];
4642 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
4643 if (_wsa_errlist[i].errnum == error_no)
4644 return _wsa_errlist[i].msg;
4646 sprintf(unknown_msg, "Unidentified error: %d", error_no);
4647 return unknown_msg;
4650 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4651 but I believe the method of keeping the socket handle separate (and
4652 insuring it is not inheritable) is the correct one. */
4654 //#define SOCK_REPLACE_HANDLE
4656 #ifdef SOCK_REPLACE_HANDLE
4657 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
4658 #else
4659 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4660 #endif
4662 int socket_to_fd (SOCKET s);
4665 sys_socket(int af, int type, int protocol)
4667 SOCKET s;
4669 if (winsock_lib == NULL)
4671 h_errno = ENETDOWN;
4672 return INVALID_SOCKET;
4675 check_errno ();
4677 /* call the real socket function */
4678 s = pfn_socket (af, type, protocol);
4680 if (s != INVALID_SOCKET)
4681 return socket_to_fd (s);
4683 set_errno ();
4684 return -1;
4687 /* Convert a SOCKET to a file descriptor. */
4689 socket_to_fd (SOCKET s)
4691 int fd;
4692 child_process * cp;
4694 /* Although under NT 3.5 _open_osfhandle will accept a socket
4695 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4696 that does not work under NT 3.1. However, we can get the same
4697 effect by using a backdoor function to replace an existing
4698 descriptor handle with the one we want. */
4700 /* allocate a file descriptor (with appropriate flags) */
4701 fd = _open ("NUL:", _O_RDWR);
4702 if (fd >= 0)
4704 #ifdef SOCK_REPLACE_HANDLE
4705 /* now replace handle to NUL with our socket handle */
4706 CloseHandle ((HANDLE) _get_osfhandle (fd));
4707 _free_osfhnd (fd);
4708 _set_osfhnd (fd, s);
4709 /* setmode (fd, _O_BINARY); */
4710 #else
4711 /* Make a non-inheritable copy of the socket handle. Note
4712 that it is possible that sockets aren't actually kernel
4713 handles, which appears to be the case on Windows 9x when
4714 the MS Proxy winsock client is installed. */
4716 /* Apparently there is a bug in NT 3.51 with some service
4717 packs, which prevents using DuplicateHandle to make a
4718 socket handle non-inheritable (causes WSACleanup to
4719 hang). The work-around is to use SetHandleInformation
4720 instead if it is available and implemented. */
4721 if (pfn_SetHandleInformation)
4723 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
4725 else
4727 HANDLE parent = GetCurrentProcess ();
4728 HANDLE new_s = INVALID_HANDLE_VALUE;
4730 if (DuplicateHandle (parent,
4731 (HANDLE) s,
4732 parent,
4733 &new_s,
4735 FALSE,
4736 DUPLICATE_SAME_ACCESS))
4738 /* It is possible that DuplicateHandle succeeds even
4739 though the socket wasn't really a kernel handle,
4740 because a real handle has the same value. So
4741 test whether the new handle really is a socket. */
4742 long nonblocking = 0;
4743 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
4745 pfn_closesocket (s);
4746 s = (SOCKET) new_s;
4748 else
4750 CloseHandle (new_s);
4755 fd_info[fd].hnd = (HANDLE) s;
4756 #endif
4758 /* set our own internal flags */
4759 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
4761 cp = new_child ();
4762 if (cp)
4764 cp->fd = fd;
4765 cp->status = STATUS_READ_ACKNOWLEDGED;
4767 /* attach child_process to fd_info */
4768 if (fd_info[ fd ].cp != NULL)
4770 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
4771 abort ();
4774 fd_info[ fd ].cp = cp;
4776 /* success! */
4777 winsock_inuse++; /* count open sockets */
4778 return fd;
4781 /* clean up */
4782 _close (fd);
4784 pfn_closesocket (s);
4785 h_errno = EMFILE;
4786 return -1;
4791 sys_bind (int s, const struct sockaddr * addr, int namelen)
4793 if (winsock_lib == NULL)
4795 h_errno = ENOTSOCK;
4796 return SOCKET_ERROR;
4799 check_errno ();
4800 if (fd_info[s].flags & FILE_SOCKET)
4802 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
4803 if (rc == SOCKET_ERROR)
4804 set_errno ();
4805 return rc;
4807 h_errno = ENOTSOCK;
4808 return SOCKET_ERROR;
4813 sys_connect (int s, const struct sockaddr * name, int namelen)
4815 if (winsock_lib == NULL)
4817 h_errno = ENOTSOCK;
4818 return SOCKET_ERROR;
4821 check_errno ();
4822 if (fd_info[s].flags & FILE_SOCKET)
4824 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
4825 if (rc == SOCKET_ERROR)
4826 set_errno ();
4827 return rc;
4829 h_errno = ENOTSOCK;
4830 return SOCKET_ERROR;
4833 u_short
4834 sys_htons (u_short hostshort)
4836 return (winsock_lib != NULL) ?
4837 pfn_htons (hostshort) : hostshort;
4840 u_short
4841 sys_ntohs (u_short netshort)
4843 return (winsock_lib != NULL) ?
4844 pfn_ntohs (netshort) : netshort;
4847 unsigned long
4848 sys_inet_addr (const char * cp)
4850 return (winsock_lib != NULL) ?
4851 pfn_inet_addr (cp) : INADDR_NONE;
4855 sys_gethostname (char * name, int namelen)
4857 if (winsock_lib != NULL)
4858 return pfn_gethostname (name, namelen);
4860 if (namelen > MAX_COMPUTERNAME_LENGTH)
4861 return !GetComputerName (name, (DWORD *)&namelen);
4863 h_errno = EFAULT;
4864 return SOCKET_ERROR;
4867 struct hostent *
4868 sys_gethostbyname(const char * name)
4870 struct hostent * host;
4872 if (winsock_lib == NULL)
4874 h_errno = ENETDOWN;
4875 return NULL;
4878 check_errno ();
4879 host = pfn_gethostbyname (name);
4880 if (!host)
4881 set_errno ();
4882 return host;
4885 struct servent *
4886 sys_getservbyname(const char * name, const char * proto)
4888 struct servent * serv;
4890 if (winsock_lib == NULL)
4892 h_errno = ENETDOWN;
4893 return NULL;
4896 check_errno ();
4897 serv = pfn_getservbyname (name, proto);
4898 if (!serv)
4899 set_errno ();
4900 return serv;
4904 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
4906 if (winsock_lib == NULL)
4908 h_errno = ENETDOWN;
4909 return SOCKET_ERROR;
4912 check_errno ();
4913 if (fd_info[s].flags & FILE_SOCKET)
4915 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
4916 if (rc == SOCKET_ERROR)
4917 set_errno ();
4918 return rc;
4920 h_errno = ENOTSOCK;
4921 return SOCKET_ERROR;
4926 sys_shutdown (int s, int how)
4928 if (winsock_lib == NULL)
4930 h_errno = ENETDOWN;
4931 return SOCKET_ERROR;
4934 check_errno ();
4935 if (fd_info[s].flags & FILE_SOCKET)
4937 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
4938 if (rc == SOCKET_ERROR)
4939 set_errno ();
4940 return rc;
4942 h_errno = ENOTSOCK;
4943 return SOCKET_ERROR;
4947 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
4949 if (winsock_lib == NULL)
4951 h_errno = ENETDOWN;
4952 return SOCKET_ERROR;
4955 check_errno ();
4956 if (fd_info[s].flags & FILE_SOCKET)
4958 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
4959 (const char *)optval, optlen);
4960 if (rc == SOCKET_ERROR)
4961 set_errno ();
4962 return rc;
4964 h_errno = ENOTSOCK;
4965 return SOCKET_ERROR;
4969 sys_listen (int s, int backlog)
4971 if (winsock_lib == NULL)
4973 h_errno = ENETDOWN;
4974 return SOCKET_ERROR;
4977 check_errno ();
4978 if (fd_info[s].flags & FILE_SOCKET)
4980 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
4981 if (rc == SOCKET_ERROR)
4982 set_errno ();
4983 else
4984 fd_info[s].flags |= FILE_LISTEN;
4985 return rc;
4987 h_errno = ENOTSOCK;
4988 return SOCKET_ERROR;
4992 sys_getsockname (int s, struct sockaddr * name, int * namelen)
4994 if (winsock_lib == NULL)
4996 h_errno = ENETDOWN;
4997 return SOCKET_ERROR;
5000 check_errno ();
5001 if (fd_info[s].flags & FILE_SOCKET)
5003 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
5004 if (rc == SOCKET_ERROR)
5005 set_errno ();
5006 return rc;
5008 h_errno = ENOTSOCK;
5009 return SOCKET_ERROR;
5013 sys_accept (int s, struct sockaddr * addr, int * addrlen)
5015 if (winsock_lib == NULL)
5017 h_errno = ENETDOWN;
5018 return -1;
5021 check_errno ();
5022 if (fd_info[s].flags & FILE_LISTEN)
5024 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
5025 int fd = -1;
5026 if (t == INVALID_SOCKET)
5027 set_errno ();
5028 else
5029 fd = socket_to_fd (t);
5031 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
5032 ResetEvent (fd_info[s].cp->char_avail);
5033 return fd;
5035 h_errno = ENOTSOCK;
5036 return -1;
5040 sys_recvfrom (int s, char * buf, int len, int flags,
5041 struct sockaddr * from, int * fromlen)
5043 if (winsock_lib == NULL)
5045 h_errno = ENETDOWN;
5046 return SOCKET_ERROR;
5049 check_errno ();
5050 if (fd_info[s].flags & FILE_SOCKET)
5052 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
5053 if (rc == SOCKET_ERROR)
5054 set_errno ();
5055 return rc;
5057 h_errno = ENOTSOCK;
5058 return SOCKET_ERROR;
5062 sys_sendto (int s, const char * buf, int len, int flags,
5063 const struct sockaddr * to, int tolen)
5065 if (winsock_lib == NULL)
5067 h_errno = ENETDOWN;
5068 return SOCKET_ERROR;
5071 check_errno ();
5072 if (fd_info[s].flags & FILE_SOCKET)
5074 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
5075 if (rc == SOCKET_ERROR)
5076 set_errno ();
5077 return rc;
5079 h_errno = ENOTSOCK;
5080 return SOCKET_ERROR;
5083 /* Windows does not have an fcntl function. Provide an implementation
5084 solely for making sockets non-blocking. */
5086 fcntl (int s, int cmd, int options)
5088 if (winsock_lib == NULL)
5090 h_errno = ENETDOWN;
5091 return -1;
5094 check_errno ();
5095 if (fd_info[s].flags & FILE_SOCKET)
5097 if (cmd == F_SETFL && options == O_NDELAY)
5099 unsigned long nblock = 1;
5100 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
5101 if (rc == SOCKET_ERROR)
5102 set_errno();
5103 /* Keep track of the fact that we set this to non-blocking. */
5104 fd_info[s].flags |= FILE_NDELAY;
5105 return rc;
5107 else
5109 h_errno = EINVAL;
5110 return SOCKET_ERROR;
5113 h_errno = ENOTSOCK;
5114 return SOCKET_ERROR;
5117 #endif /* HAVE_SOCKETS */
5120 /* Shadow main io functions: we need to handle pipes and sockets more
5121 intelligently, and implement non-blocking mode as well. */
5124 sys_close (int fd)
5126 int rc;
5128 if (fd < 0)
5130 errno = EBADF;
5131 return -1;
5134 if (fd < MAXDESC && fd_info[fd].cp)
5136 child_process * cp = fd_info[fd].cp;
5138 fd_info[fd].cp = NULL;
5140 if (CHILD_ACTIVE (cp))
5142 /* if last descriptor to active child_process then cleanup */
5143 int i;
5144 for (i = 0; i < MAXDESC; i++)
5146 if (i == fd)
5147 continue;
5148 if (fd_info[i].cp == cp)
5149 break;
5151 if (i == MAXDESC)
5153 #ifdef HAVE_SOCKETS
5154 if (fd_info[fd].flags & FILE_SOCKET)
5156 #ifndef SOCK_REPLACE_HANDLE
5157 if (winsock_lib == NULL) abort ();
5159 pfn_shutdown (SOCK_HANDLE (fd), 2);
5160 rc = pfn_closesocket (SOCK_HANDLE (fd));
5161 #endif
5162 winsock_inuse--; /* count open sockets */
5164 #endif
5165 delete_child (cp);
5170 /* Note that sockets do not need special treatment here (at least on
5171 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5172 closesocket is equivalent to CloseHandle, which is to be expected
5173 because socket handles are fully fledged kernel handles. */
5174 rc = _close (fd);
5176 if (rc == 0 && fd < MAXDESC)
5177 fd_info[fd].flags = 0;
5179 return rc;
5183 sys_dup (int fd)
5185 int new_fd;
5187 new_fd = _dup (fd);
5188 if (new_fd >= 0 && new_fd < MAXDESC)
5190 /* duplicate our internal info as well */
5191 fd_info[new_fd] = fd_info[fd];
5193 return new_fd;
5198 sys_dup2 (int src, int dst)
5200 int rc;
5202 if (dst < 0 || dst >= MAXDESC)
5204 errno = EBADF;
5205 return -1;
5208 /* make sure we close the destination first if it's a pipe or socket */
5209 if (src != dst && fd_info[dst].flags != 0)
5210 sys_close (dst);
5212 rc = _dup2 (src, dst);
5213 if (rc == 0)
5215 /* duplicate our internal info as well */
5216 fd_info[dst] = fd_info[src];
5218 return rc;
5221 /* Unix pipe() has only one arg */
5223 sys_pipe (int * phandles)
5225 int rc;
5226 unsigned flags;
5228 /* make pipe handles non-inheritable; when we spawn a child, we
5229 replace the relevant handle with an inheritable one. Also put
5230 pipes into binary mode; we will do text mode translation ourselves
5231 if required. */
5232 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
5234 if (rc == 0)
5236 /* Protect against overflow, since Windows can open more handles than
5237 our fd_info array has room for. */
5238 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
5240 _close (phandles[0]);
5241 _close (phandles[1]);
5242 rc = -1;
5244 else
5246 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
5247 fd_info[phandles[0]].flags = flags;
5249 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
5250 fd_info[phandles[1]].flags = flags;
5254 return rc;
5257 /* From ntproc.c */
5258 extern int w32_pipe_read_delay;
5260 /* Function to do blocking read of one byte, needed to implement
5261 select. It is only allowed on sockets and pipes. */
5263 _sys_read_ahead (int fd)
5265 child_process * cp;
5266 int rc;
5268 if (fd < 0 || fd >= MAXDESC)
5269 return STATUS_READ_ERROR;
5271 cp = fd_info[fd].cp;
5273 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5274 return STATUS_READ_ERROR;
5276 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
5277 || (fd_info[fd].flags & FILE_READ) == 0)
5279 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
5280 abort ();
5283 cp->status = STATUS_READ_IN_PROGRESS;
5285 if (fd_info[fd].flags & FILE_PIPE)
5287 rc = _read (fd, &cp->chr, sizeof (char));
5289 /* Give subprocess time to buffer some more output for us before
5290 reporting that input is available; we need this because Windows 95
5291 connects DOS programs to pipes by making the pipe appear to be
5292 the normal console stdout - as a result most DOS programs will
5293 write to stdout without buffering, ie. one character at a
5294 time. Even some W32 programs do this - "dir" in a command
5295 shell on NT is very slow if we don't do this. */
5296 if (rc > 0)
5298 int wait = w32_pipe_read_delay;
5300 if (wait > 0)
5301 Sleep (wait);
5302 else if (wait < 0)
5303 while (++wait <= 0)
5304 /* Yield remainder of our time slice, effectively giving a
5305 temporary priority boost to the child process. */
5306 Sleep (0);
5309 else if (fd_info[fd].flags & FILE_SERIAL)
5311 HANDLE hnd = fd_info[fd].hnd;
5312 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5313 COMMTIMEOUTS ct;
5315 /* Configure timeouts for blocking read. */
5316 if (!GetCommTimeouts (hnd, &ct))
5317 return STATUS_READ_ERROR;
5318 ct.ReadIntervalTimeout = 0;
5319 ct.ReadTotalTimeoutMultiplier = 0;
5320 ct.ReadTotalTimeoutConstant = 0;
5321 if (!SetCommTimeouts (hnd, &ct))
5322 return STATUS_READ_ERROR;
5324 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
5326 if (GetLastError () != ERROR_IO_PENDING)
5327 return STATUS_READ_ERROR;
5328 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5329 return STATUS_READ_ERROR;
5332 #ifdef HAVE_SOCKETS
5333 else if (fd_info[fd].flags & FILE_SOCKET)
5335 unsigned long nblock = 0;
5336 /* We always want this to block, so temporarily disable NDELAY. */
5337 if (fd_info[fd].flags & FILE_NDELAY)
5338 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5340 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
5342 if (fd_info[fd].flags & FILE_NDELAY)
5344 nblock = 1;
5345 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5348 #endif
5350 if (rc == sizeof (char))
5351 cp->status = STATUS_READ_SUCCEEDED;
5352 else
5353 cp->status = STATUS_READ_FAILED;
5355 return cp->status;
5359 _sys_wait_accept (int fd)
5361 HANDLE hEv;
5362 child_process * cp;
5363 int rc;
5365 if (fd < 0 || fd >= MAXDESC)
5366 return STATUS_READ_ERROR;
5368 cp = fd_info[fd].cp;
5370 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5371 return STATUS_READ_ERROR;
5373 cp->status = STATUS_READ_FAILED;
5375 hEv = pfn_WSACreateEvent ();
5376 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
5377 if (rc != SOCKET_ERROR)
5379 rc = WaitForSingleObject (hEv, INFINITE);
5380 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
5381 if (rc == WAIT_OBJECT_0)
5382 cp->status = STATUS_READ_SUCCEEDED;
5384 pfn_WSACloseEvent (hEv);
5386 return cp->status;
5390 sys_read (int fd, char * buffer, unsigned int count)
5392 int nchars;
5393 int to_read;
5394 DWORD waiting;
5395 char * orig_buffer = buffer;
5397 if (fd < 0)
5399 errno = EBADF;
5400 return -1;
5403 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5405 child_process *cp = fd_info[fd].cp;
5407 if ((fd_info[fd].flags & FILE_READ) == 0)
5409 errno = EBADF;
5410 return -1;
5413 nchars = 0;
5415 /* re-read CR carried over from last read */
5416 if (fd_info[fd].flags & FILE_LAST_CR)
5418 if (fd_info[fd].flags & FILE_BINARY) abort ();
5419 *buffer++ = 0x0d;
5420 count--;
5421 nchars++;
5422 fd_info[fd].flags &= ~FILE_LAST_CR;
5425 /* presence of a child_process structure means we are operating in
5426 non-blocking mode - otherwise we just call _read directly.
5427 Note that the child_process structure might be missing because
5428 reap_subprocess has been called; in this case the pipe is
5429 already broken, so calling _read on it is okay. */
5430 if (cp)
5432 int current_status = cp->status;
5434 switch (current_status)
5436 case STATUS_READ_FAILED:
5437 case STATUS_READ_ERROR:
5438 /* report normal EOF if nothing in buffer */
5439 if (nchars <= 0)
5440 fd_info[fd].flags |= FILE_AT_EOF;
5441 return nchars;
5443 case STATUS_READ_READY:
5444 case STATUS_READ_IN_PROGRESS:
5445 DebPrint (("sys_read called when read is in progress\n"));
5446 errno = EWOULDBLOCK;
5447 return -1;
5449 case STATUS_READ_SUCCEEDED:
5450 /* consume read-ahead char */
5451 *buffer++ = cp->chr;
5452 count--;
5453 nchars++;
5454 cp->status = STATUS_READ_ACKNOWLEDGED;
5455 ResetEvent (cp->char_avail);
5457 case STATUS_READ_ACKNOWLEDGED:
5458 break;
5460 default:
5461 DebPrint (("sys_read: bad status %d\n", current_status));
5462 errno = EBADF;
5463 return -1;
5466 if (fd_info[fd].flags & FILE_PIPE)
5468 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
5469 to_read = min (waiting, (DWORD) count);
5471 if (to_read > 0)
5472 nchars += _read (fd, buffer, to_read);
5474 else if (fd_info[fd].flags & FILE_SERIAL)
5476 HANDLE hnd = fd_info[fd].hnd;
5477 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5478 DWORD err = 0;
5479 int rc = 0;
5480 COMMTIMEOUTS ct;
5482 if (count > 0)
5484 /* Configure timeouts for non-blocking read. */
5485 if (!GetCommTimeouts (hnd, &ct))
5487 errno = EIO;
5488 return -1;
5490 ct.ReadIntervalTimeout = MAXDWORD;
5491 ct.ReadTotalTimeoutMultiplier = 0;
5492 ct.ReadTotalTimeoutConstant = 0;
5493 if (!SetCommTimeouts (hnd, &ct))
5495 errno = EIO;
5496 return -1;
5499 if (!ResetEvent (ovl->hEvent))
5501 errno = EIO;
5502 return -1;
5504 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
5506 if (GetLastError () != ERROR_IO_PENDING)
5508 errno = EIO;
5509 return -1;
5511 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5513 errno = EIO;
5514 return -1;
5517 nchars += rc;
5520 #ifdef HAVE_SOCKETS
5521 else /* FILE_SOCKET */
5523 if (winsock_lib == NULL) abort ();
5525 /* do the equivalent of a non-blocking read */
5526 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
5527 if (waiting == 0 && nchars == 0)
5529 h_errno = errno = EWOULDBLOCK;
5530 return -1;
5533 if (waiting)
5535 /* always use binary mode for sockets */
5536 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
5537 if (res == SOCKET_ERROR)
5539 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
5540 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5541 set_errno ();
5542 return -1;
5544 nchars += res;
5547 #endif
5549 else
5551 int nread = _read (fd, buffer, count);
5552 if (nread >= 0)
5553 nchars += nread;
5554 else if (nchars == 0)
5555 nchars = nread;
5558 if (nchars <= 0)
5559 fd_info[fd].flags |= FILE_AT_EOF;
5560 /* Perform text mode translation if required. */
5561 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
5563 nchars = crlf_to_lf (nchars, orig_buffer);
5564 /* If buffer contains only CR, return that. To be absolutely
5565 sure we should attempt to read the next char, but in
5566 practice a CR to be followed by LF would not appear by
5567 itself in the buffer. */
5568 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
5570 fd_info[fd].flags |= FILE_LAST_CR;
5571 nchars--;
5575 else
5576 nchars = _read (fd, buffer, count);
5578 return nchars;
5581 /* From w32xfns.c */
5582 extern HANDLE interrupt_handle;
5584 /* For now, don't bother with a non-blocking mode */
5586 sys_write (int fd, const void * buffer, unsigned int count)
5588 int nchars;
5590 if (fd < 0)
5592 errno = EBADF;
5593 return -1;
5596 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5598 if ((fd_info[fd].flags & FILE_WRITE) == 0)
5600 errno = EBADF;
5601 return -1;
5604 /* Perform text mode translation if required. */
5605 if ((fd_info[fd].flags & FILE_BINARY) == 0)
5607 char * tmpbuf = alloca (count * 2);
5608 unsigned char * src = (void *)buffer;
5609 unsigned char * dst = tmpbuf;
5610 int nbytes = count;
5612 while (1)
5614 unsigned char *next;
5615 /* copy next line or remaining bytes */
5616 next = _memccpy (dst, src, '\n', nbytes);
5617 if (next)
5619 /* copied one line ending with '\n' */
5620 int copied = next - dst;
5621 nbytes -= copied;
5622 src += copied;
5623 /* insert '\r' before '\n' */
5624 next[-1] = '\r';
5625 next[0] = '\n';
5626 dst = next + 1;
5627 count++;
5629 else
5630 /* copied remaining partial line -> now finished */
5631 break;
5633 buffer = tmpbuf;
5637 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
5639 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
5640 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
5641 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
5642 DWORD active = 0;
5644 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
5646 if (GetLastError () != ERROR_IO_PENDING)
5648 errno = EIO;
5649 return -1;
5651 if (detect_input_pending ())
5652 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
5653 QS_ALLINPUT);
5654 else
5655 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
5656 if (active == WAIT_OBJECT_0)
5657 { /* User pressed C-g, cancel write, then leave. Don't bother
5658 cleaning up as we may only get stuck in buggy drivers. */
5659 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
5660 CancelIo (hnd);
5661 errno = EIO;
5662 return -1;
5664 if (active == WAIT_OBJECT_0 + 1
5665 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
5667 errno = EIO;
5668 return -1;
5672 else
5673 #ifdef HAVE_SOCKETS
5674 if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
5676 unsigned long nblock = 0;
5677 if (winsock_lib == NULL) abort ();
5679 /* TODO: implement select() properly so non-blocking I/O works. */
5680 /* For now, make sure the write blocks. */
5681 if (fd_info[fd].flags & FILE_NDELAY)
5682 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5684 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
5686 /* Set the socket back to non-blocking if it was before,
5687 for other operations that support it. */
5688 if (fd_info[fd].flags & FILE_NDELAY)
5690 nblock = 1;
5691 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5694 if (nchars == SOCKET_ERROR)
5696 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
5697 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5698 set_errno ();
5701 else
5702 #endif
5703 nchars = _write (fd, buffer, count);
5705 return nchars;
5708 static void
5709 check_windows_init_file ()
5711 extern int noninteractive, inhibit_window_system;
5713 /* A common indication that Emacs is not installed properly is when
5714 it cannot find the Windows installation file. If this file does
5715 not exist in the expected place, tell the user. */
5717 if (!noninteractive && !inhibit_window_system)
5719 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
5720 Lisp_Object objs[2];
5721 Lisp_Object full_load_path;
5722 Lisp_Object init_file;
5723 int fd;
5725 objs[0] = Vload_path;
5726 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5727 full_load_path = Fappend (2, objs);
5728 init_file = build_string ("term/w32-win");
5729 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
5730 if (fd < 0)
5732 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
5733 char *init_file_name = SDATA (init_file);
5734 char *load_path = SDATA (load_path_print);
5735 char *buffer = alloca (1024
5736 + strlen (init_file_name)
5737 + strlen (load_path));
5739 sprintf (buffer,
5740 "The Emacs Windows initialization file \"%s.el\" "
5741 "could not be found in your Emacs installation. "
5742 "Emacs checked the following directories for this file:\n"
5743 "\n%s\n\n"
5744 "When Emacs cannot find this file, it usually means that it "
5745 "was not installed properly, or its distribution file was "
5746 "not unpacked properly.\nSee the README.W32 file in the "
5747 "top-level Emacs directory for more information.",
5748 init_file_name, load_path);
5749 MessageBox (NULL,
5750 buffer,
5751 "Emacs Abort Dialog",
5752 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
5753 /* Use the low-level Emacs abort. */
5754 #undef abort
5755 abort ();
5757 else
5759 _close (fd);
5764 void
5765 term_ntproc ()
5767 #ifdef HAVE_SOCKETS
5768 /* shutdown the socket interface if necessary */
5769 term_winsock ();
5770 #endif
5772 term_w32select ();
5775 void
5776 init_ntproc ()
5778 #ifdef HAVE_SOCKETS
5779 /* Initialise the socket interface now if available and requested by
5780 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5781 delayed until open-network-stream is called (w32-has-winsock can
5782 also be used to dynamically load or reload winsock).
5784 Conveniently, init_environment is called before us, so
5785 PRELOAD_WINSOCK can be set in the registry. */
5787 /* Always initialize this correctly. */
5788 winsock_lib = NULL;
5790 if (getenv ("PRELOAD_WINSOCK") != NULL)
5791 init_winsock (TRUE);
5792 #endif
5794 /* Initial preparation for subprocess support: replace our standard
5795 handles with non-inheritable versions. */
5797 HANDLE parent;
5798 HANDLE stdin_save = INVALID_HANDLE_VALUE;
5799 HANDLE stdout_save = INVALID_HANDLE_VALUE;
5800 HANDLE stderr_save = INVALID_HANDLE_VALUE;
5802 parent = GetCurrentProcess ();
5804 /* ignore errors when duplicating and closing; typically the
5805 handles will be invalid when running as a gui program. */
5806 DuplicateHandle (parent,
5807 GetStdHandle (STD_INPUT_HANDLE),
5808 parent,
5809 &stdin_save,
5811 FALSE,
5812 DUPLICATE_SAME_ACCESS);
5814 DuplicateHandle (parent,
5815 GetStdHandle (STD_OUTPUT_HANDLE),
5816 parent,
5817 &stdout_save,
5819 FALSE,
5820 DUPLICATE_SAME_ACCESS);
5822 DuplicateHandle (parent,
5823 GetStdHandle (STD_ERROR_HANDLE),
5824 parent,
5825 &stderr_save,
5827 FALSE,
5828 DUPLICATE_SAME_ACCESS);
5830 fclose (stdin);
5831 fclose (stdout);
5832 fclose (stderr);
5834 if (stdin_save != INVALID_HANDLE_VALUE)
5835 _open_osfhandle ((long) stdin_save, O_TEXT);
5836 else
5837 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
5838 _fdopen (0, "r");
5840 if (stdout_save != INVALID_HANDLE_VALUE)
5841 _open_osfhandle ((long) stdout_save, O_TEXT);
5842 else
5843 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5844 _fdopen (1, "w");
5846 if (stderr_save != INVALID_HANDLE_VALUE)
5847 _open_osfhandle ((long) stderr_save, O_TEXT);
5848 else
5849 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5850 _fdopen (2, "w");
5853 /* unfortunately, atexit depends on implementation of malloc */
5854 /* atexit (term_ntproc); */
5855 signal (SIGABRT, term_ntproc);
5857 /* determine which drives are fixed, for GetCachedVolumeInformation */
5859 /* GetDriveType must have trailing backslash. */
5860 char drive[] = "A:\\";
5862 /* Loop over all possible drive letters */
5863 while (*drive <= 'Z')
5865 /* Record if this drive letter refers to a fixed drive. */
5866 fixed_drives[DRIVE_INDEX (*drive)] =
5867 (GetDriveType (drive) == DRIVE_FIXED);
5869 (*drive)++;
5872 /* Reset the volume info cache. */
5873 volume_cache = NULL;
5876 /* Check to see if Emacs has been installed correctly. */
5877 check_windows_init_file ();
5881 shutdown_handler ensures that buffers' autosave files are
5882 up to date when the user logs off, or the system shuts down.
5884 BOOL WINAPI shutdown_handler(DWORD type)
5886 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5887 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
5888 || type == CTRL_LOGOFF_EVENT /* User logs off. */
5889 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
5891 /* Shut down cleanly, making sure autosave files are up to date. */
5892 shut_down_emacs (0, 0, Qnil);
5895 /* Allow other handlers to handle this signal. */
5896 return FALSE;
5900 globals_of_w32 is used to initialize those global variables that
5901 must always be initialized on startup even when the global variable
5902 initialized is non zero (see the function main in emacs.c).
5904 void
5905 globals_of_w32 ()
5907 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
5909 get_process_times_fn = (GetProcessTimes_Proc)
5910 GetProcAddress (kernel32, "GetProcessTimes");
5912 g_b_init_is_windows_9x = 0;
5913 g_b_init_open_process_token = 0;
5914 g_b_init_get_token_information = 0;
5915 g_b_init_lookup_account_sid = 0;
5916 g_b_init_get_sid_identifier_authority = 0;
5917 g_b_init_get_sid_sub_authority = 0;
5918 g_b_init_get_sid_sub_authority_count = 0;
5919 g_b_init_get_file_security = 0;
5920 g_b_init_get_security_descriptor_owner = 0;
5921 g_b_init_get_security_descriptor_group = 0;
5922 g_b_init_is_valid_sid = 0;
5923 g_b_init_create_toolhelp32_snapshot = 0;
5924 g_b_init_process32_first = 0;
5925 g_b_init_process32_next = 0;
5926 g_b_init_open_thread_token = 0;
5927 g_b_init_impersonate_self = 0;
5928 g_b_init_revert_to_self = 0;
5929 g_b_init_get_process_memory_info = 0;
5930 g_b_init_get_process_working_set_size = 0;
5931 g_b_init_global_memory_status = 0;
5932 g_b_init_global_memory_status_ex = 0;
5933 g_b_init_equal_sid = 0;
5934 g_b_init_copy_sid = 0;
5935 g_b_init_get_length_sid = 0;
5936 g_b_init_get_native_system_info = 0;
5937 g_b_init_get_system_times = 0;
5938 num_of_processors = 0;
5939 /* The following sets a handler for shutdown notifications for
5940 console apps. This actually applies to Emacs in both console and
5941 GUI modes, since we had to fool windows into thinking emacs is a
5942 console application to get console mode to work. */
5943 SetConsoleCtrlHandler(shutdown_handler, TRUE);
5945 /* "None" is the default group name on standalone workstations. */
5946 strcpy (dflt_group_name, "None");
5949 /* For make-serial-process */
5950 int serial_open (char *port)
5952 HANDLE hnd;
5953 child_process *cp;
5954 int fd = -1;
5956 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
5957 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
5958 if (hnd == INVALID_HANDLE_VALUE)
5959 error ("Could not open %s", port);
5960 fd = (int) _open_osfhandle ((int) hnd, 0);
5961 if (fd == -1)
5962 error ("Could not open %s", port);
5964 cp = new_child ();
5965 if (!cp)
5966 error ("Could not create child process");
5967 cp->fd = fd;
5968 cp->status = STATUS_READ_ACKNOWLEDGED;
5969 fd_info[ fd ].hnd = hnd;
5970 fd_info[ fd ].flags |=
5971 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
5972 if (fd_info[ fd ].cp != NULL)
5974 error ("fd_info[fd = %d] is already in use", fd);
5976 fd_info[ fd ].cp = cp;
5977 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5978 if (cp->ovl_read.hEvent == NULL)
5979 error ("Could not create read event");
5980 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5981 if (cp->ovl_write.hEvent == NULL)
5982 error ("Could not create write event");
5984 return fd;
5987 /* For serial-process-configure */
5988 void
5989 serial_configure (struct Lisp_Process *p,
5990 Lisp_Object contact)
5992 Lisp_Object childp2 = Qnil;
5993 Lisp_Object tem = Qnil;
5994 HANDLE hnd;
5995 DCB dcb;
5996 COMMTIMEOUTS ct;
5997 char summary[4] = "???"; /* This usually becomes "8N1". */
5999 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
6000 error ("Not a serial process");
6001 hnd = fd_info[ p->outfd ].hnd;
6003 childp2 = Fcopy_sequence (p->childp);
6005 /* Initialize timeouts for blocking read and blocking write. */
6006 if (!GetCommTimeouts (hnd, &ct))
6007 error ("GetCommTimeouts() failed");
6008 ct.ReadIntervalTimeout = 0;
6009 ct.ReadTotalTimeoutMultiplier = 0;
6010 ct.ReadTotalTimeoutConstant = 0;
6011 ct.WriteTotalTimeoutMultiplier = 0;
6012 ct.WriteTotalTimeoutConstant = 0;
6013 if (!SetCommTimeouts (hnd, &ct))
6014 error ("SetCommTimeouts() failed");
6015 /* Read port attributes and prepare default configuration. */
6016 memset (&dcb, 0, sizeof (dcb));
6017 dcb.DCBlength = sizeof (DCB);
6018 if (!GetCommState (hnd, &dcb))
6019 error ("GetCommState() failed");
6020 dcb.fBinary = TRUE;
6021 dcb.fNull = FALSE;
6022 dcb.fAbortOnError = FALSE;
6023 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6024 dcb.ErrorChar = 0;
6025 dcb.EofChar = 0;
6026 dcb.EvtChar = 0;
6028 /* Configure speed. */
6029 if (!NILP (Fplist_member (contact, QCspeed)))
6030 tem = Fplist_get (contact, QCspeed);
6031 else
6032 tem = Fplist_get (p->childp, QCspeed);
6033 CHECK_NUMBER (tem);
6034 dcb.BaudRate = XINT (tem);
6035 childp2 = Fplist_put (childp2, QCspeed, tem);
6037 /* Configure bytesize. */
6038 if (!NILP (Fplist_member (contact, QCbytesize)))
6039 tem = Fplist_get (contact, QCbytesize);
6040 else
6041 tem = Fplist_get (p->childp, QCbytesize);
6042 if (NILP (tem))
6043 tem = make_number (8);
6044 CHECK_NUMBER (tem);
6045 if (XINT (tem) != 7 && XINT (tem) != 8)
6046 error (":bytesize must be nil (8), 7, or 8");
6047 dcb.ByteSize = XINT (tem);
6048 summary[0] = XINT (tem) + '0';
6049 childp2 = Fplist_put (childp2, QCbytesize, tem);
6051 /* Configure parity. */
6052 if (!NILP (Fplist_member (contact, QCparity)))
6053 tem = Fplist_get (contact, QCparity);
6054 else
6055 tem = Fplist_get (p->childp, QCparity);
6056 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
6057 error (":parity must be nil (no parity), `even', or `odd'");
6058 dcb.fParity = FALSE;
6059 dcb.Parity = NOPARITY;
6060 dcb.fErrorChar = FALSE;
6061 if (NILP (tem))
6063 summary[1] = 'N';
6065 else if (EQ (tem, Qeven))
6067 summary[1] = 'E';
6068 dcb.fParity = TRUE;
6069 dcb.Parity = EVENPARITY;
6070 dcb.fErrorChar = TRUE;
6072 else if (EQ (tem, Qodd))
6074 summary[1] = 'O';
6075 dcb.fParity = TRUE;
6076 dcb.Parity = ODDPARITY;
6077 dcb.fErrorChar = TRUE;
6079 childp2 = Fplist_put (childp2, QCparity, tem);
6081 /* Configure stopbits. */
6082 if (!NILP (Fplist_member (contact, QCstopbits)))
6083 tem = Fplist_get (contact, QCstopbits);
6084 else
6085 tem = Fplist_get (p->childp, QCstopbits);
6086 if (NILP (tem))
6087 tem = make_number (1);
6088 CHECK_NUMBER (tem);
6089 if (XINT (tem) != 1 && XINT (tem) != 2)
6090 error (":stopbits must be nil (1 stopbit), 1, or 2");
6091 summary[2] = XINT (tem) + '0';
6092 if (XINT (tem) == 1)
6093 dcb.StopBits = ONESTOPBIT;
6094 else if (XINT (tem) == 2)
6095 dcb.StopBits = TWOSTOPBITS;
6096 childp2 = Fplist_put (childp2, QCstopbits, tem);
6098 /* Configure flowcontrol. */
6099 if (!NILP (Fplist_member (contact, QCflowcontrol)))
6100 tem = Fplist_get (contact, QCflowcontrol);
6101 else
6102 tem = Fplist_get (p->childp, QCflowcontrol);
6103 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
6104 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6105 dcb.fOutxCtsFlow = FALSE;
6106 dcb.fOutxDsrFlow = FALSE;
6107 dcb.fDtrControl = DTR_CONTROL_DISABLE;
6108 dcb.fDsrSensitivity = FALSE;
6109 dcb.fTXContinueOnXoff = FALSE;
6110 dcb.fOutX = FALSE;
6111 dcb.fInX = FALSE;
6112 dcb.fRtsControl = RTS_CONTROL_DISABLE;
6113 dcb.XonChar = 17; /* Control-Q */
6114 dcb.XoffChar = 19; /* Control-S */
6115 if (NILP (tem))
6117 /* Already configured. */
6119 else if (EQ (tem, Qhw))
6121 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
6122 dcb.fOutxCtsFlow = TRUE;
6124 else if (EQ (tem, Qsw))
6126 dcb.fOutX = TRUE;
6127 dcb.fInX = TRUE;
6129 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
6131 /* Activate configuration. */
6132 if (!SetCommState (hnd, &dcb))
6133 error ("SetCommState() failed");
6135 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
6136 p->childp = childp2;
6139 /* end of w32.c */
6141 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
6142 (do not change this comment) */