ChangeLog fixes.
[emacs.git] / src / w32.c
blobf1ed6ae0be9e1cab60b2838367a80f0f73bec7b7
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"
144 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
145 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
147 void globals_of_w32 (void);
148 static DWORD get_rid (PSID);
150 extern Lisp_Object Vw32_downcase_file_names;
151 extern Lisp_Object Vw32_generate_fake_inodes;
152 extern Lisp_Object Vw32_get_true_file_attributes;
153 /* Defined in process.c for its own purpose. */
154 extern Lisp_Object Qlocal;
156 extern int w32_num_mouse_buttons;
159 /* Initialization states.
161 WARNING: If you add any more such variables for additional APIs,
162 you MUST add initialization for them to globals_of_w32
163 below. This is because these variables might get set
164 to non-NULL values during dumping, but the dumped Emacs
165 cannot reuse those values, because it could be run on a
166 different version of the OS, where API addresses are
167 different. */
168 static BOOL g_b_init_is_windows_9x;
169 static BOOL g_b_init_open_process_token;
170 static BOOL g_b_init_get_token_information;
171 static BOOL g_b_init_lookup_account_sid;
172 static BOOL g_b_init_get_sid_identifier_authority;
173 static BOOL g_b_init_get_sid_sub_authority;
174 static BOOL g_b_init_get_sid_sub_authority_count;
175 static BOOL g_b_init_get_file_security;
176 static BOOL g_b_init_get_security_descriptor_owner;
177 static BOOL g_b_init_get_security_descriptor_group;
178 static BOOL g_b_init_is_valid_sid;
179 static BOOL g_b_init_create_toolhelp32_snapshot;
180 static BOOL g_b_init_process32_first;
181 static BOOL g_b_init_process32_next;
182 static BOOL g_b_init_open_thread_token;
183 static BOOL g_b_init_impersonate_self;
184 static BOOL g_b_init_revert_to_self;
185 static BOOL g_b_init_get_process_memory_info;
186 static BOOL g_b_init_get_process_working_set_size;
187 static BOOL g_b_init_global_memory_status;
188 static BOOL g_b_init_global_memory_status_ex;
189 static BOOL g_b_init_get_length_sid;
190 static BOOL g_b_init_equal_sid;
191 static BOOL g_b_init_copy_sid;
192 static BOOL g_b_init_get_native_system_info;
193 static BOOL g_b_init_get_system_times;
196 BEGIN: Wrapper functions around OpenProcessToken
197 and other functions in advapi32.dll that are only
198 supported in Windows NT / 2k / XP
200 /* ** Function pointer typedefs ** */
201 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
202 HANDLE ProcessHandle,
203 DWORD DesiredAccess,
204 PHANDLE TokenHandle);
205 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
206 HANDLE TokenHandle,
207 TOKEN_INFORMATION_CLASS TokenInformationClass,
208 LPVOID TokenInformation,
209 DWORD TokenInformationLength,
210 PDWORD ReturnLength);
211 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
212 HANDLE process_handle,
213 LPFILETIME creation_time,
214 LPFILETIME exit_time,
215 LPFILETIME kernel_time,
216 LPFILETIME user_time);
218 GetProcessTimes_Proc get_process_times_fn = NULL;
220 #ifdef _UNICODE
221 const char * const LookupAccountSid_Name = "LookupAccountSidW";
222 const char * const GetFileSecurity_Name = "GetFileSecurityW";
223 #else
224 const char * const LookupAccountSid_Name = "LookupAccountSidA";
225 const char * const GetFileSecurity_Name = "GetFileSecurityA";
226 #endif
227 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
228 LPCTSTR lpSystemName,
229 PSID Sid,
230 LPTSTR Name,
231 LPDWORD cbName,
232 LPTSTR DomainName,
233 LPDWORD cbDomainName,
234 PSID_NAME_USE peUse);
235 typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) (
236 PSID pSid);
237 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
238 PSID pSid,
239 DWORD n);
240 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
241 PSID pSid);
242 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
243 LPCTSTR lpFileName,
244 SECURITY_INFORMATION RequestedInformation,
245 PSECURITY_DESCRIPTOR pSecurityDescriptor,
246 DWORD nLength,
247 LPDWORD lpnLengthNeeded);
248 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
249 PSECURITY_DESCRIPTOR pSecurityDescriptor,
250 PSID *pOwner,
251 LPBOOL lpbOwnerDefaulted);
252 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
253 PSECURITY_DESCRIPTOR pSecurityDescriptor,
254 PSID *pGroup,
255 LPBOOL lpbGroupDefaulted);
256 typedef BOOL (WINAPI * IsValidSid_Proc) (
257 PSID sid);
258 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
259 DWORD dwFlags,
260 DWORD th32ProcessID);
261 typedef BOOL (WINAPI * Process32First_Proc) (
262 HANDLE hSnapshot,
263 LPPROCESSENTRY32 lppe);
264 typedef BOOL (WINAPI * Process32Next_Proc) (
265 HANDLE hSnapshot,
266 LPPROCESSENTRY32 lppe);
267 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
268 HANDLE ThreadHandle,
269 DWORD DesiredAccess,
270 BOOL OpenAsSelf,
271 PHANDLE TokenHandle);
272 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
273 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
274 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
275 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
276 HANDLE Process,
277 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
278 DWORD cb);
279 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
280 HANDLE hProcess,
281 DWORD * lpMinimumWorkingSetSize,
282 DWORD * lpMaximumWorkingSetSize);
283 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
284 LPMEMORYSTATUS lpBuffer);
285 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
286 LPMEMORY_STATUS_EX lpBuffer);
287 typedef BOOL (WINAPI * CopySid_Proc) (
288 DWORD nDestinationSidLength,
289 PSID pDestinationSid,
290 PSID pSourceSid);
291 typedef BOOL (WINAPI * EqualSid_Proc) (
292 PSID pSid1,
293 PSID pSid2);
294 typedef DWORD (WINAPI * GetLengthSid_Proc) (
295 PSID pSid);
296 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
297 LPSYSTEM_INFO lpSystemInfo);
298 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
299 LPFILETIME lpIdleTime,
300 LPFILETIME lpKernelTime,
301 LPFILETIME lpUserTime);
305 /* ** A utility function ** */
306 static BOOL
307 is_windows_9x (void)
309 static BOOL s_b_ret=0;
310 OSVERSIONINFO os_ver;
311 if (g_b_init_is_windows_9x == 0)
313 g_b_init_is_windows_9x = 1;
314 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
315 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
316 if (GetVersionEx (&os_ver))
318 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
321 return s_b_ret;
324 /* Get total user and system times for get-internal-run-time.
325 Returns a list of three integers if the times are provided by the OS
326 (NT derivatives), otherwise it returns the result of current-time. */
327 Lisp_Object
328 w32_get_internal_run_time (void)
330 if (get_process_times_fn)
332 FILETIME create, exit, kernel, user;
333 HANDLE proc = GetCurrentProcess ();
334 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
336 LARGE_INTEGER user_int, kernel_int, total;
337 int microseconds;
338 user_int.LowPart = user.dwLowDateTime;
339 user_int.HighPart = user.dwHighDateTime;
340 kernel_int.LowPart = kernel.dwLowDateTime;
341 kernel_int.HighPart = kernel.dwHighDateTime;
342 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
343 /* FILETIME is 100 nanosecond increments, Emacs only wants
344 microsecond resolution. */
345 total.QuadPart /= 10;
346 microseconds = total.QuadPart % 1000000;
347 total.QuadPart /= 1000000;
349 /* Sanity check to make sure we can represent the result. */
350 if (total.HighPart == 0)
352 int secs = total.LowPart;
354 return list3 (make_number ((secs >> 16) & 0xffff),
355 make_number (secs & 0xffff),
356 make_number (microseconds));
361 return Fcurrent_time ();
364 /* ** The wrapper functions ** */
366 BOOL WINAPI open_process_token (
367 HANDLE ProcessHandle,
368 DWORD DesiredAccess,
369 PHANDLE TokenHandle)
371 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
372 HMODULE hm_advapi32 = NULL;
373 if (is_windows_9x () == TRUE)
375 return FALSE;
377 if (g_b_init_open_process_token == 0)
379 g_b_init_open_process_token = 1;
380 hm_advapi32 = LoadLibrary ("Advapi32.dll");
381 s_pfn_Open_Process_Token =
382 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
384 if (s_pfn_Open_Process_Token == NULL)
386 return FALSE;
388 return (
389 s_pfn_Open_Process_Token (
390 ProcessHandle,
391 DesiredAccess,
392 TokenHandle)
396 BOOL WINAPI get_token_information (
397 HANDLE TokenHandle,
398 TOKEN_INFORMATION_CLASS TokenInformationClass,
399 LPVOID TokenInformation,
400 DWORD TokenInformationLength,
401 PDWORD ReturnLength)
403 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
404 HMODULE hm_advapi32 = NULL;
405 if (is_windows_9x () == TRUE)
407 return FALSE;
409 if (g_b_init_get_token_information == 0)
411 g_b_init_get_token_information = 1;
412 hm_advapi32 = LoadLibrary ("Advapi32.dll");
413 s_pfn_Get_Token_Information =
414 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
416 if (s_pfn_Get_Token_Information == NULL)
418 return FALSE;
420 return (
421 s_pfn_Get_Token_Information (
422 TokenHandle,
423 TokenInformationClass,
424 TokenInformation,
425 TokenInformationLength,
426 ReturnLength)
430 BOOL WINAPI lookup_account_sid (
431 LPCTSTR lpSystemName,
432 PSID Sid,
433 LPTSTR Name,
434 LPDWORD cbName,
435 LPTSTR DomainName,
436 LPDWORD cbDomainName,
437 PSID_NAME_USE peUse)
439 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
440 HMODULE hm_advapi32 = NULL;
441 if (is_windows_9x () == TRUE)
443 return FALSE;
445 if (g_b_init_lookup_account_sid == 0)
447 g_b_init_lookup_account_sid = 1;
448 hm_advapi32 = LoadLibrary ("Advapi32.dll");
449 s_pfn_Lookup_Account_Sid =
450 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
452 if (s_pfn_Lookup_Account_Sid == NULL)
454 return FALSE;
456 return (
457 s_pfn_Lookup_Account_Sid (
458 lpSystemName,
459 Sid,
460 Name,
461 cbName,
462 DomainName,
463 cbDomainName,
464 peUse)
468 PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority (
469 PSID pSid)
471 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority = NULL;
472 HMODULE hm_advapi32 = NULL;
473 if (is_windows_9x () == TRUE)
475 return NULL;
477 if (g_b_init_get_sid_identifier_authority == 0)
479 g_b_init_get_sid_identifier_authority = 1;
480 hm_advapi32 = LoadLibrary ("Advapi32.dll");
481 s_pfn_Get_Sid_Identifier_Authority =
482 (GetSidIdentifierAuthority_Proc) GetProcAddress (
483 hm_advapi32, "GetSidIdentifierAuthority");
485 if (s_pfn_Get_Sid_Identifier_Authority == NULL)
487 return NULL;
489 return (s_pfn_Get_Sid_Identifier_Authority (pSid));
492 PDWORD WINAPI get_sid_sub_authority (
493 PSID pSid,
494 DWORD n)
496 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
497 static DWORD zero = 0U;
498 HMODULE hm_advapi32 = NULL;
499 if (is_windows_9x () == TRUE)
501 return &zero;
503 if (g_b_init_get_sid_sub_authority == 0)
505 g_b_init_get_sid_sub_authority = 1;
506 hm_advapi32 = LoadLibrary ("Advapi32.dll");
507 s_pfn_Get_Sid_Sub_Authority =
508 (GetSidSubAuthority_Proc) GetProcAddress (
509 hm_advapi32, "GetSidSubAuthority");
511 if (s_pfn_Get_Sid_Sub_Authority == NULL)
513 return &zero;
515 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
518 PUCHAR WINAPI get_sid_sub_authority_count (
519 PSID pSid)
521 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
522 static UCHAR zero = 0U;
523 HMODULE hm_advapi32 = NULL;
524 if (is_windows_9x () == TRUE)
526 return &zero;
528 if (g_b_init_get_sid_sub_authority_count == 0)
530 g_b_init_get_sid_sub_authority_count = 1;
531 hm_advapi32 = LoadLibrary ("Advapi32.dll");
532 s_pfn_Get_Sid_Sub_Authority_Count =
533 (GetSidSubAuthorityCount_Proc) GetProcAddress (
534 hm_advapi32, "GetSidSubAuthorityCount");
536 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
538 return &zero;
540 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
543 BOOL WINAPI get_file_security (
544 LPCTSTR lpFileName,
545 SECURITY_INFORMATION RequestedInformation,
546 PSECURITY_DESCRIPTOR pSecurityDescriptor,
547 DWORD nLength,
548 LPDWORD lpnLengthNeeded)
550 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
551 HMODULE hm_advapi32 = NULL;
552 if (is_windows_9x () == TRUE)
554 return FALSE;
556 if (g_b_init_get_file_security == 0)
558 g_b_init_get_file_security = 1;
559 hm_advapi32 = LoadLibrary ("Advapi32.dll");
560 s_pfn_Get_File_Security =
561 (GetFileSecurity_Proc) GetProcAddress (
562 hm_advapi32, GetFileSecurity_Name);
564 if (s_pfn_Get_File_Security == NULL)
566 return FALSE;
568 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
569 pSecurityDescriptor, nLength,
570 lpnLengthNeeded));
573 BOOL WINAPI get_security_descriptor_owner (
574 PSECURITY_DESCRIPTOR pSecurityDescriptor,
575 PSID *pOwner,
576 LPBOOL lpbOwnerDefaulted)
578 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
579 HMODULE hm_advapi32 = NULL;
580 if (is_windows_9x () == TRUE)
582 return FALSE;
584 if (g_b_init_get_security_descriptor_owner == 0)
586 g_b_init_get_security_descriptor_owner = 1;
587 hm_advapi32 = LoadLibrary ("Advapi32.dll");
588 s_pfn_Get_Security_Descriptor_Owner =
589 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
590 hm_advapi32, "GetSecurityDescriptorOwner");
592 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
594 return FALSE;
596 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
597 lpbOwnerDefaulted));
600 BOOL WINAPI get_security_descriptor_group (
601 PSECURITY_DESCRIPTOR pSecurityDescriptor,
602 PSID *pGroup,
603 LPBOOL lpbGroupDefaulted)
605 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
606 HMODULE hm_advapi32 = NULL;
607 if (is_windows_9x () == TRUE)
609 return FALSE;
611 if (g_b_init_get_security_descriptor_group == 0)
613 g_b_init_get_security_descriptor_group = 1;
614 hm_advapi32 = LoadLibrary ("Advapi32.dll");
615 s_pfn_Get_Security_Descriptor_Group =
616 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
617 hm_advapi32, "GetSecurityDescriptorGroup");
619 if (s_pfn_Get_Security_Descriptor_Group == NULL)
621 return FALSE;
623 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
624 lpbGroupDefaulted));
627 BOOL WINAPI is_valid_sid (
628 PSID sid)
630 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
631 HMODULE hm_advapi32 = NULL;
632 if (is_windows_9x () == TRUE)
634 return FALSE;
636 if (g_b_init_is_valid_sid == 0)
638 g_b_init_is_valid_sid = 1;
639 hm_advapi32 = LoadLibrary ("Advapi32.dll");
640 s_pfn_Is_Valid_Sid =
641 (IsValidSid_Proc) GetProcAddress (
642 hm_advapi32, "IsValidSid");
644 if (s_pfn_Is_Valid_Sid == NULL)
646 return FALSE;
648 return (s_pfn_Is_Valid_Sid (sid));
651 BOOL WINAPI equal_sid (
652 PSID sid1,
653 PSID sid2)
655 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
656 HMODULE hm_advapi32 = NULL;
657 if (is_windows_9x () == TRUE)
659 return FALSE;
661 if (g_b_init_equal_sid == 0)
663 g_b_init_equal_sid = 1;
664 hm_advapi32 = LoadLibrary ("Advapi32.dll");
665 s_pfn_Equal_Sid =
666 (EqualSid_Proc) GetProcAddress (
667 hm_advapi32, "EqualSid");
669 if (s_pfn_Equal_Sid == NULL)
671 return FALSE;
673 return (s_pfn_Equal_Sid (sid1, sid2));
676 DWORD WINAPI get_length_sid (
677 PSID sid)
679 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
680 HMODULE hm_advapi32 = NULL;
681 if (is_windows_9x () == TRUE)
683 return 0;
685 if (g_b_init_get_length_sid == 0)
687 g_b_init_get_length_sid = 1;
688 hm_advapi32 = LoadLibrary ("Advapi32.dll");
689 s_pfn_Get_Length_Sid =
690 (GetLengthSid_Proc) GetProcAddress (
691 hm_advapi32, "GetLengthSid");
693 if (s_pfn_Get_Length_Sid == NULL)
695 return 0;
697 return (s_pfn_Get_Length_Sid (sid));
700 BOOL WINAPI copy_sid (
701 DWORD destlen,
702 PSID dest,
703 PSID src)
705 static CopySid_Proc s_pfn_Copy_Sid = NULL;
706 HMODULE hm_advapi32 = NULL;
707 if (is_windows_9x () == TRUE)
709 return FALSE;
711 if (g_b_init_copy_sid == 0)
713 g_b_init_copy_sid = 1;
714 hm_advapi32 = LoadLibrary ("Advapi32.dll");
715 s_pfn_Copy_Sid =
716 (CopySid_Proc) GetProcAddress (
717 hm_advapi32, "CopySid");
719 if (s_pfn_Copy_Sid == NULL)
721 return FALSE;
723 return (s_pfn_Copy_Sid (destlen, dest, src));
727 END: Wrapper functions around OpenProcessToken
728 and other functions in advapi32.dll that are only
729 supported in Windows NT / 2k / XP
732 void WINAPI get_native_system_info (
733 LPSYSTEM_INFO lpSystemInfo)
735 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
736 if (is_windows_9x () != TRUE)
738 if (g_b_init_get_native_system_info == 0)
740 g_b_init_get_native_system_info = 1;
741 s_pfn_Get_Native_System_Info =
742 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
743 "GetNativeSystemInfo");
745 if (s_pfn_Get_Native_System_Info != NULL)
746 s_pfn_Get_Native_System_Info (lpSystemInfo);
748 else
749 lpSystemInfo->dwNumberOfProcessors = -1;
752 BOOL WINAPI get_system_times (
753 LPFILETIME lpIdleTime,
754 LPFILETIME lpKernelTime,
755 LPFILETIME lpUserTime)
757 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
758 if (is_windows_9x () == TRUE)
760 return FALSE;
762 if (g_b_init_get_system_times == 0)
764 g_b_init_get_system_times = 1;
765 s_pfn_Get_System_times =
766 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
767 "GetSystemTimes");
769 if (s_pfn_Get_System_times == NULL)
770 return FALSE;
771 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
774 /* Equivalent of strerror for W32 error codes. */
775 char *
776 w32_strerror (int error_no)
778 static char buf[500];
780 if (error_no == 0)
781 error_no = GetLastError ();
783 buf[0] = '\0';
784 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
785 error_no,
786 0, /* choose most suitable language */
787 buf, sizeof (buf), NULL))
788 sprintf (buf, "w32 error %u", error_no);
789 return buf;
792 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
793 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
795 This is called from alloc.c:valid_pointer_p. */
797 w32_valid_pointer_p (void *p, int size)
799 SIZE_T done;
800 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
802 if (h)
804 unsigned char *buf = alloca (size);
805 int retval = ReadProcessMemory (h, p, buf, size, &done);
807 CloseHandle (h);
808 return retval;
810 else
811 return -1;
814 static char startup_dir[MAXPATHLEN];
816 /* Get the current working directory. */
817 char *
818 getwd (char *dir)
820 #if 0
821 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
822 return dir;
823 return NULL;
824 #else
825 /* Emacs doesn't actually change directory itself, and we want to
826 force our real wd to be where emacs.exe is to avoid unnecessary
827 conflicts when trying to rename or delete directories. */
828 strcpy (dir, startup_dir);
829 return dir;
830 #endif
833 #ifndef HAVE_SOCKETS
834 /* Emulate gethostname. */
836 gethostname (char *buffer, int size)
838 /* NT only allows small host names, so the buffer is
839 certainly large enough. */
840 return !GetComputerName (buffer, &size);
842 #endif /* HAVE_SOCKETS */
844 /* Emulate getloadavg. */
846 struct load_sample {
847 time_t sample_time;
848 ULONGLONG idle;
849 ULONGLONG kernel;
850 ULONGLONG user;
853 /* Number of processors on this machine. */
854 static unsigned num_of_processors;
856 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
857 static struct load_sample samples[16*60];
858 static int first_idx = -1, last_idx = -1;
859 static int max_idx = sizeof (samples) / sizeof (samples[0]);
861 static int
862 buf_next (int from)
864 int next_idx = from + 1;
866 if (next_idx >= max_idx)
867 next_idx = 0;
869 return next_idx;
872 static int
873 buf_prev (int from)
875 int prev_idx = from - 1;
877 if (prev_idx < 0)
878 prev_idx = max_idx - 1;
880 return prev_idx;
883 static void
884 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
886 SYSTEM_INFO sysinfo;
887 FILETIME ft_idle, ft_user, ft_kernel;
889 /* Initialize the number of processors on this machine. */
890 if (num_of_processors <= 0)
892 get_native_system_info (&sysinfo);
893 num_of_processors = sysinfo.dwNumberOfProcessors;
894 if (num_of_processors <= 0)
896 GetSystemInfo (&sysinfo);
897 num_of_processors = sysinfo.dwNumberOfProcessors;
899 if (num_of_processors <= 0)
900 num_of_processors = 1;
903 /* TODO: Take into account threads that are ready to run, by
904 sampling the "\System\Processor Queue Length" performance
905 counter. The code below accounts only for threads that are
906 actually running. */
908 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
910 ULARGE_INTEGER uidle, ukernel, uuser;
912 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
913 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
914 memcpy (&uuser, &ft_user, sizeof (ft_user));
915 *idle = uidle.QuadPart;
916 *kernel = ukernel.QuadPart;
917 *user = uuser.QuadPart;
919 else
921 *idle = 0;
922 *kernel = 0;
923 *user = 0;
927 /* Produce the load average for a given time interval, using the
928 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
929 1-minute, 5-minute, or 15-minute average, respectively. */
930 static double
931 getavg (int which)
933 double retval = -1.0;
934 double tdiff;
935 int idx;
936 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
937 time_t now = samples[last_idx].sample_time;
939 if (first_idx != last_idx)
941 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
943 tdiff = difftime (now, samples[idx].sample_time);
944 if (tdiff >= span - 2*DBL_EPSILON*now)
946 long double sys =
947 samples[last_idx].kernel + samples[last_idx].user
948 - (samples[idx].kernel + samples[idx].user);
949 long double idl = samples[last_idx].idle - samples[idx].idle;
951 retval = (1.0 - idl / sys) * num_of_processors;
952 break;
954 if (idx == first_idx)
955 break;
959 return retval;
963 getloadavg (double loadavg[], int nelem)
965 int elem;
966 ULONGLONG idle, kernel, user;
967 time_t now = time (NULL);
969 /* Store another sample. We ignore samples that are less than 1 sec
970 apart. */
971 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
973 sample_system_load (&idle, &kernel, &user);
974 last_idx = buf_next (last_idx);
975 samples[last_idx].sample_time = now;
976 samples[last_idx].idle = idle;
977 samples[last_idx].kernel = kernel;
978 samples[last_idx].user = user;
979 /* If the buffer has more that 15 min worth of samples, discard
980 the old ones. */
981 if (first_idx == -1)
982 first_idx = last_idx;
983 while (first_idx != last_idx
984 && (difftime (now, samples[first_idx].sample_time)
985 >= 15.0*60 + 2*DBL_EPSILON*now))
986 first_idx = buf_next (first_idx);
989 for (elem = 0; elem < nelem; elem++)
991 double avg = getavg (elem);
993 if (avg < 0)
994 break;
995 loadavg[elem] = avg;
998 return elem;
1001 /* Emulate getpwuid, getpwnam and others. */
1003 #define PASSWD_FIELD_SIZE 256
1005 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1006 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1007 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1008 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
1009 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
1011 static struct passwd dflt_passwd =
1013 dflt_passwd_name,
1014 dflt_passwd_passwd,
1018 dflt_passwd_gecos,
1019 dflt_passwd_dir,
1020 dflt_passwd_shell,
1023 static char dflt_group_name[GNLEN+1];
1025 static struct group dflt_group =
1027 /* When group information is not available, we return this as the
1028 group for all files. */
1029 dflt_group_name,
1033 unsigned
1034 getuid (void)
1036 return dflt_passwd.pw_uid;
1039 unsigned
1040 geteuid (void)
1042 /* I could imagine arguing for checking to see whether the user is
1043 in the Administrators group and returning a UID of 0 for that
1044 case, but I don't know how wise that would be in the long run. */
1045 return getuid ();
1048 unsigned
1049 getgid (void)
1051 return dflt_passwd.pw_gid;
1054 unsigned
1055 getegid (void)
1057 return getgid ();
1060 struct passwd *
1061 getpwuid (unsigned uid)
1063 if (uid == dflt_passwd.pw_uid)
1064 return &dflt_passwd;
1065 return NULL;
1068 struct group *
1069 getgrgid (gid_t gid)
1071 return &dflt_group;
1074 struct passwd *
1075 getpwnam (char *name)
1077 struct passwd *pw;
1079 pw = getpwuid (getuid ());
1080 if (!pw)
1081 return pw;
1083 if (xstrcasecmp (name, pw->pw_name))
1084 return NULL;
1086 return pw;
1089 void
1090 init_user_info (void)
1092 /* Find the user's real name by opening the process token and
1093 looking up the name associated with the user-sid in that token.
1095 Use the relative portion of the identifier authority value from
1096 the user-sid as the user id value (same for group id using the
1097 primary group sid from the process token). */
1099 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1100 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1101 DWORD glength = sizeof (gname);
1102 HANDLE token = NULL;
1103 SID_NAME_USE user_type;
1104 unsigned char *buf = NULL;
1105 DWORD blen = 0;
1106 TOKEN_USER user_token;
1107 TOKEN_PRIMARY_GROUP group_token;
1108 BOOL result;
1110 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1111 if (result)
1113 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1114 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1116 buf = xmalloc (blen);
1117 result = get_token_information (token, TokenUser,
1118 (LPVOID)buf, blen, &needed);
1119 if (result)
1121 memcpy (&user_token, buf, sizeof (user_token));
1122 result = lookup_account_sid (NULL, user_token.User.Sid,
1123 uname, &ulength,
1124 domain, &dlength, &user_type);
1127 else
1128 result = FALSE;
1130 if (result)
1132 strcpy (dflt_passwd.pw_name, uname);
1133 /* Determine a reasonable uid value. */
1134 if (xstrcasecmp ("administrator", uname) == 0)
1136 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1137 dflt_passwd.pw_gid = 513; /* well-known None gid */
1139 else
1141 /* Use the last sub-authority value of the RID, the relative
1142 portion of the SID, as user/group ID. */
1143 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1145 /* Get group id and name. */
1146 result = get_token_information (token, TokenPrimaryGroup,
1147 (LPVOID)buf, blen, &needed);
1148 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1150 buf = xrealloc (buf, blen = needed);
1151 result = get_token_information (token, TokenPrimaryGroup,
1152 (LPVOID)buf, blen, &needed);
1154 if (result)
1156 memcpy (&group_token, buf, sizeof (group_token));
1157 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1158 dlength = sizeof (domain);
1159 /* If we can get at the real Primary Group name, use that.
1160 Otherwise, the default group name was already set to
1161 "None" in globals_of_w32. */
1162 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1163 gname, &glength, NULL, &dlength,
1164 &user_type))
1165 strcpy (dflt_group_name, gname);
1167 else
1168 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1171 /* If security calls are not supported (presumably because we
1172 are running under Windows 9X), fallback to this: */
1173 else if (GetUserName (uname, &ulength))
1175 strcpy (dflt_passwd.pw_name, uname);
1176 if (xstrcasecmp ("administrator", uname) == 0)
1177 dflt_passwd.pw_uid = 0;
1178 else
1179 dflt_passwd.pw_uid = 123;
1180 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1182 else
1184 strcpy (dflt_passwd.pw_name, "unknown");
1185 dflt_passwd.pw_uid = 123;
1186 dflt_passwd.pw_gid = 123;
1188 dflt_group.gr_gid = dflt_passwd.pw_gid;
1190 /* Ensure HOME and SHELL are defined. */
1191 if (getenv ("HOME") == NULL)
1192 abort ();
1193 if (getenv ("SHELL") == NULL)
1194 abort ();
1196 /* Set dir and shell from environment variables. */
1197 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1198 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1200 xfree (buf);
1201 if (token)
1202 CloseHandle (token);
1206 random (void)
1208 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1209 return ((rand () << 15) | rand ());
1212 void
1213 srandom (int seed)
1215 srand (seed);
1219 /* Normalize filename by converting all path separators to
1220 the specified separator. Also conditionally convert upper
1221 case path name components to lower case. */
1223 static void
1224 normalize_filename (register char *fp, char path_sep)
1226 char sep;
1227 char *elem;
1229 /* Always lower-case drive letters a-z, even if the filesystem
1230 preserves case in filenames.
1231 This is so filenames can be compared by string comparison
1232 functions that are case-sensitive. Even case-preserving filesystems
1233 do not distinguish case in drive letters. */
1234 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
1236 *fp += 'a' - 'A';
1237 fp += 2;
1240 if (NILP (Vw32_downcase_file_names))
1242 while (*fp)
1244 if (*fp == '/' || *fp == '\\')
1245 *fp = path_sep;
1246 fp++;
1248 return;
1251 sep = path_sep; /* convert to this path separator */
1252 elem = fp; /* start of current path element */
1254 do {
1255 if (*fp >= 'a' && *fp <= 'z')
1256 elem = 0; /* don't convert this element */
1258 if (*fp == 0 || *fp == ':')
1260 sep = *fp; /* restore current separator (or 0) */
1261 *fp = '/'; /* after conversion of this element */
1264 if (*fp == '/' || *fp == '\\')
1266 if (elem && elem != fp)
1268 *fp = 0; /* temporary end of string */
1269 _strlwr (elem); /* while we convert to lower case */
1271 *fp = sep; /* convert (or restore) path separator */
1272 elem = fp + 1; /* next element starts after separator */
1273 sep = path_sep;
1275 } while (*fp++);
1278 /* Destructively turn backslashes into slashes. */
1279 void
1280 dostounix_filename (register char *p)
1282 normalize_filename (p, '/');
1285 /* Destructively turn slashes into backslashes. */
1286 void
1287 unixtodos_filename (register char *p)
1289 normalize_filename (p, '\\');
1292 /* Remove all CR's that are followed by a LF.
1293 (From msdos.c...probably should figure out a way to share it,
1294 although this code isn't going to ever change.) */
1296 crlf_to_lf (register int n, register unsigned char *buf)
1298 unsigned char *np = buf;
1299 unsigned char *startp = buf;
1300 unsigned char *endp = buf + n;
1302 if (n == 0)
1303 return n;
1304 while (buf < endp - 1)
1306 if (*buf == 0x0d)
1308 if (*(++buf) != 0x0a)
1309 *np++ = 0x0d;
1311 else
1312 *np++ = *buf++;
1314 if (buf < endp)
1315 *np++ = *buf++;
1316 return np - startp;
1319 /* Parse the root part of file name, if present. Return length and
1320 optionally store pointer to char after root. */
1321 static int
1322 parse_root (char * name, char ** pPath)
1324 char * start = name;
1326 if (name == NULL)
1327 return 0;
1329 /* find the root name of the volume if given */
1330 if (isalpha (name[0]) && name[1] == ':')
1332 /* skip past drive specifier */
1333 name += 2;
1334 if (IS_DIRECTORY_SEP (name[0]))
1335 name++;
1337 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1339 int slashes = 2;
1340 name += 2;
1343 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1344 break;
1345 name++;
1347 while ( *name );
1348 if (IS_DIRECTORY_SEP (name[0]))
1349 name++;
1352 if (pPath)
1353 *pPath = name;
1355 return name - start;
1358 /* Get long base name for name; name is assumed to be absolute. */
1359 static int
1360 get_long_basename (char * name, char * buf, int size)
1362 WIN32_FIND_DATA find_data;
1363 HANDLE dir_handle;
1364 int len = 0;
1366 /* must be valid filename, no wild cards or other invalid characters */
1367 if (_mbspbrk (name, "*?|<>\""))
1368 return 0;
1370 dir_handle = FindFirstFile (name, &find_data);
1371 if (dir_handle != INVALID_HANDLE_VALUE)
1373 if ((len = strlen (find_data.cFileName)) < size)
1374 memcpy (buf, find_data.cFileName, len + 1);
1375 else
1376 len = 0;
1377 FindClose (dir_handle);
1379 return len;
1382 /* Get long name for file, if possible (assumed to be absolute). */
1383 BOOL
1384 w32_get_long_filename (char * name, char * buf, int size)
1386 char * o = buf;
1387 char * p;
1388 char * q;
1389 char full[ MAX_PATH ];
1390 int len;
1392 len = strlen (name);
1393 if (len >= MAX_PATH)
1394 return FALSE;
1396 /* Use local copy for destructive modification. */
1397 memcpy (full, name, len+1);
1398 unixtodos_filename (full);
1400 /* Copy root part verbatim. */
1401 len = parse_root (full, &p);
1402 memcpy (o, full, len);
1403 o += len;
1404 *o = '\0';
1405 size -= len;
1407 while (p != NULL && *p)
1409 q = p;
1410 p = strchr (q, '\\');
1411 if (p) *p = '\0';
1412 len = get_long_basename (full, o, size);
1413 if (len > 0)
1415 o += len;
1416 size -= len;
1417 if (p != NULL)
1419 *p++ = '\\';
1420 if (size < 2)
1421 return FALSE;
1422 *o++ = '\\';
1423 size--;
1424 *o = '\0';
1427 else
1428 return FALSE;
1431 return TRUE;
1435 is_unc_volume (const char *filename)
1437 const char *ptr = filename;
1439 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1440 return 0;
1442 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1443 return 0;
1445 return 1;
1448 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1451 sigsetmask (int signal_mask)
1453 return 0;
1457 sigmask (int sig)
1459 return 0;
1463 sigblock (int sig)
1465 return 0;
1469 sigunblock (int sig)
1471 return 0;
1475 sigemptyset (sigset_t *set)
1477 return 0;
1481 sigaddset (sigset_t *set, int signo)
1483 return 0;
1487 sigfillset (sigset_t *set)
1489 return 0;
1493 sigprocmask (int how, const sigset_t *set, sigset_t *oset)
1495 return 0;
1499 setpgrp (int pid, int gid)
1501 return 0;
1505 alarm (int seconds)
1507 return 0;
1510 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1512 LPBYTE
1513 w32_get_resource (char *key, LPDWORD lpdwtype)
1515 LPBYTE lpvalue;
1516 HKEY hrootkey = NULL;
1517 DWORD cbData;
1519 /* Check both the current user and the local machine to see if
1520 we have any resources. */
1522 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1524 lpvalue = NULL;
1526 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1527 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1528 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1530 RegCloseKey (hrootkey);
1531 return (lpvalue);
1534 xfree (lpvalue);
1536 RegCloseKey (hrootkey);
1539 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1541 lpvalue = NULL;
1543 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1544 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1545 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1547 RegCloseKey (hrootkey);
1548 return (lpvalue);
1551 xfree (lpvalue);
1553 RegCloseKey (hrootkey);
1556 return (NULL);
1559 char *get_emacs_configuration (void);
1560 extern Lisp_Object Vsystem_configuration;
1562 void
1563 init_environment (char ** argv)
1565 static const char * const tempdirs[] = {
1566 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1569 int i;
1571 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1573 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1574 temporary files and assume "/tmp" if $TMPDIR is unset, which
1575 will break on DOS/Windows. Refuse to work if we cannot find
1576 a directory, not even "c:/", usable for that purpose. */
1577 for (i = 0; i < imax ; i++)
1579 const char *tmp = tempdirs[i];
1581 if (*tmp == '$')
1582 tmp = getenv (tmp + 1);
1583 /* Note that `access' can lie to us if the directory resides on a
1584 read-only filesystem, like CD-ROM or a write-protected floppy.
1585 The only way to be really sure is to actually create a file and
1586 see if it succeeds. But I think that's too much to ask. */
1587 if (tmp && _access (tmp, D_OK) == 0)
1589 char * var = alloca (strlen (tmp) + 8);
1590 sprintf (var, "TMPDIR=%s", tmp);
1591 _putenv (strdup (var));
1592 break;
1595 if (i >= imax)
1596 cmd_error_internal
1597 (Fcons (Qerror,
1598 Fcons (build_string ("no usable temporary directories found!!"),
1599 Qnil)),
1600 "While setting TMPDIR: ");
1602 /* Check for environment variables and use registry settings if they
1603 don't exist. Fallback on default values where applicable. */
1605 int i;
1606 LPBYTE lpval;
1607 DWORD dwType;
1608 char locale_name[32];
1609 struct stat ignored;
1610 char default_home[MAX_PATH];
1612 static const struct env_entry
1614 char * name;
1615 char * def_value;
1616 } dflt_envvars[] =
1618 {"HOME", "C:/"},
1619 {"PRELOAD_WINSOCK", NULL},
1620 {"emacs_dir", "C:/emacs"},
1621 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1622 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1623 {"EMACSDATA", "%emacs_dir%/etc"},
1624 {"EMACSPATH", "%emacs_dir%/bin"},
1625 /* We no longer set INFOPATH because Info-default-directory-list
1626 is then ignored. */
1627 /* {"INFOPATH", "%emacs_dir%/info"}, */
1628 {"EMACSDOC", "%emacs_dir%/etc"},
1629 {"TERM", "cmd"},
1630 {"LANG", NULL},
1633 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1635 /* We need to copy dflt_envvars[] and work on the copy because we
1636 don't want the dumped Emacs to inherit the values of
1637 environment variables we saw during dumping (which could be on
1638 a different system). The defaults above must be left intact. */
1639 struct env_entry env_vars[N_ENV_VARS];
1641 for (i = 0; i < N_ENV_VARS; i++)
1642 env_vars[i] = dflt_envvars[i];
1644 /* For backwards compatibility, check if a .emacs file exists in C:/
1645 If not, then we can try to default to the appdata directory under the
1646 user's profile, which is more likely to be writable. */
1647 if (stat ("C:/.emacs", &ignored) < 0)
1649 HRESULT profile_result;
1650 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1651 of Windows 95 and NT4 that have not been updated to include
1652 MSIE 5. */
1653 ShGetFolderPath_fn get_folder_path;
1654 get_folder_path = (ShGetFolderPath_fn)
1655 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1657 if (get_folder_path != NULL)
1659 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1660 0, default_home);
1662 /* If we can't get the appdata dir, revert to old behavior. */
1663 if (profile_result == S_OK)
1664 env_vars[0].def_value = default_home;
1668 /* Get default locale info and use it for LANG. */
1669 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1670 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1671 locale_name, sizeof (locale_name)))
1673 for (i = 0; i < N_ENV_VARS; i++)
1675 if (strcmp (env_vars[i].name, "LANG") == 0)
1677 env_vars[i].def_value = locale_name;
1678 break;
1683 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1685 /* Treat emacs_dir specially: set it unconditionally based on our
1686 location, if it appears that we are running from the bin subdir
1687 of a standard installation. */
1689 char *p;
1690 char modname[MAX_PATH];
1692 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1693 abort ();
1694 if ((p = strrchr (modname, '\\')) == NULL)
1695 abort ();
1696 *p = 0;
1698 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1700 char buf[SET_ENV_BUF_SIZE];
1702 *p = 0;
1703 for (p = modname; *p; p++)
1704 if (*p == '\\') *p = '/';
1706 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1707 _putenv (strdup (buf));
1709 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1711 /* FIXME: should use substring of get_emacs_configuration ().
1712 But I don't think the Windows build supports alpha, mips etc
1713 anymore, so have taken the easy option for now. */
1714 else if (p && xstrcasecmp (p, "\\i386") == 0)
1716 *p = 0;
1717 p = strrchr (modname, '\\');
1718 if (p != NULL)
1720 *p = 0;
1721 p = strrchr (modname, '\\');
1722 if (p && xstrcasecmp (p, "\\src") == 0)
1724 char buf[SET_ENV_BUF_SIZE];
1726 *p = 0;
1727 for (p = modname; *p; p++)
1728 if (*p == '\\') *p = '/';
1730 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1731 _putenv (strdup (buf));
1737 for (i = 0; i < N_ENV_VARS; i++)
1739 if (!getenv (env_vars[i].name))
1741 int dont_free = 0;
1743 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1744 /* Also ignore empty environment variables. */
1745 || *lpval == 0)
1747 xfree (lpval);
1748 lpval = env_vars[i].def_value;
1749 dwType = REG_EXPAND_SZ;
1750 dont_free = 1;
1753 if (lpval)
1755 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1757 if (dwType == REG_EXPAND_SZ)
1758 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
1759 else if (dwType == REG_SZ)
1760 strcpy (buf1, lpval);
1761 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1763 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
1764 buf1);
1765 _putenv (strdup (buf2));
1768 if (!dont_free)
1769 xfree (lpval);
1775 /* Rebuild system configuration to reflect invoking system. */
1776 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1778 /* Another special case: on NT, the PATH variable is actually named
1779 "Path" although cmd.exe (perhaps NT itself) arranges for
1780 environment variable lookup and setting to be case insensitive.
1781 However, Emacs assumes a fully case sensitive environment, so we
1782 need to change "Path" to "PATH" to match the expectations of
1783 various elisp packages. We do this by the sneaky method of
1784 modifying the string in the C runtime environ entry.
1786 The same applies to COMSPEC. */
1788 char ** envp;
1790 for (envp = environ; *envp; envp++)
1791 if (_strnicmp (*envp, "PATH=", 5) == 0)
1792 memcpy (*envp, "PATH=", 5);
1793 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1794 memcpy (*envp, "COMSPEC=", 8);
1797 /* Remember the initial working directory for getwd, then make the
1798 real wd be the location of emacs.exe to avoid conflicts when
1799 renaming or deleting directories. (We also don't call chdir when
1800 running subprocesses for the same reason.) */
1801 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1802 abort ();
1805 char *p;
1806 static char modname[MAX_PATH];
1808 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1809 abort ();
1810 if ((p = strrchr (modname, '\\')) == NULL)
1811 abort ();
1812 *p = 0;
1814 SetCurrentDirectory (modname);
1816 /* Ensure argv[0] has the full path to Emacs. */
1817 *p = '\\';
1818 argv[0] = modname;
1821 /* Determine if there is a middle mouse button, to allow parse_button
1822 to decide whether right mouse events should be mouse-2 or
1823 mouse-3. */
1824 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1826 init_user_info ();
1829 char *
1830 emacs_root_dir (void)
1832 static char root_dir[FILENAME_MAX];
1833 const char *p;
1835 p = getenv ("emacs_dir");
1836 if (p == NULL)
1837 abort ();
1838 strcpy (root_dir, p);
1839 root_dir[parse_root (root_dir, NULL)] = '\0';
1840 dostounix_filename (root_dir);
1841 return root_dir;
1844 /* We don't have scripts to automatically determine the system configuration
1845 for Emacs before it's compiled, and we don't want to have to make the
1846 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1847 routine. */
1849 char *
1850 get_emacs_configuration (void)
1852 char *arch, *oem, *os;
1853 int build_num;
1854 static char configuration_buffer[32];
1856 /* Determine the processor type. */
1857 switch (get_processor_type ())
1860 #ifdef PROCESSOR_INTEL_386
1861 case PROCESSOR_INTEL_386:
1862 case PROCESSOR_INTEL_486:
1863 case PROCESSOR_INTEL_PENTIUM:
1864 arch = "i386";
1865 break;
1866 #endif
1868 #ifdef PROCESSOR_MIPS_R2000
1869 case PROCESSOR_MIPS_R2000:
1870 case PROCESSOR_MIPS_R3000:
1871 case PROCESSOR_MIPS_R4000:
1872 arch = "mips";
1873 break;
1874 #endif
1876 #ifdef PROCESSOR_ALPHA_21064
1877 case PROCESSOR_ALPHA_21064:
1878 arch = "alpha";
1879 break;
1880 #endif
1882 default:
1883 arch = "unknown";
1884 break;
1887 /* Use the OEM field to reflect the compiler/library combination. */
1888 #ifdef _MSC_VER
1889 #define COMPILER_NAME "msvc"
1890 #else
1891 #ifdef __GNUC__
1892 #define COMPILER_NAME "mingw"
1893 #else
1894 #define COMPILER_NAME "unknown"
1895 #endif
1896 #endif
1897 oem = COMPILER_NAME;
1899 switch (osinfo_cache.dwPlatformId) {
1900 case VER_PLATFORM_WIN32_NT:
1901 os = "nt";
1902 build_num = osinfo_cache.dwBuildNumber;
1903 break;
1904 case VER_PLATFORM_WIN32_WINDOWS:
1905 if (osinfo_cache.dwMinorVersion == 0) {
1906 os = "windows95";
1907 } else {
1908 os = "windows98";
1910 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1911 break;
1912 case VER_PLATFORM_WIN32s:
1913 /* Not supported, should not happen. */
1914 os = "windows32s";
1915 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1916 break;
1917 default:
1918 os = "unknown";
1919 build_num = 0;
1920 break;
1923 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1924 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1925 get_w32_major_version (), get_w32_minor_version (), build_num);
1926 } else {
1927 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1930 return configuration_buffer;
1933 char *
1934 get_emacs_configuration_options (void)
1936 static char options_buffer[256];
1938 /* Work out the effective configure options for this build. */
1939 #ifdef _MSC_VER
1940 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1941 #else
1942 #ifdef __GNUC__
1943 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1944 #else
1945 #define COMPILER_VERSION ""
1946 #endif
1947 #endif
1949 sprintf (options_buffer, COMPILER_VERSION);
1950 #ifdef EMACSDEBUG
1951 strcat (options_buffer, " --no-opt");
1952 #endif
1953 #ifdef USER_CFLAGS
1954 strcat (options_buffer, " --cflags");
1955 strcat (options_buffer, USER_CFLAGS);
1956 #endif
1957 #ifdef USER_LDFLAGS
1958 strcat (options_buffer, " --ldflags");
1959 strcat (options_buffer, USER_LDFLAGS);
1960 #endif
1961 return options_buffer;
1965 #include <sys/timeb.h>
1967 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1968 void
1969 gettimeofday (struct timeval *tv, struct timezone *tz)
1971 struct _timeb tb;
1972 _ftime (&tb);
1974 tv->tv_sec = tb.time;
1975 tv->tv_usec = tb.millitm * 1000L;
1976 if (tz)
1978 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
1979 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
1983 /* ------------------------------------------------------------------------- */
1984 /* IO support and wrapper functions for W32 API. */
1985 /* ------------------------------------------------------------------------- */
1987 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1988 on network directories, so we handle that case here.
1989 (Ulrich Leodolter, 1/11/95). */
1990 char *
1991 sys_ctime (const time_t *t)
1993 char *str = (char *) ctime (t);
1994 return (str ? str : "Sun Jan 01 00:00:00 1970");
1997 /* Emulate sleep...we could have done this with a define, but that
1998 would necessitate including windows.h in the files that used it.
1999 This is much easier. */
2000 void
2001 sys_sleep (int seconds)
2003 Sleep (seconds * 1000);
2006 /* Internal MSVC functions for low-level descriptor munging */
2007 extern int __cdecl _set_osfhnd (int fd, long h);
2008 extern int __cdecl _free_osfhnd (int fd);
2010 /* parallel array of private info on file handles */
2011 filedesc fd_info [ MAXDESC ];
2013 typedef struct volume_info_data {
2014 struct volume_info_data * next;
2016 /* time when info was obtained */
2017 DWORD timestamp;
2019 /* actual volume info */
2020 char * root_dir;
2021 DWORD serialnum;
2022 DWORD maxcomp;
2023 DWORD flags;
2024 char * name;
2025 char * type;
2026 } volume_info_data;
2028 /* Global referenced by various functions. */
2029 static volume_info_data volume_info;
2031 /* Vector to indicate which drives are local and fixed (for which cached
2032 data never expires). */
2033 static BOOL fixed_drives[26];
2035 /* Consider cached volume information to be stale if older than 10s,
2036 at least for non-local drives. Info for fixed drives is never stale. */
2037 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2038 #define VOLINFO_STILL_VALID( root_dir, info ) \
2039 ( ( isalpha (root_dir[0]) && \
2040 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2041 || GetTickCount () - info->timestamp < 10000 )
2043 /* Cache support functions. */
2045 /* Simple linked list with linear search is sufficient. */
2046 static volume_info_data *volume_cache = NULL;
2048 static volume_info_data *
2049 lookup_volume_info (char * root_dir)
2051 volume_info_data * info;
2053 for (info = volume_cache; info; info = info->next)
2054 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2055 break;
2056 return info;
2059 static void
2060 add_volume_info (char * root_dir, volume_info_data * info)
2062 info->root_dir = xstrdup (root_dir);
2063 info->next = volume_cache;
2064 volume_cache = info;
2068 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2069 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2070 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2071 volume_info_data *
2072 GetCachedVolumeInformation (char * root_dir)
2074 volume_info_data * info;
2075 char default_root[ MAX_PATH ];
2077 /* NULL for root_dir means use root from current directory. */
2078 if (root_dir == NULL)
2080 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
2081 return NULL;
2082 parse_root (default_root, &root_dir);
2083 *root_dir = 0;
2084 root_dir = default_root;
2087 /* Local fixed drives can be cached permanently. Removable drives
2088 cannot be cached permanently, since the volume name and serial
2089 number (if nothing else) can change. Remote drives should be
2090 treated as if they are removable, since there is no sure way to
2091 tell whether they are or not. Also, the UNC association of drive
2092 letters mapped to remote volumes can be changed at any time (even
2093 by other processes) without notice.
2095 As a compromise, so we can benefit from caching info for remote
2096 volumes, we use a simple expiry mechanism to invalidate cache
2097 entries that are more than ten seconds old. */
2099 #if 0
2100 /* No point doing this, because WNetGetConnection is even slower than
2101 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2102 GetDriveType is about the only call of this type which does not
2103 involve network access, and so is extremely quick). */
2105 /* Map drive letter to UNC if remote. */
2106 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2108 char remote_name[ 256 ];
2109 char drive[3] = { root_dir[0], ':' };
2111 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2112 == NO_ERROR)
2113 /* do something */ ;
2115 #endif
2117 info = lookup_volume_info (root_dir);
2119 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2121 char name[ 256 ];
2122 DWORD serialnum;
2123 DWORD maxcomp;
2124 DWORD flags;
2125 char type[ 256 ];
2127 /* Info is not cached, or is stale. */
2128 if (!GetVolumeInformation (root_dir,
2129 name, sizeof (name),
2130 &serialnum,
2131 &maxcomp,
2132 &flags,
2133 type, sizeof (type)))
2134 return NULL;
2136 /* Cache the volume information for future use, overwriting existing
2137 entry if present. */
2138 if (info == NULL)
2140 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
2141 add_volume_info (root_dir, info);
2143 else
2145 xfree (info->name);
2146 xfree (info->type);
2149 info->name = xstrdup (name);
2150 info->serialnum = serialnum;
2151 info->maxcomp = maxcomp;
2152 info->flags = flags;
2153 info->type = xstrdup (type);
2154 info->timestamp = GetTickCount ();
2157 return info;
2160 /* Get information on the volume where name is held; set path pointer to
2161 start of pathname in name (past UNC header\volume header if present). */
2163 get_volume_info (const char * name, const char ** pPath)
2165 char temp[MAX_PATH];
2166 char *rootname = NULL; /* default to current volume */
2167 volume_info_data * info;
2169 if (name == NULL)
2170 return FALSE;
2172 /* find the root name of the volume if given */
2173 if (isalpha (name[0]) && name[1] == ':')
2175 rootname = temp;
2176 temp[0] = *name++;
2177 temp[1] = *name++;
2178 temp[2] = '\\';
2179 temp[3] = 0;
2181 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2183 char *str = temp;
2184 int slashes = 4;
2185 rootname = temp;
2188 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2189 break;
2190 *str++ = *name++;
2192 while ( *name );
2194 *str++ = '\\';
2195 *str = 0;
2198 if (pPath)
2199 *pPath = name;
2201 info = GetCachedVolumeInformation (rootname);
2202 if (info != NULL)
2204 /* Set global referenced by other functions. */
2205 volume_info = *info;
2206 return TRUE;
2208 return FALSE;
2211 /* Determine if volume is FAT format (ie. only supports short 8.3
2212 names); also set path pointer to start of pathname in name. */
2214 is_fat_volume (const char * name, const char ** pPath)
2216 if (get_volume_info (name, pPath))
2217 return (volume_info.maxcomp == 12);
2218 return FALSE;
2221 /* Map filename to a valid 8.3 name if necessary. */
2222 const char *
2223 map_w32_filename (const char * name, const char ** pPath)
2225 static char shortname[MAX_PATH];
2226 char * str = shortname;
2227 char c;
2228 char * path;
2229 const char * save_name = name;
2231 if (strlen (name) >= MAX_PATH)
2233 /* Return a filename which will cause callers to fail. */
2234 strcpy (shortname, "?");
2235 return shortname;
2238 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2240 register int left = 8; /* maximum number of chars in part */
2241 register int extn = 0; /* extension added? */
2242 register int dots = 2; /* maximum number of dots allowed */
2244 while (name < path)
2245 *str++ = *name++; /* skip past UNC header */
2247 while ((c = *name++))
2249 switch ( c )
2251 case '\\':
2252 case '/':
2253 *str++ = '\\';
2254 extn = 0; /* reset extension flags */
2255 dots = 2; /* max 2 dots */
2256 left = 8; /* max length 8 for main part */
2257 break;
2258 case ':':
2259 *str++ = ':';
2260 extn = 0; /* reset extension flags */
2261 dots = 2; /* max 2 dots */
2262 left = 8; /* max length 8 for main part */
2263 break;
2264 case '.':
2265 if ( dots )
2267 /* Convert path components of the form .xxx to _xxx,
2268 but leave . and .. as they are. This allows .emacs
2269 to be read as _emacs, for example. */
2271 if (! *name ||
2272 *name == '.' ||
2273 IS_DIRECTORY_SEP (*name))
2275 *str++ = '.';
2276 dots--;
2278 else
2280 *str++ = '_';
2281 left--;
2282 dots = 0;
2285 else if ( !extn )
2287 *str++ = '.';
2288 extn = 1; /* we've got an extension */
2289 left = 3; /* 3 chars in extension */
2291 else
2293 /* any embedded dots after the first are converted to _ */
2294 *str++ = '_';
2296 break;
2297 case '~':
2298 case '#': /* don't lose these, they're important */
2299 if ( ! left )
2300 str[-1] = c; /* replace last character of part */
2301 /* FALLTHRU */
2302 default:
2303 if ( left )
2305 *str++ = tolower (c); /* map to lower case (looks nicer) */
2306 left--;
2307 dots = 0; /* started a path component */
2309 break;
2312 *str = '\0';
2314 else
2316 strcpy (shortname, name);
2317 unixtodos_filename (shortname);
2320 if (pPath)
2321 *pPath = shortname + (path - save_name);
2323 return shortname;
2326 static int
2327 is_exec (const char * name)
2329 char * p = strrchr (name, '.');
2330 return
2331 (p != NULL
2332 && (xstrcasecmp (p, ".exe") == 0 ||
2333 xstrcasecmp (p, ".com") == 0 ||
2334 xstrcasecmp (p, ".bat") == 0 ||
2335 xstrcasecmp (p, ".cmd") == 0));
2338 /* Emulate the Unix directory procedures opendir, closedir,
2339 and readdir. We can't use the procedures supplied in sysdep.c,
2340 so we provide them here. */
2342 struct direct dir_static; /* simulated directory contents */
2343 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2344 static int dir_is_fat;
2345 static char dir_pathname[MAXPATHLEN+1];
2346 static WIN32_FIND_DATA dir_find_data;
2348 /* Support shares on a network resource as subdirectories of a read-only
2349 root directory. */
2350 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2351 HANDLE open_unc_volume (const char *);
2352 char *read_unc_volume (HANDLE, char *, int);
2353 void close_unc_volume (HANDLE);
2355 DIR *
2356 opendir (char *filename)
2358 DIR *dirp;
2360 /* Opening is done by FindFirstFile. However, a read is inherent to
2361 this operation, so we defer the open until read time. */
2363 if (dir_find_handle != INVALID_HANDLE_VALUE)
2364 return NULL;
2365 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2366 return NULL;
2368 if (is_unc_volume (filename))
2370 wnet_enum_handle = open_unc_volume (filename);
2371 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2372 return NULL;
2375 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2376 return NULL;
2378 dirp->dd_fd = 0;
2379 dirp->dd_loc = 0;
2380 dirp->dd_size = 0;
2382 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2383 dir_pathname[MAXPATHLEN] = '\0';
2384 dir_is_fat = is_fat_volume (filename, NULL);
2386 return dirp;
2389 void
2390 closedir (DIR *dirp)
2392 /* If we have a find-handle open, close it. */
2393 if (dir_find_handle != INVALID_HANDLE_VALUE)
2395 FindClose (dir_find_handle);
2396 dir_find_handle = INVALID_HANDLE_VALUE;
2398 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2400 close_unc_volume (wnet_enum_handle);
2401 wnet_enum_handle = INVALID_HANDLE_VALUE;
2403 xfree ((char *) dirp);
2406 struct direct *
2407 readdir (DIR *dirp)
2409 int downcase = !NILP (Vw32_downcase_file_names);
2411 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2413 if (!read_unc_volume (wnet_enum_handle,
2414 dir_find_data.cFileName,
2415 MAX_PATH))
2416 return NULL;
2418 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2419 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2421 char filename[MAXNAMLEN + 3];
2422 int ln;
2424 strcpy (filename, dir_pathname);
2425 ln = strlen (filename) - 1;
2426 if (!IS_DIRECTORY_SEP (filename[ln]))
2427 strcat (filename, "\\");
2428 strcat (filename, "*");
2430 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2432 if (dir_find_handle == INVALID_HANDLE_VALUE)
2433 return NULL;
2435 else
2437 if (!FindNextFile (dir_find_handle, &dir_find_data))
2438 return NULL;
2441 /* Emacs never uses this value, so don't bother making it match
2442 value returned by stat(). */
2443 dir_static.d_ino = 1;
2445 strcpy (dir_static.d_name, dir_find_data.cFileName);
2447 /* If the file name in cFileName[] includes `?' characters, it means
2448 the original file name used characters that cannot be represented
2449 by the current ANSI codepage. To avoid total lossage, retrieve
2450 the short 8+3 alias of the long file name. */
2451 if (_mbspbrk (dir_static.d_name, "?"))
2453 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2454 downcase = 1; /* 8+3 aliases are returned in all caps */
2456 dir_static.d_namlen = strlen (dir_static.d_name);
2457 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
2458 dir_static.d_namlen - dir_static.d_namlen % 4;
2460 /* If the file name in cFileName[] includes `?' characters, it means
2461 the original file name used characters that cannot be represented
2462 by the current ANSI codepage. To avoid total lossage, retrieve
2463 the short 8+3 alias of the long file name. */
2464 if (_mbspbrk (dir_find_data.cFileName, "?"))
2466 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2467 /* 8+3 aliases are returned in all caps, which could break
2468 various alists that look at filenames' extensions. */
2469 downcase = 1;
2471 else
2472 strcpy (dir_static.d_name, dir_find_data.cFileName);
2473 dir_static.d_namlen = strlen (dir_static.d_name);
2474 if (dir_is_fat)
2475 _strlwr (dir_static.d_name);
2476 else if (downcase)
2478 register char *p;
2479 for (p = dir_static.d_name; *p; p++)
2480 if (*p >= 'a' && *p <= 'z')
2481 break;
2482 if (!*p)
2483 _strlwr (dir_static.d_name);
2486 return &dir_static;
2489 HANDLE
2490 open_unc_volume (const char *path)
2492 NETRESOURCE nr;
2493 HANDLE henum;
2494 int result;
2496 nr.dwScope = RESOURCE_GLOBALNET;
2497 nr.dwType = RESOURCETYPE_DISK;
2498 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2499 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2500 nr.lpLocalName = NULL;
2501 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
2502 nr.lpComment = NULL;
2503 nr.lpProvider = NULL;
2505 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2506 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2508 if (result == NO_ERROR)
2509 return henum;
2510 else
2511 return INVALID_HANDLE_VALUE;
2514 char *
2515 read_unc_volume (HANDLE henum, char *readbuf, int size)
2517 DWORD count;
2518 int result;
2519 DWORD bufsize = 512;
2520 char *buffer;
2521 char *ptr;
2523 count = 1;
2524 buffer = alloca (bufsize);
2525 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
2526 if (result != NO_ERROR)
2527 return NULL;
2529 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2530 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2531 ptr += 2;
2532 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2533 ptr++;
2535 strncpy (readbuf, ptr, size);
2536 return readbuf;
2539 void
2540 close_unc_volume (HANDLE henum)
2542 if (henum != INVALID_HANDLE_VALUE)
2543 WNetCloseEnum (henum);
2546 DWORD
2547 unc_volume_file_attributes (const char *path)
2549 HANDLE henum;
2550 DWORD attrs;
2552 henum = open_unc_volume (path);
2553 if (henum == INVALID_HANDLE_VALUE)
2554 return -1;
2556 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2558 close_unc_volume (henum);
2560 return attrs;
2563 /* Ensure a network connection is authenticated. */
2564 static void
2565 logon_network_drive (const char *path)
2567 NETRESOURCE resource;
2568 char share[MAX_PATH];
2569 int i, n_slashes;
2570 char drive[4];
2571 UINT drvtype;
2573 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
2574 drvtype = DRIVE_REMOTE;
2575 else if (path[0] == '\0' || path[1] != ':')
2576 drvtype = GetDriveType (NULL);
2577 else
2579 drive[0] = path[0];
2580 drive[1] = ':';
2581 drive[2] = '\\';
2582 drive[3] = '\0';
2583 drvtype = GetDriveType (drive);
2586 /* Only logon to networked drives. */
2587 if (drvtype != DRIVE_REMOTE)
2588 return;
2590 n_slashes = 2;
2591 strncpy (share, path, MAX_PATH);
2592 /* Truncate to just server and share name. */
2593 for (i = 2; i < MAX_PATH; i++)
2595 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2597 share[i] = '\0';
2598 break;
2602 resource.dwType = RESOURCETYPE_DISK;
2603 resource.lpLocalName = NULL;
2604 resource.lpRemoteName = share;
2605 resource.lpProvider = NULL;
2607 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2610 /* Shadow some MSVC runtime functions to map requests for long filenames
2611 to reasonable short names if necessary. This was originally added to
2612 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2613 long file names. */
2616 sys_access (const char * path, int mode)
2618 DWORD attributes;
2620 /* MSVC implementation doesn't recognize D_OK. */
2621 path = map_w32_filename (path, NULL);
2622 if (is_unc_volume (path))
2624 attributes = unc_volume_file_attributes (path);
2625 if (attributes == -1) {
2626 errno = EACCES;
2627 return -1;
2630 else if ((attributes = GetFileAttributes (path)) == -1)
2632 /* Should try mapping GetLastError to errno; for now just indicate
2633 that path doesn't exist. */
2634 errno = EACCES;
2635 return -1;
2637 if ((mode & X_OK) != 0 && !is_exec (path))
2639 errno = EACCES;
2640 return -1;
2642 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2644 errno = EACCES;
2645 return -1;
2647 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2649 errno = EACCES;
2650 return -1;
2652 return 0;
2656 sys_chdir (const char * path)
2658 return _chdir (map_w32_filename (path, NULL));
2662 sys_chmod (const char * path, int mode)
2664 return _chmod (map_w32_filename (path, NULL), mode);
2668 sys_chown (const char *path, uid_t owner, gid_t group)
2670 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2671 return -1;
2672 return 0;
2676 sys_creat (const char * path, int mode)
2678 return _creat (map_w32_filename (path, NULL), mode);
2681 FILE *
2682 sys_fopen (const char * path, const char * mode)
2684 int fd;
2685 int oflag;
2686 const char * mode_save = mode;
2688 /* Force all file handles to be non-inheritable. This is necessary to
2689 ensure child processes don't unwittingly inherit handles that might
2690 prevent future file access. */
2692 if (mode[0] == 'r')
2693 oflag = O_RDONLY;
2694 else if (mode[0] == 'w' || mode[0] == 'a')
2695 oflag = O_WRONLY | O_CREAT | O_TRUNC;
2696 else
2697 return NULL;
2699 /* Only do simplistic option parsing. */
2700 while (*++mode)
2701 if (mode[0] == '+')
2703 oflag &= ~(O_RDONLY | O_WRONLY);
2704 oflag |= O_RDWR;
2706 else if (mode[0] == 'b')
2708 oflag &= ~O_TEXT;
2709 oflag |= O_BINARY;
2711 else if (mode[0] == 't')
2713 oflag &= ~O_BINARY;
2714 oflag |= O_TEXT;
2716 else break;
2718 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2719 if (fd < 0)
2720 return NULL;
2722 return _fdopen (fd, mode_save);
2725 /* This only works on NTFS volumes, but is useful to have. */
2727 sys_link (const char * old, const char * new)
2729 HANDLE fileh;
2730 int result = -1;
2731 char oldname[MAX_PATH], newname[MAX_PATH];
2733 if (old == NULL || new == NULL)
2735 errno = ENOENT;
2736 return -1;
2739 strcpy (oldname, map_w32_filename (old, NULL));
2740 strcpy (newname, map_w32_filename (new, NULL));
2742 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2743 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2744 if (fileh != INVALID_HANDLE_VALUE)
2746 int wlen;
2748 /* Confusingly, the "alternate" stream name field does not apply
2749 when restoring a hard link, and instead contains the actual
2750 stream data for the link (ie. the name of the link to create).
2751 The WIN32_STREAM_ID structure before the cStreamName field is
2752 the stream header, which is then immediately followed by the
2753 stream data. */
2755 struct {
2756 WIN32_STREAM_ID wid;
2757 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2758 } data;
2760 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2761 data.wid.cStreamName, MAX_PATH);
2762 if (wlen > 0)
2764 LPVOID context = NULL;
2765 DWORD wbytes = 0;
2767 data.wid.dwStreamId = BACKUP_LINK;
2768 data.wid.dwStreamAttributes = 0;
2769 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
2770 data.wid.Size.HighPart = 0;
2771 data.wid.dwStreamNameSize = 0;
2773 if (BackupWrite (fileh, (LPBYTE)&data,
2774 offsetof (WIN32_STREAM_ID, cStreamName)
2775 + data.wid.Size.LowPart,
2776 &wbytes, FALSE, FALSE, &context)
2777 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2779 /* succeeded */
2780 result = 0;
2782 else
2784 /* Should try mapping GetLastError to errno; for now just
2785 indicate a general error (eg. links not supported). */
2786 errno = EINVAL; // perhaps EMLINK?
2790 CloseHandle (fileh);
2792 else
2793 errno = ENOENT;
2795 return result;
2799 sys_mkdir (const char * path)
2801 return _mkdir (map_w32_filename (path, NULL));
2804 /* Because of long name mapping issues, we need to implement this
2805 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2806 a unique name, instead of setting the input template to an empty
2807 string.
2809 Standard algorithm seems to be use pid or tid with a letter on the
2810 front (in place of the 6 X's) and cycle through the letters to find a
2811 unique name. We extend that to allow any reasonable character as the
2812 first of the 6 X's. */
2813 char *
2814 sys_mktemp (char * template)
2816 char * p;
2817 int i;
2818 unsigned uid = GetCurrentThreadId ();
2819 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2821 if (template == NULL)
2822 return NULL;
2823 p = template + strlen (template);
2824 i = 5;
2825 /* replace up to the last 5 X's with uid in decimal */
2826 while (--p >= template && p[0] == 'X' && --i >= 0)
2828 p[0] = '0' + uid % 10;
2829 uid /= 10;
2832 if (i < 0 && p[0] == 'X')
2834 i = 0;
2837 int save_errno = errno;
2838 p[0] = first_char[i];
2839 if (sys_access (template, 0) < 0)
2841 errno = save_errno;
2842 return template;
2845 while (++i < sizeof (first_char));
2848 /* Template is badly formed or else we can't generate a unique name,
2849 so return empty string */
2850 template[0] = 0;
2851 return template;
2855 sys_open (const char * path, int oflag, int mode)
2857 const char* mpath = map_w32_filename (path, NULL);
2858 /* Try to open file without _O_CREAT, to be able to write to hidden
2859 and system files. Force all file handles to be
2860 non-inheritable. */
2861 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2862 if (res >= 0)
2863 return res;
2864 return _open (mpath, oflag | _O_NOINHERIT, mode);
2868 sys_rename (const char * oldname, const char * newname)
2870 BOOL result;
2871 char temp[MAX_PATH];
2873 /* MoveFile on Windows 95 doesn't correctly change the short file name
2874 alias in a number of circumstances (it is not easy to predict when
2875 just by looking at oldname and newname, unfortunately). In these
2876 cases, renaming through a temporary name avoids the problem.
2878 A second problem on Windows 95 is that renaming through a temp name when
2879 newname is uppercase fails (the final long name ends up in
2880 lowercase, although the short alias might be uppercase) UNLESS the
2881 long temp name is not 8.3.
2883 So, on Windows 95 we always rename through a temp name, and we make sure
2884 the temp name has a long extension to ensure correct renaming. */
2886 strcpy (temp, map_w32_filename (oldname, NULL));
2888 if (os_subtype == OS_WIN95)
2890 char * o;
2891 char * p;
2892 int i = 0;
2894 oldname = map_w32_filename (oldname, NULL);
2895 if (o = strrchr (oldname, '\\'))
2896 o++;
2897 else
2898 o = (char *) oldname;
2900 if (p = strrchr (temp, '\\'))
2901 p++;
2902 else
2903 p = temp;
2907 /* Force temp name to require a manufactured 8.3 alias - this
2908 seems to make the second rename work properly. */
2909 sprintf (p, "_.%s.%u", o, i);
2910 i++;
2911 result = rename (oldname, temp);
2913 /* This loop must surely terminate! */
2914 while (result < 0 && errno == EEXIST);
2915 if (result < 0)
2916 return -1;
2919 /* Emulate Unix behavior - newname is deleted if it already exists
2920 (at least if it is a file; don't do this for directories).
2922 Since we mustn't do this if we are just changing the case of the
2923 file name (we would end up deleting the file we are trying to
2924 rename!), we let rename detect if the destination file already
2925 exists - that way we avoid the possible pitfalls of trying to
2926 determine ourselves whether two names really refer to the same
2927 file, which is not always possible in the general case. (Consider
2928 all the permutations of shared or subst'd drives, etc.) */
2930 newname = map_w32_filename (newname, NULL);
2931 result = rename (temp, newname);
2933 if (result < 0
2934 && errno == EEXIST
2935 && _chmod (newname, 0666) == 0
2936 && _unlink (newname) == 0)
2937 result = rename (temp, newname);
2939 return result;
2943 sys_rmdir (const char * path)
2945 return _rmdir (map_w32_filename (path, NULL));
2949 sys_unlink (const char * path)
2951 path = map_w32_filename (path, NULL);
2953 /* On Unix, unlink works without write permission. */
2954 _chmod (path, 0666);
2955 return _unlink (path);
2958 static FILETIME utc_base_ft;
2959 static ULONGLONG utc_base; /* In 100ns units */
2960 static int init = 0;
2962 #define FILETIME_TO_U64(result, ft) \
2963 do { \
2964 ULARGE_INTEGER uiTemp; \
2965 uiTemp.LowPart = (ft).dwLowDateTime; \
2966 uiTemp.HighPart = (ft).dwHighDateTime; \
2967 result = uiTemp.QuadPart; \
2968 } while (0)
2970 static void
2971 initialize_utc_base (void)
2973 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2974 SYSTEMTIME st;
2976 st.wYear = 1970;
2977 st.wMonth = 1;
2978 st.wDay = 1;
2979 st.wHour = 0;
2980 st.wMinute = 0;
2981 st.wSecond = 0;
2982 st.wMilliseconds = 0;
2984 SystemTimeToFileTime (&st, &utc_base_ft);
2985 FILETIME_TO_U64 (utc_base, utc_base_ft);
2988 static time_t
2989 convert_time (FILETIME ft)
2991 ULONGLONG tmp;
2993 if (!init)
2995 initialize_utc_base();
2996 init = 1;
2999 if (CompareFileTime (&ft, &utc_base_ft) < 0)
3000 return 0;
3002 FILETIME_TO_U64 (tmp, ft);
3003 return (time_t) ((tmp - utc_base) / 10000000L);
3007 void
3008 convert_from_time_t (time_t time, FILETIME * pft)
3010 ULARGE_INTEGER tmp;
3012 if (!init)
3014 initialize_utc_base ();
3015 init = 1;
3018 /* time in 100ns units since 1-Jan-1601 */
3019 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
3020 pft->dwHighDateTime = tmp.HighPart;
3021 pft->dwLowDateTime = tmp.LowPart;
3024 #if 0
3025 /* No reason to keep this; faking inode values either by hashing or even
3026 using the file index from GetInformationByHandle, is not perfect and
3027 so by default Emacs doesn't use the inode values on Windows.
3028 Instead, we now determine file-truename correctly (except for
3029 possible drive aliasing etc). */
3031 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3032 static unsigned
3033 hashval (const unsigned char * str)
3035 unsigned h = 0;
3036 while (*str)
3038 h = (h << 4) + *str++;
3039 h ^= (h >> 28);
3041 return h;
3044 /* Return the hash value of the canonical pathname, excluding the
3045 drive/UNC header, to get a hopefully unique inode number. */
3046 static DWORD
3047 generate_inode_val (const char * name)
3049 char fullname[ MAX_PATH ];
3050 char * p;
3051 unsigned hash;
3053 /* Get the truly canonical filename, if it exists. (Note: this
3054 doesn't resolve aliasing due to subst commands, or recognise hard
3055 links. */
3056 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3057 abort ();
3059 parse_root (fullname, &p);
3060 /* Normal W32 filesystems are still case insensitive. */
3061 _strlwr (p);
3062 return hashval (p);
3065 #endif
3067 static PSECURITY_DESCRIPTOR
3068 get_file_security_desc (const char *fname)
3070 PSECURITY_DESCRIPTOR psd = NULL;
3071 DWORD sd_len, err;
3072 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3073 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3075 if (!get_file_security (fname, si, psd, 0, &sd_len))
3077 err = GetLastError ();
3078 if (err != ERROR_INSUFFICIENT_BUFFER)
3079 return NULL;
3082 psd = xmalloc (sd_len);
3083 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3085 xfree (psd);
3086 return NULL;
3089 return psd;
3092 static DWORD
3093 get_rid (PSID sid)
3095 unsigned n_subauthorities;
3097 /* Use the last sub-authority value of the RID, the relative
3098 portion of the SID, as user/group ID. */
3099 n_subauthorities = *get_sid_sub_authority_count (sid);
3100 if (n_subauthorities < 1)
3101 return 0; /* the "World" RID */
3102 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3105 /* Caching SID and account values for faster lokup. */
3107 #ifdef __GNUC__
3108 # define FLEXIBLE_ARRAY_MEMBER
3109 #else
3110 # define FLEXIBLE_ARRAY_MEMBER 1
3111 #endif
3113 struct w32_id {
3114 unsigned rid;
3115 struct w32_id *next;
3116 char name[GNLEN+1];
3117 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3120 static struct w32_id *w32_idlist;
3122 static int
3123 w32_cached_id (PSID sid, unsigned *id, char *name)
3125 struct w32_id *tail, *found;
3127 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3129 if (equal_sid ((PSID)tail->sid, sid))
3131 found = tail;
3132 break;
3135 if (found)
3137 *id = found->rid;
3138 strcpy (name, found->name);
3139 return 1;
3141 else
3142 return 0;
3145 static void
3146 w32_add_to_cache (PSID sid, unsigned id, char *name)
3148 DWORD sid_len;
3149 struct w32_id *new_entry;
3151 /* We don't want to leave behind stale cache from when Emacs was
3152 dumped. */
3153 if (initialized)
3155 sid_len = get_length_sid (sid);
3156 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3157 if (new_entry)
3159 new_entry->rid = id;
3160 strcpy (new_entry->name, name);
3161 copy_sid (sid_len, (PSID)new_entry->sid, sid);
3162 new_entry->next = w32_idlist;
3163 w32_idlist = new_entry;
3168 #define UID 1
3169 #define GID 2
3171 static int
3172 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
3173 unsigned *id, char *nm, int what)
3175 PSID sid = NULL;
3176 char machine[MAX_COMPUTERNAME_LENGTH+1];
3177 BOOL dflt;
3178 SID_NAME_USE ignore;
3179 char name[UNLEN+1];
3180 DWORD name_len = sizeof (name);
3181 char domain[1024];
3182 DWORD domain_len = sizeof (domain);
3183 char *mp = NULL;
3184 int use_dflt = 0;
3185 int result;
3187 if (what == UID)
3188 result = get_security_descriptor_owner (psd, &sid, &dflt);
3189 else if (what == GID)
3190 result = get_security_descriptor_group (psd, &sid, &dflt);
3191 else
3192 result = 0;
3194 if (!result || !is_valid_sid (sid))
3195 use_dflt = 1;
3196 else if (!w32_cached_id (sid, id, nm))
3198 /* If FNAME is a UNC, we need to lookup account on the
3199 specified machine. */
3200 if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
3201 && fname[2] != '\0')
3203 const char *s;
3204 char *p;
3206 for (s = fname + 2, p = machine;
3207 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
3208 *p = *s;
3209 *p = '\0';
3210 mp = machine;
3213 if (!lookup_account_sid (mp, sid, name, &name_len,
3214 domain, &domain_len, &ignore)
3215 || name_len > UNLEN+1)
3216 use_dflt = 1;
3217 else
3219 *id = get_rid (sid);
3220 strcpy (nm, name);
3221 w32_add_to_cache (sid, *id, name);
3224 return use_dflt;
3227 static void
3228 get_file_owner_and_group (
3229 PSECURITY_DESCRIPTOR psd,
3230 const char *fname,
3231 struct stat *st)
3233 int dflt_usr = 0, dflt_grp = 0;
3235 if (!psd)
3237 dflt_usr = 1;
3238 dflt_grp = 1;
3240 else
3242 if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
3243 dflt_usr = 1;
3244 if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
3245 dflt_grp = 1;
3247 /* Consider files to belong to current user/group, if we cannot get
3248 more accurate information. */
3249 if (dflt_usr)
3251 st->st_uid = dflt_passwd.pw_uid;
3252 strcpy (st->st_uname, dflt_passwd.pw_name);
3254 if (dflt_grp)
3256 st->st_gid = dflt_passwd.pw_gid;
3257 strcpy (st->st_gname, dflt_group.gr_name);
3261 /* Return non-zero if NAME is a potentially slow filesystem. */
3263 is_slow_fs (const char *name)
3265 char drive_root[4];
3266 UINT devtype;
3268 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
3269 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
3270 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
3271 devtype = GetDriveType (NULL); /* use root of current drive */
3272 else
3274 /* GetDriveType needs the root directory of the drive. */
3275 strncpy (drive_root, name, 2);
3276 drive_root[2] = '\\';
3277 drive_root[3] = '\0';
3278 devtype = GetDriveType (drive_root);
3280 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
3283 /* MSVC stat function can't cope with UNC names and has other bugs, so
3284 replace it with our own. This also allows us to calculate consistent
3285 inode values without hacks in the main Emacs code. */
3287 stat (const char * path, struct stat * buf)
3289 char *name, *r;
3290 char drive_root[4];
3291 UINT devtype;
3292 WIN32_FIND_DATA wfd;
3293 HANDLE fh;
3294 unsigned __int64 fake_inode;
3295 int permission;
3296 int len;
3297 int rootdir = FALSE;
3298 PSECURITY_DESCRIPTOR psd = NULL;
3300 if (path == NULL || buf == NULL)
3302 errno = EFAULT;
3303 return -1;
3306 name = (char *) map_w32_filename (path, &path);
3307 /* Must be valid filename, no wild cards or other invalid
3308 characters. We use _mbspbrk to support multibyte strings that
3309 might look to strpbrk as if they included literal *, ?, and other
3310 characters mentioned below that are disallowed by Windows
3311 filesystems. */
3312 if (_mbspbrk (name, "*?|<>\""))
3314 errno = ENOENT;
3315 return -1;
3318 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3319 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3320 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3322 r[1] = r[2] = '\0';
3325 /* Remove trailing directory separator, unless name is the root
3326 directory of a drive or UNC volume in which case ensure there
3327 is a trailing separator. */
3328 len = strlen (name);
3329 rootdir = (path >= name + len - 1
3330 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3331 name = strcpy (alloca (len + 2), name);
3333 if (is_unc_volume (name))
3335 DWORD attrs = unc_volume_file_attributes (name);
3337 if (attrs == -1)
3338 return -1;
3340 memset (&wfd, 0, sizeof (wfd));
3341 wfd.dwFileAttributes = attrs;
3342 wfd.ftCreationTime = utc_base_ft;
3343 wfd.ftLastAccessTime = utc_base_ft;
3344 wfd.ftLastWriteTime = utc_base_ft;
3345 strcpy (wfd.cFileName, name);
3347 else if (rootdir)
3349 if (!IS_DIRECTORY_SEP (name[len-1]))
3350 strcat (name, "\\");
3351 if (GetDriveType (name) < 2)
3353 errno = ENOENT;
3354 return -1;
3356 memset (&wfd, 0, sizeof (wfd));
3357 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
3358 wfd.ftCreationTime = utc_base_ft;
3359 wfd.ftLastAccessTime = utc_base_ft;
3360 wfd.ftLastWriteTime = utc_base_ft;
3361 strcpy (wfd.cFileName, name);
3363 else
3365 if (IS_DIRECTORY_SEP (name[len-1]))
3366 name[len - 1] = 0;
3368 /* (This is hacky, but helps when doing file completions on
3369 network drives.) Optimize by using information available from
3370 active readdir if possible. */
3371 len = strlen (dir_pathname);
3372 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3373 len--;
3374 if (dir_find_handle != INVALID_HANDLE_VALUE
3375 && strnicmp (name, dir_pathname, len) == 0
3376 && IS_DIRECTORY_SEP (name[len])
3377 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3379 /* This was the last entry returned by readdir. */
3380 wfd = dir_find_data;
3382 else
3384 logon_network_drive (name);
3386 fh = FindFirstFile (name, &wfd);
3387 if (fh == INVALID_HANDLE_VALUE)
3389 errno = ENOENT;
3390 return -1;
3392 FindClose (fh);
3396 if (!(NILP (Vw32_get_true_file_attributes)
3397 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
3398 /* No access rights required to get info. */
3399 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
3400 FILE_FLAG_BACKUP_SEMANTICS, NULL))
3401 != INVALID_HANDLE_VALUE)
3403 /* This is more accurate in terms of gettting the correct number
3404 of links, but is quite slow (it is noticeable when Emacs is
3405 making a list of file name completions). */
3406 BY_HANDLE_FILE_INFORMATION info;
3408 if (GetFileInformationByHandle (fh, &info))
3410 buf->st_nlink = info.nNumberOfLinks;
3411 /* Might as well use file index to fake inode values, but this
3412 is not guaranteed to be unique unless we keep a handle open
3413 all the time (even then there are situations where it is
3414 not unique). Reputedly, there are at most 48 bits of info
3415 (on NTFS, presumably less on FAT). */
3416 fake_inode = info.nFileIndexHigh;
3417 fake_inode <<= 32;
3418 fake_inode += info.nFileIndexLow;
3420 else
3422 buf->st_nlink = 1;
3423 fake_inode = 0;
3426 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3428 buf->st_mode = S_IFDIR;
3430 else
3432 switch (GetFileType (fh))
3434 case FILE_TYPE_DISK:
3435 buf->st_mode = S_IFREG;
3436 break;
3437 case FILE_TYPE_PIPE:
3438 buf->st_mode = S_IFIFO;
3439 break;
3440 case FILE_TYPE_CHAR:
3441 case FILE_TYPE_UNKNOWN:
3442 default:
3443 buf->st_mode = S_IFCHR;
3446 CloseHandle (fh);
3447 psd = get_file_security_desc (name);
3448 get_file_owner_and_group (psd, name, buf);
3450 else
3452 /* Don't bother to make this information more accurate. */
3453 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
3454 S_IFDIR : S_IFREG;
3455 buf->st_nlink = 1;
3456 fake_inode = 0;
3458 get_file_owner_and_group (NULL, name, buf);
3460 xfree (psd);
3462 #if 0
3463 /* Not sure if there is any point in this. */
3464 if (!NILP (Vw32_generate_fake_inodes))
3465 fake_inode = generate_inode_val (name);
3466 else if (fake_inode == 0)
3468 /* For want of something better, try to make everything unique. */
3469 static DWORD gen_num = 0;
3470 fake_inode = ++gen_num;
3472 #endif
3474 /* MSVC defines _ino_t to be short; other libc's might not. */
3475 if (sizeof (buf->st_ino) == 2)
3476 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3477 else
3478 buf->st_ino = fake_inode;
3480 /* volume_info is set indirectly by map_w32_filename */
3481 buf->st_dev = volume_info.serialnum;
3482 buf->st_rdev = volume_info.serialnum;
3485 buf->st_size = wfd.nFileSizeHigh;
3486 buf->st_size <<= 32;
3487 buf->st_size += wfd.nFileSizeLow;
3489 /* Convert timestamps to Unix format. */
3490 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
3491 buf->st_atime = convert_time (wfd.ftLastAccessTime);
3492 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3493 buf->st_ctime = convert_time (wfd.ftCreationTime);
3494 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3496 /* determine rwx permissions */
3497 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3498 permission = S_IREAD;
3499 else
3500 permission = S_IREAD | S_IWRITE;
3502 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3503 permission |= S_IEXEC;
3504 else if (is_exec (name))
3505 permission |= S_IEXEC;
3507 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3509 return 0;
3512 /* Provide fstat and utime as well as stat for consistent handling of
3513 file timestamps. */
3515 fstat (int desc, struct stat * buf)
3517 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3518 BY_HANDLE_FILE_INFORMATION info;
3519 unsigned __int64 fake_inode;
3520 int permission;
3522 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3524 case FILE_TYPE_DISK:
3525 buf->st_mode = S_IFREG;
3526 if (!GetFileInformationByHandle (fh, &info))
3528 errno = EACCES;
3529 return -1;
3531 break;
3532 case FILE_TYPE_PIPE:
3533 buf->st_mode = S_IFIFO;
3534 goto non_disk;
3535 case FILE_TYPE_CHAR:
3536 case FILE_TYPE_UNKNOWN:
3537 default:
3538 buf->st_mode = S_IFCHR;
3539 non_disk:
3540 memset (&info, 0, sizeof (info));
3541 info.dwFileAttributes = 0;
3542 info.ftCreationTime = utc_base_ft;
3543 info.ftLastAccessTime = utc_base_ft;
3544 info.ftLastWriteTime = utc_base_ft;
3547 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3548 buf->st_mode = S_IFDIR;
3550 buf->st_nlink = info.nNumberOfLinks;
3551 /* Might as well use file index to fake inode values, but this
3552 is not guaranteed to be unique unless we keep a handle open
3553 all the time (even then there are situations where it is
3554 not unique). Reputedly, there are at most 48 bits of info
3555 (on NTFS, presumably less on FAT). */
3556 fake_inode = info.nFileIndexHigh;
3557 fake_inode <<= 32;
3558 fake_inode += info.nFileIndexLow;
3560 /* MSVC defines _ino_t to be short; other libc's might not. */
3561 if (sizeof (buf->st_ino) == 2)
3562 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3563 else
3564 buf->st_ino = fake_inode;
3566 /* Consider files to belong to current user.
3567 FIXME: this should use GetSecurityInfo API, but it is only
3568 available for _WIN32_WINNT >= 0x501. */
3569 buf->st_uid = dflt_passwd.pw_uid;
3570 buf->st_gid = dflt_passwd.pw_gid;
3571 strcpy (buf->st_uname, dflt_passwd.pw_name);
3572 strcpy (buf->st_gname, dflt_group.gr_name);
3574 buf->st_dev = info.dwVolumeSerialNumber;
3575 buf->st_rdev = info.dwVolumeSerialNumber;
3577 buf->st_size = info.nFileSizeHigh;
3578 buf->st_size <<= 32;
3579 buf->st_size += info.nFileSizeLow;
3581 /* Convert timestamps to Unix format. */
3582 buf->st_mtime = convert_time (info.ftLastWriteTime);
3583 buf->st_atime = convert_time (info.ftLastAccessTime);
3584 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3585 buf->st_ctime = convert_time (info.ftCreationTime);
3586 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3588 /* determine rwx permissions */
3589 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3590 permission = S_IREAD;
3591 else
3592 permission = S_IREAD | S_IWRITE;
3594 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3595 permission |= S_IEXEC;
3596 else
3598 #if 0 /* no way of knowing the filename */
3599 char * p = strrchr (name, '.');
3600 if (p != NULL &&
3601 (xstrcasecmp (p, ".exe") == 0 ||
3602 xstrcasecmp (p, ".com") == 0 ||
3603 xstrcasecmp (p, ".bat") == 0 ||
3604 xstrcasecmp (p, ".cmd") == 0))
3605 permission |= S_IEXEC;
3606 #endif
3609 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3611 return 0;
3615 utime (const char *name, struct utimbuf *times)
3617 struct utimbuf deftime;
3618 HANDLE fh;
3619 FILETIME mtime;
3620 FILETIME atime;
3622 if (times == NULL)
3624 deftime.modtime = deftime.actime = time (NULL);
3625 times = &deftime;
3628 /* Need write access to set times. */
3629 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
3630 0, OPEN_EXISTING, 0, NULL);
3631 if (fh)
3633 convert_from_time_t (times->actime, &atime);
3634 convert_from_time_t (times->modtime, &mtime);
3635 if (!SetFileTime (fh, NULL, &atime, &mtime))
3637 CloseHandle (fh);
3638 errno = EACCES;
3639 return -1;
3641 CloseHandle (fh);
3643 else
3645 errno = EINVAL;
3646 return -1;
3648 return 0;
3652 /* Support for browsing other processes and their attributes. See
3653 process.c for the Lisp bindings. */
3655 /* Helper wrapper functions. */
3657 HANDLE WINAPI create_toolhelp32_snapshot (
3658 DWORD Flags,
3659 DWORD Ignored)
3661 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
3663 if (g_b_init_create_toolhelp32_snapshot == 0)
3665 g_b_init_create_toolhelp32_snapshot = 1;
3666 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
3667 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3668 "CreateToolhelp32Snapshot");
3670 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
3672 return INVALID_HANDLE_VALUE;
3674 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
3677 BOOL WINAPI process32_first (
3678 HANDLE hSnapshot,
3679 LPPROCESSENTRY32 lppe)
3681 static Process32First_Proc s_pfn_Process32_First = NULL;
3683 if (g_b_init_process32_first == 0)
3685 g_b_init_process32_first = 1;
3686 s_pfn_Process32_First = (Process32First_Proc)
3687 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3688 "Process32First");
3690 if (s_pfn_Process32_First == NULL)
3692 return FALSE;
3694 return (s_pfn_Process32_First (hSnapshot, lppe));
3697 BOOL WINAPI process32_next (
3698 HANDLE hSnapshot,
3699 LPPROCESSENTRY32 lppe)
3701 static Process32Next_Proc s_pfn_Process32_Next = NULL;
3703 if (g_b_init_process32_next == 0)
3705 g_b_init_process32_next = 1;
3706 s_pfn_Process32_Next = (Process32Next_Proc)
3707 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3708 "Process32Next");
3710 if (s_pfn_Process32_Next == NULL)
3712 return FALSE;
3714 return (s_pfn_Process32_Next (hSnapshot, lppe));
3717 BOOL WINAPI open_thread_token (
3718 HANDLE ThreadHandle,
3719 DWORD DesiredAccess,
3720 BOOL OpenAsSelf,
3721 PHANDLE TokenHandle)
3723 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
3724 HMODULE hm_advapi32 = NULL;
3725 if (is_windows_9x () == TRUE)
3727 SetLastError (ERROR_NOT_SUPPORTED);
3728 return FALSE;
3730 if (g_b_init_open_thread_token == 0)
3732 g_b_init_open_thread_token = 1;
3733 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3734 s_pfn_Open_Thread_Token =
3735 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
3737 if (s_pfn_Open_Thread_Token == NULL)
3739 SetLastError (ERROR_NOT_SUPPORTED);
3740 return FALSE;
3742 return (
3743 s_pfn_Open_Thread_Token (
3744 ThreadHandle,
3745 DesiredAccess,
3746 OpenAsSelf,
3747 TokenHandle)
3751 BOOL WINAPI impersonate_self (
3752 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
3754 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
3755 HMODULE hm_advapi32 = NULL;
3756 if (is_windows_9x () == TRUE)
3758 return FALSE;
3760 if (g_b_init_impersonate_self == 0)
3762 g_b_init_impersonate_self = 1;
3763 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3764 s_pfn_Impersonate_Self =
3765 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
3767 if (s_pfn_Impersonate_Self == NULL)
3769 return FALSE;
3771 return s_pfn_Impersonate_Self (ImpersonationLevel);
3774 BOOL WINAPI revert_to_self (void)
3776 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
3777 HMODULE hm_advapi32 = NULL;
3778 if (is_windows_9x () == TRUE)
3780 return FALSE;
3782 if (g_b_init_revert_to_self == 0)
3784 g_b_init_revert_to_self = 1;
3785 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3786 s_pfn_Revert_To_Self =
3787 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
3789 if (s_pfn_Revert_To_Self == NULL)
3791 return FALSE;
3793 return s_pfn_Revert_To_Self ();
3796 BOOL WINAPI get_process_memory_info (
3797 HANDLE h_proc,
3798 PPROCESS_MEMORY_COUNTERS mem_counters,
3799 DWORD bufsize)
3801 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
3802 HMODULE hm_psapi = NULL;
3803 if (is_windows_9x () == TRUE)
3805 return FALSE;
3807 if (g_b_init_get_process_memory_info == 0)
3809 g_b_init_get_process_memory_info = 1;
3810 hm_psapi = LoadLibrary ("Psapi.dll");
3811 if (hm_psapi)
3812 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
3813 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
3815 if (s_pfn_Get_Process_Memory_Info == NULL)
3817 return FALSE;
3819 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
3822 BOOL WINAPI get_process_working_set_size (
3823 HANDLE h_proc,
3824 DWORD *minrss,
3825 DWORD *maxrss)
3827 static GetProcessWorkingSetSize_Proc
3828 s_pfn_Get_Process_Working_Set_Size = NULL;
3830 if (is_windows_9x () == TRUE)
3832 return FALSE;
3834 if (g_b_init_get_process_working_set_size == 0)
3836 g_b_init_get_process_working_set_size = 1;
3837 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
3838 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3839 "GetProcessWorkingSetSize");
3841 if (s_pfn_Get_Process_Working_Set_Size == NULL)
3843 return FALSE;
3845 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
3848 BOOL WINAPI global_memory_status (
3849 MEMORYSTATUS *buf)
3851 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
3853 if (is_windows_9x () == TRUE)
3855 return FALSE;
3857 if (g_b_init_global_memory_status == 0)
3859 g_b_init_global_memory_status = 1;
3860 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
3861 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3862 "GlobalMemoryStatus");
3864 if (s_pfn_Global_Memory_Status == NULL)
3866 return FALSE;
3868 return s_pfn_Global_Memory_Status (buf);
3871 BOOL WINAPI global_memory_status_ex (
3872 MEMORY_STATUS_EX *buf)
3874 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
3876 if (is_windows_9x () == TRUE)
3878 return FALSE;
3880 if (g_b_init_global_memory_status_ex == 0)
3882 g_b_init_global_memory_status_ex = 1;
3883 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
3884 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3885 "GlobalMemoryStatusEx");
3887 if (s_pfn_Global_Memory_Status_Ex == NULL)
3889 return FALSE;
3891 return s_pfn_Global_Memory_Status_Ex (buf);
3894 Lisp_Object
3895 list_system_processes (void)
3897 struct gcpro gcpro1;
3898 Lisp_Object proclist = Qnil;
3899 HANDLE h_snapshot;
3901 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
3903 if (h_snapshot != INVALID_HANDLE_VALUE)
3905 PROCESSENTRY32 proc_entry;
3906 DWORD proc_id;
3907 BOOL res;
3909 GCPRO1 (proclist);
3911 proc_entry.dwSize = sizeof (PROCESSENTRY32);
3912 for (res = process32_first (h_snapshot, &proc_entry); res;
3913 res = process32_next (h_snapshot, &proc_entry))
3915 proc_id = proc_entry.th32ProcessID;
3916 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
3919 CloseHandle (h_snapshot);
3920 UNGCPRO;
3921 proclist = Fnreverse (proclist);
3924 return proclist;
3927 static int
3928 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
3930 TOKEN_PRIVILEGES priv;
3931 DWORD priv_size = sizeof (priv);
3932 DWORD opriv_size = sizeof (*old_priv);
3933 HANDLE h_token = NULL;
3934 HANDLE h_thread = GetCurrentThread ();
3935 int ret_val = 0;
3936 BOOL res;
3938 res = open_thread_token (h_thread,
3939 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3940 FALSE, &h_token);
3941 if (!res && GetLastError () == ERROR_NO_TOKEN)
3943 if (impersonate_self (SecurityImpersonation))
3944 res = open_thread_token (h_thread,
3945 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3946 FALSE, &h_token);
3948 if (res)
3950 priv.PrivilegeCount = 1;
3951 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
3952 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
3953 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
3954 old_priv, &opriv_size)
3955 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3956 ret_val = 1;
3958 if (h_token)
3959 CloseHandle (h_token);
3961 return ret_val;
3964 static int
3965 restore_privilege (TOKEN_PRIVILEGES *priv)
3967 DWORD priv_size = sizeof (*priv);
3968 HANDLE h_token = NULL;
3969 int ret_val = 0;
3971 if (open_thread_token (GetCurrentThread (),
3972 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3973 FALSE, &h_token))
3975 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
3976 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3977 ret_val = 1;
3979 if (h_token)
3980 CloseHandle (h_token);
3982 return ret_val;
3985 static Lisp_Object
3986 ltime (long time_sec, long time_usec)
3988 return list3 (make_number ((time_sec >> 16) & 0xffff),
3989 make_number (time_sec & 0xffff),
3990 make_number (time_usec));
3993 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
3995 static int
3996 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
3997 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
3998 double *pcpu)
4000 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
4001 ULONGLONG tem1, tem2, tem3, tem;
4003 if (!h_proc
4004 || !get_process_times_fn
4005 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
4006 &ft_kernel, &ft_user))
4007 return 0;
4009 GetSystemTimeAsFileTime (&ft_current);
4011 FILETIME_TO_U64 (tem1, ft_kernel);
4012 tem1 /= 10L;
4013 *stime = U64_TO_LISP_TIME (tem1);
4015 FILETIME_TO_U64 (tem2, ft_user);
4016 tem2 /= 10L;
4017 *utime = U64_TO_LISP_TIME (tem2);
4019 tem3 = tem1 + tem2;
4020 *ttime = U64_TO_LISP_TIME (tem3);
4022 FILETIME_TO_U64 (tem, ft_creation);
4023 /* Process no 4 (System) returns zero creation time. */
4024 if (tem)
4025 tem = (tem - utc_base) / 10L;
4026 *ctime = U64_TO_LISP_TIME (tem);
4028 if (tem)
4030 FILETIME_TO_U64 (tem3, ft_current);
4031 tem = (tem3 - utc_base) / 10L - tem;
4033 *etime = U64_TO_LISP_TIME (tem);
4035 if (tem)
4037 *pcpu = 100.0 * (tem1 + tem2) / tem;
4038 if (*pcpu > 100)
4039 *pcpu = 100.0;
4041 else
4042 *pcpu = 0;
4044 return 1;
4047 Lisp_Object
4048 system_process_attributes (Lisp_Object pid)
4050 struct gcpro gcpro1, gcpro2, gcpro3;
4051 Lisp_Object attrs = Qnil;
4052 Lisp_Object cmd_str, decoded_cmd, tem;
4053 HANDLE h_snapshot, h_proc;
4054 DWORD proc_id;
4055 int found_proc = 0;
4056 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
4057 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
4058 DWORD glength = sizeof (gname);
4059 HANDLE token = NULL;
4060 SID_NAME_USE user_type;
4061 unsigned char *buf = NULL;
4062 DWORD blen = 0;
4063 TOKEN_USER user_token;
4064 TOKEN_PRIMARY_GROUP group_token;
4065 unsigned euid;
4066 unsigned egid;
4067 DWORD sess;
4068 PROCESS_MEMORY_COUNTERS mem;
4069 PROCESS_MEMORY_COUNTERS_EX mem_ex;
4070 DWORD minrss, maxrss;
4071 MEMORYSTATUS memst;
4072 MEMORY_STATUS_EX memstex;
4073 double totphys = 0.0;
4074 Lisp_Object ctime, stime, utime, etime, ttime;
4075 double pcpu;
4076 BOOL result = FALSE;
4078 CHECK_NUMBER_OR_FLOAT (pid);
4079 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
4081 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4083 GCPRO3 (attrs, decoded_cmd, tem);
4085 if (h_snapshot != INVALID_HANDLE_VALUE)
4087 PROCESSENTRY32 pe;
4088 BOOL res;
4090 pe.dwSize = sizeof (PROCESSENTRY32);
4091 for (res = process32_first (h_snapshot, &pe); res;
4092 res = process32_next (h_snapshot, &pe))
4094 if (proc_id == pe.th32ProcessID)
4096 if (proc_id == 0)
4097 decoded_cmd = build_string ("Idle");
4098 else
4100 /* Decode the command name from locale-specific
4101 encoding. */
4102 cmd_str = make_unibyte_string (pe.szExeFile,
4103 strlen (pe.szExeFile));
4104 decoded_cmd =
4105 code_convert_string_norecord (cmd_str,
4106 Vlocale_coding_system, 0);
4108 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
4109 attrs = Fcons (Fcons (Qppid,
4110 make_fixnum_or_float (pe.th32ParentProcessID)),
4111 attrs);
4112 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
4113 attrs);
4114 attrs = Fcons (Fcons (Qthcount,
4115 make_fixnum_or_float (pe.cntThreads)),
4116 attrs);
4117 found_proc = 1;
4118 break;
4122 CloseHandle (h_snapshot);
4125 if (!found_proc)
4127 UNGCPRO;
4128 return Qnil;
4131 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4132 FALSE, proc_id);
4133 /* If we were denied a handle to the process, try again after
4134 enabling the SeDebugPrivilege in our process. */
4135 if (!h_proc)
4137 TOKEN_PRIVILEGES priv_current;
4139 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
4141 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4142 FALSE, proc_id);
4143 restore_privilege (&priv_current);
4144 revert_to_self ();
4147 if (h_proc)
4149 result = open_process_token (h_proc, TOKEN_QUERY, &token);
4150 if (result)
4152 result = get_token_information (token, TokenUser, NULL, 0, &blen);
4153 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4155 buf = xmalloc (blen);
4156 result = get_token_information (token, TokenUser,
4157 (LPVOID)buf, blen, &needed);
4158 if (result)
4160 memcpy (&user_token, buf, sizeof (user_token));
4161 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
4163 euid = get_rid (user_token.User.Sid);
4164 result = lookup_account_sid (NULL, user_token.User.Sid,
4165 uname, &ulength,
4166 domain, &dlength,
4167 &user_type);
4168 if (result)
4169 w32_add_to_cache (user_token.User.Sid, euid, uname);
4170 else
4172 strcpy (uname, "unknown");
4173 result = TRUE;
4176 ulength = strlen (uname);
4180 if (result)
4182 /* Determine a reasonable euid and gid values. */
4183 if (xstrcasecmp ("administrator", uname) == 0)
4185 euid = 500; /* well-known Administrator uid */
4186 egid = 513; /* well-known None gid */
4188 else
4190 /* Get group id and name. */
4191 result = get_token_information (token, TokenPrimaryGroup,
4192 (LPVOID)buf, blen, &needed);
4193 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4195 buf = xrealloc (buf, blen = needed);
4196 result = get_token_information (token, TokenPrimaryGroup,
4197 (LPVOID)buf, blen, &needed);
4199 if (result)
4201 memcpy (&group_token, buf, sizeof (group_token));
4202 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
4204 egid = get_rid (group_token.PrimaryGroup);
4205 dlength = sizeof (domain);
4206 result =
4207 lookup_account_sid (NULL, group_token.PrimaryGroup,
4208 gname, &glength, NULL, &dlength,
4209 &user_type);
4210 if (result)
4211 w32_add_to_cache (group_token.PrimaryGroup,
4212 egid, gname);
4213 else
4215 strcpy (gname, "None");
4216 result = TRUE;
4219 glength = strlen (gname);
4223 xfree (buf);
4225 if (!result)
4227 if (!is_windows_9x ())
4229 /* We couldn't open the process token, presumably because of
4230 insufficient access rights. Assume this process is run
4231 by the system. */
4232 strcpy (uname, "SYSTEM");
4233 strcpy (gname, "None");
4234 euid = 18; /* SYSTEM */
4235 egid = 513; /* None */
4236 glength = strlen (gname);
4237 ulength = strlen (uname);
4239 /* If we are running under Windows 9X, where security calls are
4240 not supported, we assume all processes are run by the current
4241 user. */
4242 else if (GetUserName (uname, &ulength))
4244 if (xstrcasecmp ("administrator", uname) == 0)
4245 euid = 0;
4246 else
4247 euid = 123;
4248 egid = euid;
4249 strcpy (gname, "None");
4250 glength = strlen (gname);
4251 ulength = strlen (uname);
4253 else
4255 euid = 123;
4256 egid = 123;
4257 strcpy (uname, "administrator");
4258 ulength = strlen (uname);
4259 strcpy (gname, "None");
4260 glength = strlen (gname);
4262 if (token)
4263 CloseHandle (token);
4266 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
4267 tem = make_unibyte_string (uname, ulength);
4268 attrs = Fcons (Fcons (Quser,
4269 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4270 attrs);
4271 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
4272 tem = make_unibyte_string (gname, glength);
4273 attrs = Fcons (Fcons (Qgroup,
4274 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4275 attrs);
4277 if (global_memory_status_ex (&memstex))
4278 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4279 totphys = memstex.ullTotalPhys / 1024.0;
4280 #else
4281 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4282 double, so we need to do this for it... */
4284 DWORD tot_hi = memstex.ullTotalPhys >> 32;
4285 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
4286 DWORD tot_lo = memstex.ullTotalPhys % 1024;
4288 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
4290 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4291 else if (global_memory_status (&memst))
4292 totphys = memst.dwTotalPhys / 1024.0;
4294 if (h_proc
4295 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
4296 sizeof (mem_ex)))
4298 DWORD rss = mem_ex.WorkingSetSize / 1024;
4300 attrs = Fcons (Fcons (Qmajflt,
4301 make_fixnum_or_float (mem_ex.PageFaultCount)),
4302 attrs);
4303 attrs = Fcons (Fcons (Qvsize,
4304 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
4305 attrs);
4306 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4307 if (totphys)
4308 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4310 else if (h_proc
4311 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
4313 DWORD rss = mem_ex.WorkingSetSize / 1024;
4315 attrs = Fcons (Fcons (Qmajflt,
4316 make_fixnum_or_float (mem.PageFaultCount)),
4317 attrs);
4318 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4319 if (totphys)
4320 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4322 else if (h_proc
4323 && get_process_working_set_size (h_proc, &minrss, &maxrss))
4325 DWORD rss = maxrss / 1024;
4327 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
4328 if (totphys)
4329 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4332 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
4334 attrs = Fcons (Fcons (Qutime, utime), attrs);
4335 attrs = Fcons (Fcons (Qstime, stime), attrs);
4336 attrs = Fcons (Fcons (Qtime, ttime), attrs);
4337 attrs = Fcons (Fcons (Qstart, ctime), attrs);
4338 attrs = Fcons (Fcons (Qetime, etime), attrs);
4339 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
4342 /* FIXME: Retrieve command line by walking the PEB of the process. */
4344 if (h_proc)
4345 CloseHandle (h_proc);
4346 UNGCPRO;
4347 return attrs;
4351 #ifdef HAVE_SOCKETS
4353 /* Wrappers for winsock functions to map between our file descriptors
4354 and winsock's handles; also set h_errno for convenience.
4356 To allow Emacs to run on systems which don't have winsock support
4357 installed, we dynamically link to winsock on startup if present, and
4358 otherwise provide the minimum necessary functionality
4359 (eg. gethostname). */
4361 /* function pointers for relevant socket functions */
4362 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
4363 void (PASCAL *pfn_WSASetLastError) (int iError);
4364 int (PASCAL *pfn_WSAGetLastError) (void);
4365 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
4366 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
4367 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
4368 int (PASCAL *pfn_socket) (int af, int type, int protocol);
4369 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
4370 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
4371 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
4372 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
4373 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
4374 int (PASCAL *pfn_closesocket) (SOCKET s);
4375 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
4376 int (PASCAL *pfn_WSACleanup) (void);
4378 u_short (PASCAL *pfn_htons) (u_short hostshort);
4379 u_short (PASCAL *pfn_ntohs) (u_short netshort);
4380 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
4381 int (PASCAL *pfn_gethostname) (char * name, int namelen);
4382 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
4383 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
4384 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
4385 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
4386 const char * optval, int optlen);
4387 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
4388 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
4389 int * namelen);
4390 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
4391 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
4392 struct sockaddr * from, int * fromlen);
4393 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
4394 const struct sockaddr * to, int tolen);
4396 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4397 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
4398 #ifndef HANDLE_FLAG_INHERIT
4399 #define HANDLE_FLAG_INHERIT 1
4400 #endif
4402 HANDLE winsock_lib;
4403 static int winsock_inuse;
4405 BOOL
4406 term_winsock (void)
4408 if (winsock_lib != NULL && winsock_inuse == 0)
4410 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4411 after WSAStartup returns successfully, but it seems reasonable
4412 to allow unloading winsock anyway in that case. */
4413 if (pfn_WSACleanup () == 0 ||
4414 pfn_WSAGetLastError () == WSAENETDOWN)
4416 if (FreeLibrary (winsock_lib))
4417 winsock_lib = NULL;
4418 return TRUE;
4421 return FALSE;
4424 BOOL
4425 init_winsock (int load_now)
4427 WSADATA winsockData;
4429 if (winsock_lib != NULL)
4430 return TRUE;
4432 pfn_SetHandleInformation = NULL;
4433 pfn_SetHandleInformation
4434 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4435 "SetHandleInformation");
4437 winsock_lib = LoadLibrary ("Ws2_32.dll");
4439 if (winsock_lib != NULL)
4441 /* dynamically link to socket functions */
4443 #define LOAD_PROC(fn) \
4444 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4445 goto fail;
4447 LOAD_PROC (WSAStartup);
4448 LOAD_PROC (WSASetLastError);
4449 LOAD_PROC (WSAGetLastError);
4450 LOAD_PROC (WSAEventSelect);
4451 LOAD_PROC (WSACreateEvent);
4452 LOAD_PROC (WSACloseEvent);
4453 LOAD_PROC (socket);
4454 LOAD_PROC (bind);
4455 LOAD_PROC (connect);
4456 LOAD_PROC (ioctlsocket);
4457 LOAD_PROC (recv);
4458 LOAD_PROC (send);
4459 LOAD_PROC (closesocket);
4460 LOAD_PROC (shutdown);
4461 LOAD_PROC (htons);
4462 LOAD_PROC (ntohs);
4463 LOAD_PROC (inet_addr);
4464 LOAD_PROC (gethostname);
4465 LOAD_PROC (gethostbyname);
4466 LOAD_PROC (getservbyname);
4467 LOAD_PROC (getpeername);
4468 LOAD_PROC (WSACleanup);
4469 LOAD_PROC (setsockopt);
4470 LOAD_PROC (listen);
4471 LOAD_PROC (getsockname);
4472 LOAD_PROC (accept);
4473 LOAD_PROC (recvfrom);
4474 LOAD_PROC (sendto);
4475 #undef LOAD_PROC
4477 /* specify version 1.1 of winsock */
4478 if (pfn_WSAStartup (0x101, &winsockData) == 0)
4480 if (winsockData.wVersion != 0x101)
4481 goto fail;
4483 if (!load_now)
4485 /* Report that winsock exists and is usable, but leave
4486 socket functions disabled. I am assuming that calling
4487 WSAStartup does not require any network interaction,
4488 and in particular does not cause or require a dial-up
4489 connection to be established. */
4491 pfn_WSACleanup ();
4492 FreeLibrary (winsock_lib);
4493 winsock_lib = NULL;
4495 winsock_inuse = 0;
4496 return TRUE;
4499 fail:
4500 FreeLibrary (winsock_lib);
4501 winsock_lib = NULL;
4504 return FALSE;
4508 int h_errno = 0;
4510 /* function to set h_errno for compatibility; map winsock error codes to
4511 normal system codes where they overlap (non-overlapping definitions
4512 are already in <sys/socket.h> */
4513 static void
4514 set_errno (void)
4516 if (winsock_lib == NULL)
4517 h_errno = EINVAL;
4518 else
4519 h_errno = pfn_WSAGetLastError ();
4521 switch (h_errno)
4523 case WSAEACCES: h_errno = EACCES; break;
4524 case WSAEBADF: h_errno = EBADF; break;
4525 case WSAEFAULT: h_errno = EFAULT; break;
4526 case WSAEINTR: h_errno = EINTR; break;
4527 case WSAEINVAL: h_errno = EINVAL; break;
4528 case WSAEMFILE: h_errno = EMFILE; break;
4529 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
4530 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
4532 errno = h_errno;
4535 static void
4536 check_errno (void)
4538 if (h_errno == 0 && winsock_lib != NULL)
4539 pfn_WSASetLastError (0);
4542 /* Extend strerror to handle the winsock-specific error codes. */
4543 struct {
4544 int errnum;
4545 char * msg;
4546 } _wsa_errlist[] = {
4547 WSAEINTR , "Interrupted function call",
4548 WSAEBADF , "Bad file descriptor",
4549 WSAEACCES , "Permission denied",
4550 WSAEFAULT , "Bad address",
4551 WSAEINVAL , "Invalid argument",
4552 WSAEMFILE , "Too many open files",
4554 WSAEWOULDBLOCK , "Resource temporarily unavailable",
4555 WSAEINPROGRESS , "Operation now in progress",
4556 WSAEALREADY , "Operation already in progress",
4557 WSAENOTSOCK , "Socket operation on non-socket",
4558 WSAEDESTADDRREQ , "Destination address required",
4559 WSAEMSGSIZE , "Message too long",
4560 WSAEPROTOTYPE , "Protocol wrong type for socket",
4561 WSAENOPROTOOPT , "Bad protocol option",
4562 WSAEPROTONOSUPPORT , "Protocol not supported",
4563 WSAESOCKTNOSUPPORT , "Socket type not supported",
4564 WSAEOPNOTSUPP , "Operation not supported",
4565 WSAEPFNOSUPPORT , "Protocol family not supported",
4566 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
4567 WSAEADDRINUSE , "Address already in use",
4568 WSAEADDRNOTAVAIL , "Cannot assign requested address",
4569 WSAENETDOWN , "Network is down",
4570 WSAENETUNREACH , "Network is unreachable",
4571 WSAENETRESET , "Network dropped connection on reset",
4572 WSAECONNABORTED , "Software caused connection abort",
4573 WSAECONNRESET , "Connection reset by peer",
4574 WSAENOBUFS , "No buffer space available",
4575 WSAEISCONN , "Socket is already connected",
4576 WSAENOTCONN , "Socket is not connected",
4577 WSAESHUTDOWN , "Cannot send after socket shutdown",
4578 WSAETOOMANYREFS , "Too many references", /* not sure */
4579 WSAETIMEDOUT , "Connection timed out",
4580 WSAECONNREFUSED , "Connection refused",
4581 WSAELOOP , "Network loop", /* not sure */
4582 WSAENAMETOOLONG , "Name is too long",
4583 WSAEHOSTDOWN , "Host is down",
4584 WSAEHOSTUNREACH , "No route to host",
4585 WSAENOTEMPTY , "Buffer not empty", /* not sure */
4586 WSAEPROCLIM , "Too many processes",
4587 WSAEUSERS , "Too many users", /* not sure */
4588 WSAEDQUOT , "Double quote in host name", /* really not sure */
4589 WSAESTALE , "Data is stale", /* not sure */
4590 WSAEREMOTE , "Remote error", /* not sure */
4592 WSASYSNOTREADY , "Network subsystem is unavailable",
4593 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
4594 WSANOTINITIALISED , "Winsock not initialized successfully",
4595 WSAEDISCON , "Graceful shutdown in progress",
4596 #ifdef WSAENOMORE
4597 WSAENOMORE , "No more operations allowed", /* not sure */
4598 WSAECANCELLED , "Operation cancelled", /* not sure */
4599 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
4600 WSAEINVALIDPROVIDER , "Invalid service provider version number",
4601 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
4602 WSASYSCALLFAILURE , "System call failure",
4603 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
4604 WSATYPE_NOT_FOUND , "Class type not found",
4605 WSA_E_NO_MORE , "No more resources available", /* really not sure */
4606 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
4607 WSAEREFUSED , "Operation refused", /* not sure */
4608 #endif
4610 WSAHOST_NOT_FOUND , "Host not found",
4611 WSATRY_AGAIN , "Authoritative host not found during name lookup",
4612 WSANO_RECOVERY , "Non-recoverable error during name lookup",
4613 WSANO_DATA , "Valid name, no data record of requested type",
4615 -1, NULL
4618 char *
4619 sys_strerror (int error_no)
4621 int i;
4622 static char unknown_msg[40];
4624 if (error_no >= 0 && error_no < sys_nerr)
4625 return sys_errlist[error_no];
4627 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
4628 if (_wsa_errlist[i].errnum == error_no)
4629 return _wsa_errlist[i].msg;
4631 sprintf (unknown_msg, "Unidentified error: %d", error_no);
4632 return unknown_msg;
4635 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4636 but I believe the method of keeping the socket handle separate (and
4637 insuring it is not inheritable) is the correct one. */
4639 //#define SOCK_REPLACE_HANDLE
4641 #ifdef SOCK_REPLACE_HANDLE
4642 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
4643 #else
4644 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4645 #endif
4647 int socket_to_fd (SOCKET s);
4650 sys_socket (int af, int type, int protocol)
4652 SOCKET s;
4654 if (winsock_lib == NULL)
4656 h_errno = ENETDOWN;
4657 return INVALID_SOCKET;
4660 check_errno ();
4662 /* call the real socket function */
4663 s = pfn_socket (af, type, protocol);
4665 if (s != INVALID_SOCKET)
4666 return socket_to_fd (s);
4668 set_errno ();
4669 return -1;
4672 /* Convert a SOCKET to a file descriptor. */
4674 socket_to_fd (SOCKET s)
4676 int fd;
4677 child_process * cp;
4679 /* Although under NT 3.5 _open_osfhandle will accept a socket
4680 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4681 that does not work under NT 3.1. However, we can get the same
4682 effect by using a backdoor function to replace an existing
4683 descriptor handle with the one we want. */
4685 /* allocate a file descriptor (with appropriate flags) */
4686 fd = _open ("NUL:", _O_RDWR);
4687 if (fd >= 0)
4689 #ifdef SOCK_REPLACE_HANDLE
4690 /* now replace handle to NUL with our socket handle */
4691 CloseHandle ((HANDLE) _get_osfhandle (fd));
4692 _free_osfhnd (fd);
4693 _set_osfhnd (fd, s);
4694 /* setmode (fd, _O_BINARY); */
4695 #else
4696 /* Make a non-inheritable copy of the socket handle. Note
4697 that it is possible that sockets aren't actually kernel
4698 handles, which appears to be the case on Windows 9x when
4699 the MS Proxy winsock client is installed. */
4701 /* Apparently there is a bug in NT 3.51 with some service
4702 packs, which prevents using DuplicateHandle to make a
4703 socket handle non-inheritable (causes WSACleanup to
4704 hang). The work-around is to use SetHandleInformation
4705 instead if it is available and implemented. */
4706 if (pfn_SetHandleInformation)
4708 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
4710 else
4712 HANDLE parent = GetCurrentProcess ();
4713 HANDLE new_s = INVALID_HANDLE_VALUE;
4715 if (DuplicateHandle (parent,
4716 (HANDLE) s,
4717 parent,
4718 &new_s,
4720 FALSE,
4721 DUPLICATE_SAME_ACCESS))
4723 /* It is possible that DuplicateHandle succeeds even
4724 though the socket wasn't really a kernel handle,
4725 because a real handle has the same value. So
4726 test whether the new handle really is a socket. */
4727 long nonblocking = 0;
4728 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
4730 pfn_closesocket (s);
4731 s = (SOCKET) new_s;
4733 else
4735 CloseHandle (new_s);
4740 fd_info[fd].hnd = (HANDLE) s;
4741 #endif
4743 /* set our own internal flags */
4744 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
4746 cp = new_child ();
4747 if (cp)
4749 cp->fd = fd;
4750 cp->status = STATUS_READ_ACKNOWLEDGED;
4752 /* attach child_process to fd_info */
4753 if (fd_info[ fd ].cp != NULL)
4755 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
4756 abort ();
4759 fd_info[ fd ].cp = cp;
4761 /* success! */
4762 winsock_inuse++; /* count open sockets */
4763 return fd;
4766 /* clean up */
4767 _close (fd);
4769 pfn_closesocket (s);
4770 h_errno = EMFILE;
4771 return -1;
4776 sys_bind (int s, const struct sockaddr * addr, int namelen)
4778 if (winsock_lib == NULL)
4780 h_errno = ENOTSOCK;
4781 return SOCKET_ERROR;
4784 check_errno ();
4785 if (fd_info[s].flags & FILE_SOCKET)
4787 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
4788 if (rc == SOCKET_ERROR)
4789 set_errno ();
4790 return rc;
4792 h_errno = ENOTSOCK;
4793 return SOCKET_ERROR;
4798 sys_connect (int s, const struct sockaddr * name, int namelen)
4800 if (winsock_lib == NULL)
4802 h_errno = ENOTSOCK;
4803 return SOCKET_ERROR;
4806 check_errno ();
4807 if (fd_info[s].flags & FILE_SOCKET)
4809 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
4810 if (rc == SOCKET_ERROR)
4811 set_errno ();
4812 return rc;
4814 h_errno = ENOTSOCK;
4815 return SOCKET_ERROR;
4818 u_short
4819 sys_htons (u_short hostshort)
4821 return (winsock_lib != NULL) ?
4822 pfn_htons (hostshort) : hostshort;
4825 u_short
4826 sys_ntohs (u_short netshort)
4828 return (winsock_lib != NULL) ?
4829 pfn_ntohs (netshort) : netshort;
4832 unsigned long
4833 sys_inet_addr (const char * cp)
4835 return (winsock_lib != NULL) ?
4836 pfn_inet_addr (cp) : INADDR_NONE;
4840 sys_gethostname (char * name, int namelen)
4842 if (winsock_lib != NULL)
4843 return pfn_gethostname (name, namelen);
4845 if (namelen > MAX_COMPUTERNAME_LENGTH)
4846 return !GetComputerName (name, (DWORD *)&namelen);
4848 h_errno = EFAULT;
4849 return SOCKET_ERROR;
4852 struct hostent *
4853 sys_gethostbyname (const char * name)
4855 struct hostent * host;
4857 if (winsock_lib == NULL)
4859 h_errno = ENETDOWN;
4860 return NULL;
4863 check_errno ();
4864 host = pfn_gethostbyname (name);
4865 if (!host)
4866 set_errno ();
4867 return host;
4870 struct servent *
4871 sys_getservbyname (const char * name, const char * proto)
4873 struct servent * serv;
4875 if (winsock_lib == NULL)
4877 h_errno = ENETDOWN;
4878 return NULL;
4881 check_errno ();
4882 serv = pfn_getservbyname (name, proto);
4883 if (!serv)
4884 set_errno ();
4885 return serv;
4889 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
4891 if (winsock_lib == NULL)
4893 h_errno = ENETDOWN;
4894 return SOCKET_ERROR;
4897 check_errno ();
4898 if (fd_info[s].flags & FILE_SOCKET)
4900 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
4901 if (rc == SOCKET_ERROR)
4902 set_errno ();
4903 return rc;
4905 h_errno = ENOTSOCK;
4906 return SOCKET_ERROR;
4911 sys_shutdown (int s, int how)
4913 if (winsock_lib == NULL)
4915 h_errno = ENETDOWN;
4916 return SOCKET_ERROR;
4919 check_errno ();
4920 if (fd_info[s].flags & FILE_SOCKET)
4922 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
4923 if (rc == SOCKET_ERROR)
4924 set_errno ();
4925 return rc;
4927 h_errno = ENOTSOCK;
4928 return SOCKET_ERROR;
4932 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
4934 if (winsock_lib == NULL)
4936 h_errno = ENETDOWN;
4937 return SOCKET_ERROR;
4940 check_errno ();
4941 if (fd_info[s].flags & FILE_SOCKET)
4943 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
4944 (const char *)optval, optlen);
4945 if (rc == SOCKET_ERROR)
4946 set_errno ();
4947 return rc;
4949 h_errno = ENOTSOCK;
4950 return SOCKET_ERROR;
4954 sys_listen (int s, int backlog)
4956 if (winsock_lib == NULL)
4958 h_errno = ENETDOWN;
4959 return SOCKET_ERROR;
4962 check_errno ();
4963 if (fd_info[s].flags & FILE_SOCKET)
4965 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
4966 if (rc == SOCKET_ERROR)
4967 set_errno ();
4968 else
4969 fd_info[s].flags |= FILE_LISTEN;
4970 return rc;
4972 h_errno = ENOTSOCK;
4973 return SOCKET_ERROR;
4977 sys_getsockname (int s, struct sockaddr * name, int * namelen)
4979 if (winsock_lib == NULL)
4981 h_errno = ENETDOWN;
4982 return SOCKET_ERROR;
4985 check_errno ();
4986 if (fd_info[s].flags & FILE_SOCKET)
4988 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
4989 if (rc == SOCKET_ERROR)
4990 set_errno ();
4991 return rc;
4993 h_errno = ENOTSOCK;
4994 return SOCKET_ERROR;
4998 sys_accept (int s, struct sockaddr * addr, int * addrlen)
5000 if (winsock_lib == NULL)
5002 h_errno = ENETDOWN;
5003 return -1;
5006 check_errno ();
5007 if (fd_info[s].flags & FILE_LISTEN)
5009 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
5010 int fd = -1;
5011 if (t == INVALID_SOCKET)
5012 set_errno ();
5013 else
5014 fd = socket_to_fd (t);
5016 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
5017 ResetEvent (fd_info[s].cp->char_avail);
5018 return fd;
5020 h_errno = ENOTSOCK;
5021 return -1;
5025 sys_recvfrom (int s, char * buf, int len, int flags,
5026 struct sockaddr * from, int * fromlen)
5028 if (winsock_lib == NULL)
5030 h_errno = ENETDOWN;
5031 return SOCKET_ERROR;
5034 check_errno ();
5035 if (fd_info[s].flags & FILE_SOCKET)
5037 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
5038 if (rc == SOCKET_ERROR)
5039 set_errno ();
5040 return rc;
5042 h_errno = ENOTSOCK;
5043 return SOCKET_ERROR;
5047 sys_sendto (int s, const char * buf, int len, int flags,
5048 const struct sockaddr * to, int tolen)
5050 if (winsock_lib == NULL)
5052 h_errno = ENETDOWN;
5053 return SOCKET_ERROR;
5056 check_errno ();
5057 if (fd_info[s].flags & FILE_SOCKET)
5059 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
5060 if (rc == SOCKET_ERROR)
5061 set_errno ();
5062 return rc;
5064 h_errno = ENOTSOCK;
5065 return SOCKET_ERROR;
5068 /* Windows does not have an fcntl function. Provide an implementation
5069 solely for making sockets non-blocking. */
5071 fcntl (int s, int cmd, int options)
5073 if (winsock_lib == NULL)
5075 h_errno = ENETDOWN;
5076 return -1;
5079 check_errno ();
5080 if (fd_info[s].flags & FILE_SOCKET)
5082 if (cmd == F_SETFL && options == O_NDELAY)
5084 unsigned long nblock = 1;
5085 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
5086 if (rc == SOCKET_ERROR)
5087 set_errno();
5088 /* Keep track of the fact that we set this to non-blocking. */
5089 fd_info[s].flags |= FILE_NDELAY;
5090 return rc;
5092 else
5094 h_errno = EINVAL;
5095 return SOCKET_ERROR;
5098 h_errno = ENOTSOCK;
5099 return SOCKET_ERROR;
5102 #endif /* HAVE_SOCKETS */
5105 /* Shadow main io functions: we need to handle pipes and sockets more
5106 intelligently, and implement non-blocking mode as well. */
5109 sys_close (int fd)
5111 int rc;
5113 if (fd < 0)
5115 errno = EBADF;
5116 return -1;
5119 if (fd < MAXDESC && fd_info[fd].cp)
5121 child_process * cp = fd_info[fd].cp;
5123 fd_info[fd].cp = NULL;
5125 if (CHILD_ACTIVE (cp))
5127 /* if last descriptor to active child_process then cleanup */
5128 int i;
5129 for (i = 0; i < MAXDESC; i++)
5131 if (i == fd)
5132 continue;
5133 if (fd_info[i].cp == cp)
5134 break;
5136 if (i == MAXDESC)
5138 #ifdef HAVE_SOCKETS
5139 if (fd_info[fd].flags & FILE_SOCKET)
5141 #ifndef SOCK_REPLACE_HANDLE
5142 if (winsock_lib == NULL) abort ();
5144 pfn_shutdown (SOCK_HANDLE (fd), 2);
5145 rc = pfn_closesocket (SOCK_HANDLE (fd));
5146 #endif
5147 winsock_inuse--; /* count open sockets */
5149 #endif
5150 delete_child (cp);
5155 /* Note that sockets do not need special treatment here (at least on
5156 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5157 closesocket is equivalent to CloseHandle, which is to be expected
5158 because socket handles are fully fledged kernel handles. */
5159 rc = _close (fd);
5161 if (rc == 0 && fd < MAXDESC)
5162 fd_info[fd].flags = 0;
5164 return rc;
5168 sys_dup (int fd)
5170 int new_fd;
5172 new_fd = _dup (fd);
5173 if (new_fd >= 0 && new_fd < MAXDESC)
5175 /* duplicate our internal info as well */
5176 fd_info[new_fd] = fd_info[fd];
5178 return new_fd;
5183 sys_dup2 (int src, int dst)
5185 int rc;
5187 if (dst < 0 || dst >= MAXDESC)
5189 errno = EBADF;
5190 return -1;
5193 /* make sure we close the destination first if it's a pipe or socket */
5194 if (src != dst && fd_info[dst].flags != 0)
5195 sys_close (dst);
5197 rc = _dup2 (src, dst);
5198 if (rc == 0)
5200 /* duplicate our internal info as well */
5201 fd_info[dst] = fd_info[src];
5203 return rc;
5206 /* Unix pipe() has only one arg */
5208 sys_pipe (int * phandles)
5210 int rc;
5211 unsigned flags;
5213 /* make pipe handles non-inheritable; when we spawn a child, we
5214 replace the relevant handle with an inheritable one. Also put
5215 pipes into binary mode; we will do text mode translation ourselves
5216 if required. */
5217 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
5219 if (rc == 0)
5221 /* Protect against overflow, since Windows can open more handles than
5222 our fd_info array has room for. */
5223 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
5225 _close (phandles[0]);
5226 _close (phandles[1]);
5227 rc = -1;
5229 else
5231 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
5232 fd_info[phandles[0]].flags = flags;
5234 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
5235 fd_info[phandles[1]].flags = flags;
5239 return rc;
5242 /* From ntproc.c */
5243 extern int w32_pipe_read_delay;
5245 /* Function to do blocking read of one byte, needed to implement
5246 select. It is only allowed on sockets and pipes. */
5248 _sys_read_ahead (int fd)
5250 child_process * cp;
5251 int rc;
5253 if (fd < 0 || fd >= MAXDESC)
5254 return STATUS_READ_ERROR;
5256 cp = fd_info[fd].cp;
5258 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5259 return STATUS_READ_ERROR;
5261 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
5262 || (fd_info[fd].flags & FILE_READ) == 0)
5264 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
5265 abort ();
5268 cp->status = STATUS_READ_IN_PROGRESS;
5270 if (fd_info[fd].flags & FILE_PIPE)
5272 rc = _read (fd, &cp->chr, sizeof (char));
5274 /* Give subprocess time to buffer some more output for us before
5275 reporting that input is available; we need this because Windows 95
5276 connects DOS programs to pipes by making the pipe appear to be
5277 the normal console stdout - as a result most DOS programs will
5278 write to stdout without buffering, ie. one character at a
5279 time. Even some W32 programs do this - "dir" in a command
5280 shell on NT is very slow if we don't do this. */
5281 if (rc > 0)
5283 int wait = w32_pipe_read_delay;
5285 if (wait > 0)
5286 Sleep (wait);
5287 else if (wait < 0)
5288 while (++wait <= 0)
5289 /* Yield remainder of our time slice, effectively giving a
5290 temporary priority boost to the child process. */
5291 Sleep (0);
5294 else if (fd_info[fd].flags & FILE_SERIAL)
5296 HANDLE hnd = fd_info[fd].hnd;
5297 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5298 COMMTIMEOUTS ct;
5300 /* Configure timeouts for blocking read. */
5301 if (!GetCommTimeouts (hnd, &ct))
5302 return STATUS_READ_ERROR;
5303 ct.ReadIntervalTimeout = 0;
5304 ct.ReadTotalTimeoutMultiplier = 0;
5305 ct.ReadTotalTimeoutConstant = 0;
5306 if (!SetCommTimeouts (hnd, &ct))
5307 return STATUS_READ_ERROR;
5309 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
5311 if (GetLastError () != ERROR_IO_PENDING)
5312 return STATUS_READ_ERROR;
5313 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5314 return STATUS_READ_ERROR;
5317 #ifdef HAVE_SOCKETS
5318 else if (fd_info[fd].flags & FILE_SOCKET)
5320 unsigned long nblock = 0;
5321 /* We always want this to block, so temporarily disable NDELAY. */
5322 if (fd_info[fd].flags & FILE_NDELAY)
5323 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5325 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
5327 if (fd_info[fd].flags & FILE_NDELAY)
5329 nblock = 1;
5330 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5333 #endif
5335 if (rc == sizeof (char))
5336 cp->status = STATUS_READ_SUCCEEDED;
5337 else
5338 cp->status = STATUS_READ_FAILED;
5340 return cp->status;
5344 _sys_wait_accept (int fd)
5346 HANDLE hEv;
5347 child_process * cp;
5348 int rc;
5350 if (fd < 0 || fd >= MAXDESC)
5351 return STATUS_READ_ERROR;
5353 cp = fd_info[fd].cp;
5355 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5356 return STATUS_READ_ERROR;
5358 cp->status = STATUS_READ_FAILED;
5360 hEv = pfn_WSACreateEvent ();
5361 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
5362 if (rc != SOCKET_ERROR)
5364 rc = WaitForSingleObject (hEv, INFINITE);
5365 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
5366 if (rc == WAIT_OBJECT_0)
5367 cp->status = STATUS_READ_SUCCEEDED;
5369 pfn_WSACloseEvent (hEv);
5371 return cp->status;
5375 sys_read (int fd, char * buffer, unsigned int count)
5377 int nchars;
5378 int to_read;
5379 DWORD waiting;
5380 char * orig_buffer = buffer;
5382 if (fd < 0)
5384 errno = EBADF;
5385 return -1;
5388 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5390 child_process *cp = fd_info[fd].cp;
5392 if ((fd_info[fd].flags & FILE_READ) == 0)
5394 errno = EBADF;
5395 return -1;
5398 nchars = 0;
5400 /* re-read CR carried over from last read */
5401 if (fd_info[fd].flags & FILE_LAST_CR)
5403 if (fd_info[fd].flags & FILE_BINARY) abort ();
5404 *buffer++ = 0x0d;
5405 count--;
5406 nchars++;
5407 fd_info[fd].flags &= ~FILE_LAST_CR;
5410 /* presence of a child_process structure means we are operating in
5411 non-blocking mode - otherwise we just call _read directly.
5412 Note that the child_process structure might be missing because
5413 reap_subprocess has been called; in this case the pipe is
5414 already broken, so calling _read on it is okay. */
5415 if (cp)
5417 int current_status = cp->status;
5419 switch (current_status)
5421 case STATUS_READ_FAILED:
5422 case STATUS_READ_ERROR:
5423 /* report normal EOF if nothing in buffer */
5424 if (nchars <= 0)
5425 fd_info[fd].flags |= FILE_AT_EOF;
5426 return nchars;
5428 case STATUS_READ_READY:
5429 case STATUS_READ_IN_PROGRESS:
5430 DebPrint (("sys_read called when read is in progress\n"));
5431 errno = EWOULDBLOCK;
5432 return -1;
5434 case STATUS_READ_SUCCEEDED:
5435 /* consume read-ahead char */
5436 *buffer++ = cp->chr;
5437 count--;
5438 nchars++;
5439 cp->status = STATUS_READ_ACKNOWLEDGED;
5440 ResetEvent (cp->char_avail);
5442 case STATUS_READ_ACKNOWLEDGED:
5443 break;
5445 default:
5446 DebPrint (("sys_read: bad status %d\n", current_status));
5447 errno = EBADF;
5448 return -1;
5451 if (fd_info[fd].flags & FILE_PIPE)
5453 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
5454 to_read = min (waiting, (DWORD) count);
5456 if (to_read > 0)
5457 nchars += _read (fd, buffer, to_read);
5459 else if (fd_info[fd].flags & FILE_SERIAL)
5461 HANDLE hnd = fd_info[fd].hnd;
5462 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5463 DWORD err = 0;
5464 int rc = 0;
5465 COMMTIMEOUTS ct;
5467 if (count > 0)
5469 /* Configure timeouts for non-blocking read. */
5470 if (!GetCommTimeouts (hnd, &ct))
5472 errno = EIO;
5473 return -1;
5475 ct.ReadIntervalTimeout = MAXDWORD;
5476 ct.ReadTotalTimeoutMultiplier = 0;
5477 ct.ReadTotalTimeoutConstant = 0;
5478 if (!SetCommTimeouts (hnd, &ct))
5480 errno = EIO;
5481 return -1;
5484 if (!ResetEvent (ovl->hEvent))
5486 errno = EIO;
5487 return -1;
5489 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
5491 if (GetLastError () != ERROR_IO_PENDING)
5493 errno = EIO;
5494 return -1;
5496 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5498 errno = EIO;
5499 return -1;
5502 nchars += rc;
5505 #ifdef HAVE_SOCKETS
5506 else /* FILE_SOCKET */
5508 if (winsock_lib == NULL) abort ();
5510 /* do the equivalent of a non-blocking read */
5511 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
5512 if (waiting == 0 && nchars == 0)
5514 h_errno = errno = EWOULDBLOCK;
5515 return -1;
5518 if (waiting)
5520 /* always use binary mode for sockets */
5521 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
5522 if (res == SOCKET_ERROR)
5524 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5525 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5526 set_errno ();
5527 return -1;
5529 nchars += res;
5532 #endif
5534 else
5536 int nread = _read (fd, buffer, count);
5537 if (nread >= 0)
5538 nchars += nread;
5539 else if (nchars == 0)
5540 nchars = nread;
5543 if (nchars <= 0)
5544 fd_info[fd].flags |= FILE_AT_EOF;
5545 /* Perform text mode translation if required. */
5546 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
5548 nchars = crlf_to_lf (nchars, orig_buffer);
5549 /* If buffer contains only CR, return that. To be absolutely
5550 sure we should attempt to read the next char, but in
5551 practice a CR to be followed by LF would not appear by
5552 itself in the buffer. */
5553 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
5555 fd_info[fd].flags |= FILE_LAST_CR;
5556 nchars--;
5560 else
5561 nchars = _read (fd, buffer, count);
5563 return nchars;
5566 /* From w32xfns.c */
5567 extern HANDLE interrupt_handle;
5569 /* For now, don't bother with a non-blocking mode */
5571 sys_write (int fd, const void * buffer, unsigned int count)
5573 int nchars;
5575 if (fd < 0)
5577 errno = EBADF;
5578 return -1;
5581 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5583 if ((fd_info[fd].flags & FILE_WRITE) == 0)
5585 errno = EBADF;
5586 return -1;
5589 /* Perform text mode translation if required. */
5590 if ((fd_info[fd].flags & FILE_BINARY) == 0)
5592 char * tmpbuf = alloca (count * 2);
5593 unsigned char * src = (void *)buffer;
5594 unsigned char * dst = tmpbuf;
5595 int nbytes = count;
5597 while (1)
5599 unsigned char *next;
5600 /* copy next line or remaining bytes */
5601 next = _memccpy (dst, src, '\n', nbytes);
5602 if (next)
5604 /* copied one line ending with '\n' */
5605 int copied = next - dst;
5606 nbytes -= copied;
5607 src += copied;
5608 /* insert '\r' before '\n' */
5609 next[-1] = '\r';
5610 next[0] = '\n';
5611 dst = next + 1;
5612 count++;
5614 else
5615 /* copied remaining partial line -> now finished */
5616 break;
5618 buffer = tmpbuf;
5622 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
5624 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
5625 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
5626 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
5627 DWORD active = 0;
5629 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
5631 if (GetLastError () != ERROR_IO_PENDING)
5633 errno = EIO;
5634 return -1;
5636 if (detect_input_pending ())
5637 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
5638 QS_ALLINPUT);
5639 else
5640 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
5641 if (active == WAIT_OBJECT_0)
5642 { /* User pressed C-g, cancel write, then leave. Don't bother
5643 cleaning up as we may only get stuck in buggy drivers. */
5644 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
5645 CancelIo (hnd);
5646 errno = EIO;
5647 return -1;
5649 if (active == WAIT_OBJECT_0 + 1
5650 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
5652 errno = EIO;
5653 return -1;
5657 else
5658 #ifdef HAVE_SOCKETS
5659 if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
5661 unsigned long nblock = 0;
5662 if (winsock_lib == NULL) abort ();
5664 /* TODO: implement select() properly so non-blocking I/O works. */
5665 /* For now, make sure the write blocks. */
5666 if (fd_info[fd].flags & FILE_NDELAY)
5667 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5669 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
5671 /* Set the socket back to non-blocking if it was before,
5672 for other operations that support it. */
5673 if (fd_info[fd].flags & FILE_NDELAY)
5675 nblock = 1;
5676 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5679 if (nchars == SOCKET_ERROR)
5681 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5682 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5683 set_errno ();
5686 else
5687 #endif
5689 /* Some networked filesystems don't like too large writes, so
5690 break them into smaller chunks. See the Comments section of
5691 the MSDN documentation of WriteFile for details behind the
5692 choice of the value of CHUNK below. See also the thread
5693 http://thread.gmane.org/gmane.comp.version-control.git/145294
5694 in the git mailing list. */
5695 const unsigned char *p = buffer;
5696 const unsigned chunk = 30 * 1024 * 1024;
5698 nchars = 0;
5699 while (count > 0)
5701 unsigned this_chunk = count < chunk ? count : chunk;
5702 int n = _write (fd, p, this_chunk);
5704 nchars += n;
5705 if (n < 0)
5707 nchars = n;
5708 break;
5710 else if (n < this_chunk)
5711 break;
5712 count -= n;
5713 p += n;
5717 return nchars;
5720 static void
5721 check_windows_init_file (void)
5723 extern int noninteractive, inhibit_window_system;
5725 /* A common indication that Emacs is not installed properly is when
5726 it cannot find the Windows installation file. If this file does
5727 not exist in the expected place, tell the user. */
5729 if (!noninteractive && !inhibit_window_system)
5731 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
5732 Lisp_Object objs[2];
5733 Lisp_Object full_load_path;
5734 Lisp_Object init_file;
5735 int fd;
5737 objs[0] = Vload_path;
5738 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5739 full_load_path = Fappend (2, objs);
5740 init_file = build_string ("term/w32-win");
5741 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
5742 if (fd < 0)
5744 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
5745 char *init_file_name = SDATA (init_file);
5746 char *load_path = SDATA (load_path_print);
5747 char *buffer = alloca (1024
5748 + strlen (init_file_name)
5749 + strlen (load_path));
5751 sprintf (buffer,
5752 "The Emacs Windows initialization file \"%s.el\" "
5753 "could not be found in your Emacs installation. "
5754 "Emacs checked the following directories for this file:\n"
5755 "\n%s\n\n"
5756 "When Emacs cannot find this file, it usually means that it "
5757 "was not installed properly, or its distribution file was "
5758 "not unpacked properly.\nSee the README.W32 file in the "
5759 "top-level Emacs directory for more information.",
5760 init_file_name, load_path);
5761 MessageBox (NULL,
5762 buffer,
5763 "Emacs Abort Dialog",
5764 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
5765 /* Use the low-level Emacs abort. */
5766 #undef abort
5767 abort ();
5769 else
5771 _close (fd);
5776 void
5777 term_ntproc (void)
5779 #ifdef HAVE_SOCKETS
5780 /* shutdown the socket interface if necessary */
5781 term_winsock ();
5782 #endif
5784 term_w32select ();
5787 void
5788 init_ntproc (void)
5790 #ifdef HAVE_SOCKETS
5791 /* Initialise the socket interface now if available and requested by
5792 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5793 delayed until open-network-stream is called (w32-has-winsock can
5794 also be used to dynamically load or reload winsock).
5796 Conveniently, init_environment is called before us, so
5797 PRELOAD_WINSOCK can be set in the registry. */
5799 /* Always initialize this correctly. */
5800 winsock_lib = NULL;
5802 if (getenv ("PRELOAD_WINSOCK") != NULL)
5803 init_winsock (TRUE);
5804 #endif
5806 /* Initial preparation for subprocess support: replace our standard
5807 handles with non-inheritable versions. */
5809 HANDLE parent;
5810 HANDLE stdin_save = INVALID_HANDLE_VALUE;
5811 HANDLE stdout_save = INVALID_HANDLE_VALUE;
5812 HANDLE stderr_save = INVALID_HANDLE_VALUE;
5814 parent = GetCurrentProcess ();
5816 /* ignore errors when duplicating and closing; typically the
5817 handles will be invalid when running as a gui program. */
5818 DuplicateHandle (parent,
5819 GetStdHandle (STD_INPUT_HANDLE),
5820 parent,
5821 &stdin_save,
5823 FALSE,
5824 DUPLICATE_SAME_ACCESS);
5826 DuplicateHandle (parent,
5827 GetStdHandle (STD_OUTPUT_HANDLE),
5828 parent,
5829 &stdout_save,
5831 FALSE,
5832 DUPLICATE_SAME_ACCESS);
5834 DuplicateHandle (parent,
5835 GetStdHandle (STD_ERROR_HANDLE),
5836 parent,
5837 &stderr_save,
5839 FALSE,
5840 DUPLICATE_SAME_ACCESS);
5842 fclose (stdin);
5843 fclose (stdout);
5844 fclose (stderr);
5846 if (stdin_save != INVALID_HANDLE_VALUE)
5847 _open_osfhandle ((long) stdin_save, O_TEXT);
5848 else
5849 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
5850 _fdopen (0, "r");
5852 if (stdout_save != INVALID_HANDLE_VALUE)
5853 _open_osfhandle ((long) stdout_save, O_TEXT);
5854 else
5855 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5856 _fdopen (1, "w");
5858 if (stderr_save != INVALID_HANDLE_VALUE)
5859 _open_osfhandle ((long) stderr_save, O_TEXT);
5860 else
5861 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5862 _fdopen (2, "w");
5865 /* unfortunately, atexit depends on implementation of malloc */
5866 /* atexit (term_ntproc); */
5867 signal (SIGABRT, term_ntproc);
5869 /* determine which drives are fixed, for GetCachedVolumeInformation */
5871 /* GetDriveType must have trailing backslash. */
5872 char drive[] = "A:\\";
5874 /* Loop over all possible drive letters */
5875 while (*drive <= 'Z')
5877 /* Record if this drive letter refers to a fixed drive. */
5878 fixed_drives[DRIVE_INDEX (*drive)] =
5879 (GetDriveType (drive) == DRIVE_FIXED);
5881 (*drive)++;
5884 /* Reset the volume info cache. */
5885 volume_cache = NULL;
5888 /* Check to see if Emacs has been installed correctly. */
5889 check_windows_init_file ();
5893 shutdown_handler ensures that buffers' autosave files are
5894 up to date when the user logs off, or the system shuts down.
5896 BOOL WINAPI
5897 shutdown_handler (DWORD type)
5899 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5900 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
5901 || type == CTRL_LOGOFF_EVENT /* User logs off. */
5902 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
5904 /* Shut down cleanly, making sure autosave files are up to date. */
5905 shut_down_emacs (0, 0, Qnil);
5908 /* Allow other handlers to handle this signal. */
5909 return FALSE;
5913 globals_of_w32 is used to initialize those global variables that
5914 must always be initialized on startup even when the global variable
5915 initialized is non zero (see the function main in emacs.c).
5917 void
5918 globals_of_w32 (void)
5920 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
5922 get_process_times_fn = (GetProcessTimes_Proc)
5923 GetProcAddress (kernel32, "GetProcessTimes");
5925 g_b_init_is_windows_9x = 0;
5926 g_b_init_open_process_token = 0;
5927 g_b_init_get_token_information = 0;
5928 g_b_init_lookup_account_sid = 0;
5929 g_b_init_get_sid_identifier_authority = 0;
5930 g_b_init_get_sid_sub_authority = 0;
5931 g_b_init_get_sid_sub_authority_count = 0;
5932 g_b_init_get_file_security = 0;
5933 g_b_init_get_security_descriptor_owner = 0;
5934 g_b_init_get_security_descriptor_group = 0;
5935 g_b_init_is_valid_sid = 0;
5936 g_b_init_create_toolhelp32_snapshot = 0;
5937 g_b_init_process32_first = 0;
5938 g_b_init_process32_next = 0;
5939 g_b_init_open_thread_token = 0;
5940 g_b_init_impersonate_self = 0;
5941 g_b_init_revert_to_self = 0;
5942 g_b_init_get_process_memory_info = 0;
5943 g_b_init_get_process_working_set_size = 0;
5944 g_b_init_global_memory_status = 0;
5945 g_b_init_global_memory_status_ex = 0;
5946 g_b_init_equal_sid = 0;
5947 g_b_init_copy_sid = 0;
5948 g_b_init_get_length_sid = 0;
5949 g_b_init_get_native_system_info = 0;
5950 g_b_init_get_system_times = 0;
5951 num_of_processors = 0;
5952 /* The following sets a handler for shutdown notifications for
5953 console apps. This actually applies to Emacs in both console and
5954 GUI modes, since we had to fool windows into thinking emacs is a
5955 console application to get console mode to work. */
5956 SetConsoleCtrlHandler (shutdown_handler, TRUE);
5958 /* "None" is the default group name on standalone workstations. */
5959 strcpy (dflt_group_name, "None");
5962 /* For make-serial-process */
5964 serial_open (char *port)
5966 HANDLE hnd;
5967 child_process *cp;
5968 int fd = -1;
5970 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
5971 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
5972 if (hnd == INVALID_HANDLE_VALUE)
5973 error ("Could not open %s", port);
5974 fd = (int) _open_osfhandle ((int) hnd, 0);
5975 if (fd == -1)
5976 error ("Could not open %s", port);
5978 cp = new_child ();
5979 if (!cp)
5980 error ("Could not create child process");
5981 cp->fd = fd;
5982 cp->status = STATUS_READ_ACKNOWLEDGED;
5983 fd_info[ fd ].hnd = hnd;
5984 fd_info[ fd ].flags |=
5985 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
5986 if (fd_info[ fd ].cp != NULL)
5988 error ("fd_info[fd = %d] is already in use", fd);
5990 fd_info[ fd ].cp = cp;
5991 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5992 if (cp->ovl_read.hEvent == NULL)
5993 error ("Could not create read event");
5994 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5995 if (cp->ovl_write.hEvent == NULL)
5996 error ("Could not create write event");
5998 return fd;
6001 /* For serial-process-configure */
6002 void
6003 serial_configure (struct Lisp_Process *p,
6004 Lisp_Object contact)
6006 Lisp_Object childp2 = Qnil;
6007 Lisp_Object tem = Qnil;
6008 HANDLE hnd;
6009 DCB dcb;
6010 COMMTIMEOUTS ct;
6011 char summary[4] = "???"; /* This usually becomes "8N1". */
6013 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
6014 error ("Not a serial process");
6015 hnd = fd_info[ p->outfd ].hnd;
6017 childp2 = Fcopy_sequence (p->childp);
6019 /* Initialize timeouts for blocking read and blocking write. */
6020 if (!GetCommTimeouts (hnd, &ct))
6021 error ("GetCommTimeouts() failed");
6022 ct.ReadIntervalTimeout = 0;
6023 ct.ReadTotalTimeoutMultiplier = 0;
6024 ct.ReadTotalTimeoutConstant = 0;
6025 ct.WriteTotalTimeoutMultiplier = 0;
6026 ct.WriteTotalTimeoutConstant = 0;
6027 if (!SetCommTimeouts (hnd, &ct))
6028 error ("SetCommTimeouts() failed");
6029 /* Read port attributes and prepare default configuration. */
6030 memset (&dcb, 0, sizeof (dcb));
6031 dcb.DCBlength = sizeof (DCB);
6032 if (!GetCommState (hnd, &dcb))
6033 error ("GetCommState() failed");
6034 dcb.fBinary = TRUE;
6035 dcb.fNull = FALSE;
6036 dcb.fAbortOnError = FALSE;
6037 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6038 dcb.ErrorChar = 0;
6039 dcb.EofChar = 0;
6040 dcb.EvtChar = 0;
6042 /* Configure speed. */
6043 if (!NILP (Fplist_member (contact, QCspeed)))
6044 tem = Fplist_get (contact, QCspeed);
6045 else
6046 tem = Fplist_get (p->childp, QCspeed);
6047 CHECK_NUMBER (tem);
6048 dcb.BaudRate = XINT (tem);
6049 childp2 = Fplist_put (childp2, QCspeed, tem);
6051 /* Configure bytesize. */
6052 if (!NILP (Fplist_member (contact, QCbytesize)))
6053 tem = Fplist_get (contact, QCbytesize);
6054 else
6055 tem = Fplist_get (p->childp, QCbytesize);
6056 if (NILP (tem))
6057 tem = make_number (8);
6058 CHECK_NUMBER (tem);
6059 if (XINT (tem) != 7 && XINT (tem) != 8)
6060 error (":bytesize must be nil (8), 7, or 8");
6061 dcb.ByteSize = XINT (tem);
6062 summary[0] = XINT (tem) + '0';
6063 childp2 = Fplist_put (childp2, QCbytesize, tem);
6065 /* Configure parity. */
6066 if (!NILP (Fplist_member (contact, QCparity)))
6067 tem = Fplist_get (contact, QCparity);
6068 else
6069 tem = Fplist_get (p->childp, QCparity);
6070 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
6071 error (":parity must be nil (no parity), `even', or `odd'");
6072 dcb.fParity = FALSE;
6073 dcb.Parity = NOPARITY;
6074 dcb.fErrorChar = FALSE;
6075 if (NILP (tem))
6077 summary[1] = 'N';
6079 else if (EQ (tem, Qeven))
6081 summary[1] = 'E';
6082 dcb.fParity = TRUE;
6083 dcb.Parity = EVENPARITY;
6084 dcb.fErrorChar = TRUE;
6086 else if (EQ (tem, Qodd))
6088 summary[1] = 'O';
6089 dcb.fParity = TRUE;
6090 dcb.Parity = ODDPARITY;
6091 dcb.fErrorChar = TRUE;
6093 childp2 = Fplist_put (childp2, QCparity, tem);
6095 /* Configure stopbits. */
6096 if (!NILP (Fplist_member (contact, QCstopbits)))
6097 tem = Fplist_get (contact, QCstopbits);
6098 else
6099 tem = Fplist_get (p->childp, QCstopbits);
6100 if (NILP (tem))
6101 tem = make_number (1);
6102 CHECK_NUMBER (tem);
6103 if (XINT (tem) != 1 && XINT (tem) != 2)
6104 error (":stopbits must be nil (1 stopbit), 1, or 2");
6105 summary[2] = XINT (tem) + '0';
6106 if (XINT (tem) == 1)
6107 dcb.StopBits = ONESTOPBIT;
6108 else if (XINT (tem) == 2)
6109 dcb.StopBits = TWOSTOPBITS;
6110 childp2 = Fplist_put (childp2, QCstopbits, tem);
6112 /* Configure flowcontrol. */
6113 if (!NILP (Fplist_member (contact, QCflowcontrol)))
6114 tem = Fplist_get (contact, QCflowcontrol);
6115 else
6116 tem = Fplist_get (p->childp, QCflowcontrol);
6117 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
6118 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6119 dcb.fOutxCtsFlow = FALSE;
6120 dcb.fOutxDsrFlow = FALSE;
6121 dcb.fDtrControl = DTR_CONTROL_DISABLE;
6122 dcb.fDsrSensitivity = FALSE;
6123 dcb.fTXContinueOnXoff = FALSE;
6124 dcb.fOutX = FALSE;
6125 dcb.fInX = FALSE;
6126 dcb.fRtsControl = RTS_CONTROL_DISABLE;
6127 dcb.XonChar = 17; /* Control-Q */
6128 dcb.XoffChar = 19; /* Control-S */
6129 if (NILP (tem))
6131 /* Already configured. */
6133 else if (EQ (tem, Qhw))
6135 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
6136 dcb.fOutxCtsFlow = TRUE;
6138 else if (EQ (tem, Qsw))
6140 dcb.fOutX = TRUE;
6141 dcb.fInX = TRUE;
6143 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
6145 /* Activate configuration. */
6146 if (!SetCommState (hnd, &dcb))
6147 error ("SetCommState() failed");
6149 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
6150 p->childp = childp2;
6153 /* end of w32.c */
6155 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
6156 (do not change this comment) */