Change by author without assignment thankfully tiny.
[emacs.git] / src / w32.c
blobc7af7f0634076ec8f53f34bae6b73abd6e4690a3
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 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 <io.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <ctype.h>
30 #include <signal.h>
31 #include <sys/file.h>
32 #include <sys/time.h>
33 #include <sys/utime.h>
34 #include <mbstring.h> /* for _mbspbrk */
35 #include <math.h>
37 /* must include CRT headers *before* config.h */
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
43 #undef access
44 #undef chdir
45 #undef chmod
46 #undef creat
47 #undef ctime
48 #undef fopen
49 #undef link
50 #undef mkdir
51 #undef mktemp
52 #undef open
53 #undef rename
54 #undef rmdir
55 #undef unlink
57 #undef close
58 #undef dup
59 #undef dup2
60 #undef pipe
61 #undef read
62 #undef write
64 #undef strerror
66 #include "lisp.h"
68 #include <pwd.h>
69 #include <grp.h>
71 #ifdef __GNUC__
72 #define _ANONYMOUS_UNION
73 #define _ANONYMOUS_STRUCT
74 #endif
75 #include <windows.h>
76 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
77 use a different name to avoid compilation problems. */
78 typedef struct _MEMORY_STATUS_EX {
79 DWORD dwLength;
80 DWORD dwMemoryLoad;
81 DWORDLONG ullTotalPhys;
82 DWORDLONG ullAvailPhys;
83 DWORDLONG ullTotalPageFile;
84 DWORDLONG ullAvailPageFile;
85 DWORDLONG ullTotalVirtual;
86 DWORDLONG ullAvailVirtual;
87 DWORDLONG ullAvailExtendedVirtual;
88 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
90 #include <lmcons.h>
91 #include <shlobj.h>
93 #include <tlhelp32.h>
94 #include <psapi.h>
95 /* This either is not in psapi.h or guarded by higher value of
96 _WIN32_WINNT than what we use. */
97 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
98 DWORD cb;
99 DWORD PageFaultCount;
100 DWORD PeakWorkingSetSize;
101 DWORD WorkingSetSize;
102 DWORD QuotaPeakPagedPoolUsage;
103 DWORD QuotaPagedPoolUsage;
104 DWORD QuotaPeakNonPagedPoolUsage;
105 DWORD QuotaNonPagedPoolUsage;
106 DWORD PagefileUsage;
107 DWORD PeakPagefileUsage;
108 DWORD PrivateUsage;
109 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
111 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
112 #include <sys/socket.h>
113 #undef socket
114 #undef bind
115 #undef connect
116 #undef htons
117 #undef ntohs
118 #undef inet_addr
119 #undef gethostname
120 #undef gethostbyname
121 #undef getservbyname
122 #undef getpeername
123 #undef shutdown
124 #undef setsockopt
125 #undef listen
126 #undef getsockname
127 #undef accept
128 #undef recvfrom
129 #undef sendto
130 #endif
132 #include "w32.h"
133 #include "ndir.h"
134 #include "w32heap.h"
135 #include "systime.h"
136 #include "dispextern.h" /* for xstrcasecmp */
137 #include "coding.h" /* for Vlocale_coding_system */
139 /* For serial_configure and serial_open. */
140 #include "process.h"
141 /* From process.c */
142 extern Lisp_Object QCport, QCspeed, QCprocess;
143 extern Lisp_Object QCbytesize, QCstopbits, QCparity, Qodd, Qeven;
144 extern Lisp_Object QCflowcontrol, Qhw, Qsw, QCsummary;
146 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
147 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
149 void globals_of_w32 ();
150 static DWORD get_rid (PSID);
152 extern Lisp_Object Vw32_downcase_file_names;
153 extern Lisp_Object Vw32_generate_fake_inodes;
154 extern Lisp_Object Vw32_get_true_file_attributes;
155 /* Defined in process.c for its own purpose. */
156 extern Lisp_Object Qlocal;
158 extern int w32_num_mouse_buttons;
161 /* Initialization states.
163 WARNING: If you add any more such variables for additional APIs,
164 you MUST add initialization for them to globals_of_w32
165 below. This is because these variables might get set
166 to non-NULL values during dumping, but the dumped Emacs
167 cannot reuse those values, because it could be run on a
168 different version of the OS, where API addresses are
169 different. */
170 static BOOL g_b_init_is_windows_9x;
171 static BOOL g_b_init_open_process_token;
172 static BOOL g_b_init_get_token_information;
173 static BOOL g_b_init_lookup_account_sid;
174 static BOOL g_b_init_get_sid_identifier_authority;
175 static BOOL g_b_init_get_sid_sub_authority;
176 static BOOL g_b_init_get_sid_sub_authority_count;
177 static BOOL g_b_init_get_file_security;
178 static BOOL g_b_init_get_security_descriptor_owner;
179 static BOOL g_b_init_get_security_descriptor_group;
180 static BOOL g_b_init_is_valid_sid;
181 static BOOL g_b_init_create_toolhelp32_snapshot;
182 static BOOL g_b_init_process32_first;
183 static BOOL g_b_init_process32_next;
184 static BOOL g_b_init_open_thread_token;
185 static BOOL g_b_init_impersonate_self;
186 static BOOL g_b_init_revert_to_self;
187 static BOOL g_b_init_get_process_memory_info;
188 static BOOL g_b_init_get_process_working_set_size;
189 static BOOL g_b_init_global_memory_status;
190 static BOOL g_b_init_global_memory_status_ex;
191 static BOOL g_b_init_get_length_sid;
192 static BOOL g_b_init_equal_sid;
193 static BOOL g_b_init_copy_sid;
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);
299 /* ** A utility function ** */
300 static BOOL
301 is_windows_9x ()
303 static BOOL s_b_ret=0;
304 OSVERSIONINFO os_ver;
305 if (g_b_init_is_windows_9x == 0)
307 g_b_init_is_windows_9x = 1;
308 ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
309 os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
310 if (GetVersionEx (&os_ver))
312 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
315 return s_b_ret;
318 /* Get total user and system times for get-internal-run-time.
319 Returns a list of three integers if the times are provided by the OS
320 (NT derivatives), otherwise it returns the result of current-time. */
321 Lisp_Object
322 w32_get_internal_run_time ()
324 if (get_process_times_fn)
326 FILETIME create, exit, kernel, user;
327 HANDLE proc = GetCurrentProcess();
328 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
330 LARGE_INTEGER user_int, kernel_int, total;
331 int microseconds;
332 user_int.LowPart = user.dwLowDateTime;
333 user_int.HighPart = user.dwHighDateTime;
334 kernel_int.LowPart = kernel.dwLowDateTime;
335 kernel_int.HighPart = kernel.dwHighDateTime;
336 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
337 /* FILETIME is 100 nanosecond increments, Emacs only wants
338 microsecond resolution. */
339 total.QuadPart /= 10;
340 microseconds = total.QuadPart % 1000000;
341 total.QuadPart /= 1000000;
343 /* Sanity check to make sure we can represent the result. */
344 if (total.HighPart == 0)
346 int secs = total.LowPart;
348 return list3 (make_number ((secs >> 16) & 0xffff),
349 make_number (secs & 0xffff),
350 make_number (microseconds));
355 return Fcurrent_time ();
358 /* ** The wrapper functions ** */
360 BOOL WINAPI open_process_token (
361 HANDLE ProcessHandle,
362 DWORD DesiredAccess,
363 PHANDLE TokenHandle)
365 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
366 HMODULE hm_advapi32 = NULL;
367 if (is_windows_9x () == TRUE)
369 return FALSE;
371 if (g_b_init_open_process_token == 0)
373 g_b_init_open_process_token = 1;
374 hm_advapi32 = LoadLibrary ("Advapi32.dll");
375 s_pfn_Open_Process_Token =
376 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
378 if (s_pfn_Open_Process_Token == NULL)
380 return FALSE;
382 return (
383 s_pfn_Open_Process_Token (
384 ProcessHandle,
385 DesiredAccess,
386 TokenHandle)
390 BOOL WINAPI get_token_information (
391 HANDLE TokenHandle,
392 TOKEN_INFORMATION_CLASS TokenInformationClass,
393 LPVOID TokenInformation,
394 DWORD TokenInformationLength,
395 PDWORD ReturnLength)
397 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
398 HMODULE hm_advapi32 = NULL;
399 if (is_windows_9x () == TRUE)
401 return FALSE;
403 if (g_b_init_get_token_information == 0)
405 g_b_init_get_token_information = 1;
406 hm_advapi32 = LoadLibrary ("Advapi32.dll");
407 s_pfn_Get_Token_Information =
408 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
410 if (s_pfn_Get_Token_Information == NULL)
412 return FALSE;
414 return (
415 s_pfn_Get_Token_Information (
416 TokenHandle,
417 TokenInformationClass,
418 TokenInformation,
419 TokenInformationLength,
420 ReturnLength)
424 BOOL WINAPI lookup_account_sid (
425 LPCTSTR lpSystemName,
426 PSID Sid,
427 LPTSTR Name,
428 LPDWORD cbName,
429 LPTSTR DomainName,
430 LPDWORD cbDomainName,
431 PSID_NAME_USE peUse)
433 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
434 HMODULE hm_advapi32 = NULL;
435 if (is_windows_9x () == TRUE)
437 return FALSE;
439 if (g_b_init_lookup_account_sid == 0)
441 g_b_init_lookup_account_sid = 1;
442 hm_advapi32 = LoadLibrary ("Advapi32.dll");
443 s_pfn_Lookup_Account_Sid =
444 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
446 if (s_pfn_Lookup_Account_Sid == NULL)
448 return FALSE;
450 return (
451 s_pfn_Lookup_Account_Sid (
452 lpSystemName,
453 Sid,
454 Name,
455 cbName,
456 DomainName,
457 cbDomainName,
458 peUse)
462 PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority (
463 PSID pSid)
465 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority = NULL;
466 HMODULE hm_advapi32 = NULL;
467 if (is_windows_9x () == TRUE)
469 return NULL;
471 if (g_b_init_get_sid_identifier_authority == 0)
473 g_b_init_get_sid_identifier_authority = 1;
474 hm_advapi32 = LoadLibrary ("Advapi32.dll");
475 s_pfn_Get_Sid_Identifier_Authority =
476 (GetSidIdentifierAuthority_Proc) GetProcAddress (
477 hm_advapi32, "GetSidIdentifierAuthority");
479 if (s_pfn_Get_Sid_Identifier_Authority == NULL)
481 return NULL;
483 return (s_pfn_Get_Sid_Identifier_Authority (pSid));
486 PDWORD WINAPI get_sid_sub_authority (
487 PSID pSid,
488 DWORD n)
490 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
491 static DWORD zero = 0U;
492 HMODULE hm_advapi32 = NULL;
493 if (is_windows_9x () == TRUE)
495 return &zero;
497 if (g_b_init_get_sid_sub_authority == 0)
499 g_b_init_get_sid_sub_authority = 1;
500 hm_advapi32 = LoadLibrary ("Advapi32.dll");
501 s_pfn_Get_Sid_Sub_Authority =
502 (GetSidSubAuthority_Proc) GetProcAddress (
503 hm_advapi32, "GetSidSubAuthority");
505 if (s_pfn_Get_Sid_Sub_Authority == NULL)
507 return &zero;
509 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
512 PUCHAR WINAPI get_sid_sub_authority_count (
513 PSID pSid)
515 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
516 static UCHAR zero = 0U;
517 HMODULE hm_advapi32 = NULL;
518 if (is_windows_9x () == TRUE)
520 return &zero;
522 if (g_b_init_get_sid_sub_authority_count == 0)
524 g_b_init_get_sid_sub_authority_count = 1;
525 hm_advapi32 = LoadLibrary ("Advapi32.dll");
526 s_pfn_Get_Sid_Sub_Authority_Count =
527 (GetSidSubAuthorityCount_Proc) GetProcAddress (
528 hm_advapi32, "GetSidSubAuthorityCount");
530 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
532 return &zero;
534 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
537 BOOL WINAPI get_file_security (
538 LPCTSTR lpFileName,
539 SECURITY_INFORMATION RequestedInformation,
540 PSECURITY_DESCRIPTOR pSecurityDescriptor,
541 DWORD nLength,
542 LPDWORD lpnLengthNeeded)
544 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
545 HMODULE hm_advapi32 = NULL;
546 if (is_windows_9x () == TRUE)
548 return FALSE;
550 if (g_b_init_get_file_security == 0)
552 g_b_init_get_file_security = 1;
553 hm_advapi32 = LoadLibrary ("Advapi32.dll");
554 s_pfn_Get_File_Security =
555 (GetFileSecurity_Proc) GetProcAddress (
556 hm_advapi32, GetFileSecurity_Name);
558 if (s_pfn_Get_File_Security == NULL)
560 return FALSE;
562 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
563 pSecurityDescriptor, nLength,
564 lpnLengthNeeded));
567 BOOL WINAPI get_security_descriptor_owner (
568 PSECURITY_DESCRIPTOR pSecurityDescriptor,
569 PSID *pOwner,
570 LPBOOL lpbOwnerDefaulted)
572 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
573 HMODULE hm_advapi32 = NULL;
574 if (is_windows_9x () == TRUE)
576 return FALSE;
578 if (g_b_init_get_security_descriptor_owner == 0)
580 g_b_init_get_security_descriptor_owner = 1;
581 hm_advapi32 = LoadLibrary ("Advapi32.dll");
582 s_pfn_Get_Security_Descriptor_Owner =
583 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
584 hm_advapi32, "GetSecurityDescriptorOwner");
586 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
588 return FALSE;
590 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
591 lpbOwnerDefaulted));
594 BOOL WINAPI get_security_descriptor_group (
595 PSECURITY_DESCRIPTOR pSecurityDescriptor,
596 PSID *pGroup,
597 LPBOOL lpbGroupDefaulted)
599 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
600 HMODULE hm_advapi32 = NULL;
601 if (is_windows_9x () == TRUE)
603 return FALSE;
605 if (g_b_init_get_security_descriptor_group == 0)
607 g_b_init_get_security_descriptor_group = 1;
608 hm_advapi32 = LoadLibrary ("Advapi32.dll");
609 s_pfn_Get_Security_Descriptor_Group =
610 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
611 hm_advapi32, "GetSecurityDescriptorGroup");
613 if (s_pfn_Get_Security_Descriptor_Group == NULL)
615 return FALSE;
617 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
618 lpbGroupDefaulted));
621 BOOL WINAPI is_valid_sid (
622 PSID sid)
624 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
625 HMODULE hm_advapi32 = NULL;
626 if (is_windows_9x () == TRUE)
628 return FALSE;
630 if (g_b_init_is_valid_sid == 0)
632 g_b_init_is_valid_sid = 1;
633 hm_advapi32 = LoadLibrary ("Advapi32.dll");
634 s_pfn_Is_Valid_Sid =
635 (IsValidSid_Proc) GetProcAddress (
636 hm_advapi32, "IsValidSid");
638 if (s_pfn_Is_Valid_Sid == NULL)
640 return FALSE;
642 return (s_pfn_Is_Valid_Sid (sid));
645 BOOL WINAPI equal_sid (
646 PSID sid1,
647 PSID sid2)
649 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
650 HMODULE hm_advapi32 = NULL;
651 if (is_windows_9x () == TRUE)
653 return FALSE;
655 if (g_b_init_equal_sid == 0)
657 g_b_init_equal_sid = 1;
658 hm_advapi32 = LoadLibrary ("Advapi32.dll");
659 s_pfn_Equal_Sid =
660 (EqualSid_Proc) GetProcAddress (
661 hm_advapi32, "EqualSid");
663 if (s_pfn_Equal_Sid == NULL)
665 return FALSE;
667 return (s_pfn_Equal_Sid (sid1, sid2));
670 DWORD WINAPI get_length_sid (
671 PSID sid)
673 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
674 HMODULE hm_advapi32 = NULL;
675 if (is_windows_9x () == TRUE)
677 return 0;
679 if (g_b_init_get_length_sid == 0)
681 g_b_init_get_length_sid = 1;
682 hm_advapi32 = LoadLibrary ("Advapi32.dll");
683 s_pfn_Get_Length_Sid =
684 (GetLengthSid_Proc) GetProcAddress (
685 hm_advapi32, "GetLengthSid");
687 if (s_pfn_Get_Length_Sid == NULL)
689 return 0;
691 return (s_pfn_Get_Length_Sid (sid));
694 BOOL WINAPI copy_sid (
695 DWORD destlen,
696 PSID dest,
697 PSID src)
699 static CopySid_Proc s_pfn_Copy_Sid = NULL;
700 HMODULE hm_advapi32 = NULL;
701 if (is_windows_9x () == TRUE)
703 return FALSE;
705 if (g_b_init_copy_sid == 0)
707 g_b_init_copy_sid = 1;
708 hm_advapi32 = LoadLibrary ("Advapi32.dll");
709 s_pfn_Copy_Sid =
710 (CopySid_Proc) GetProcAddress (
711 hm_advapi32, "CopySid");
713 if (s_pfn_Copy_Sid == NULL)
715 return FALSE;
717 return (s_pfn_Copy_Sid (destlen, dest, src));
721 END: Wrapper functions around OpenProcessToken
722 and other functions in advapi32.dll that are only
723 supported in Windows NT / 2k / XP
727 /* Equivalent of strerror for W32 error codes. */
728 char *
729 w32_strerror (int error_no)
731 static char buf[500];
733 if (error_no == 0)
734 error_no = GetLastError ();
736 buf[0] = '\0';
737 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
738 error_no,
739 0, /* choose most suitable language */
740 buf, sizeof (buf), NULL))
741 sprintf (buf, "w32 error %u", error_no);
742 return buf;
745 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
746 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
748 This is called from alloc.c:valid_pointer_p. */
750 w32_valid_pointer_p (void *p, int size)
752 SIZE_T done;
753 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
755 if (h)
757 unsigned char *buf = alloca (size);
758 int retval = ReadProcessMemory (h, p, buf, size, &done);
760 CloseHandle (h);
761 return retval;
763 else
764 return -1;
767 static char startup_dir[MAXPATHLEN];
769 /* Get the current working directory. */
770 char *
771 getwd (char *dir)
773 #if 0
774 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
775 return dir;
776 return NULL;
777 #else
778 /* Emacs doesn't actually change directory itself, and we want to
779 force our real wd to be where emacs.exe is to avoid unnecessary
780 conflicts when trying to rename or delete directories. */
781 strcpy (dir, startup_dir);
782 return dir;
783 #endif
786 #ifndef HAVE_SOCKETS
787 /* Emulate gethostname. */
789 gethostname (char *buffer, int size)
791 /* NT only allows small host names, so the buffer is
792 certainly large enough. */
793 return !GetComputerName (buffer, &size);
795 #endif /* HAVE_SOCKETS */
797 /* Emulate getloadavg. */
799 getloadavg (double loadavg[], int nelem)
801 int i;
803 /* A faithful emulation is going to have to be saved for a rainy day. */
804 for (i = 0; i < nelem; i++)
806 loadavg[i] = 0.0;
808 return i;
811 /* Emulate getpwuid, getpwnam and others. */
813 #define PASSWD_FIELD_SIZE 256
815 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
816 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
817 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
818 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
819 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
821 static struct passwd dflt_passwd =
823 dflt_passwd_name,
824 dflt_passwd_passwd,
828 dflt_passwd_gecos,
829 dflt_passwd_dir,
830 dflt_passwd_shell,
833 static char dflt_group_name[GNLEN+1];
835 static struct group dflt_group =
837 /* When group information is not available, we return this as the
838 group for all files. */
839 dflt_group_name,
844 getuid ()
846 return dflt_passwd.pw_uid;
850 geteuid ()
852 /* I could imagine arguing for checking to see whether the user is
853 in the Administrators group and returning a UID of 0 for that
854 case, but I don't know how wise that would be in the long run. */
855 return getuid ();
859 getgid ()
861 return dflt_passwd.pw_gid;
865 getegid ()
867 return getgid ();
870 struct passwd *
871 getpwuid (int uid)
873 if (uid == dflt_passwd.pw_uid)
874 return &dflt_passwd;
875 return NULL;
878 struct group *
879 getgrgid (gid_t gid)
881 return &dflt_group;
884 struct passwd *
885 getpwnam (char *name)
887 struct passwd *pw;
889 pw = getpwuid (getuid ());
890 if (!pw)
891 return pw;
893 if (xstrcasecmp (name, pw->pw_name))
894 return NULL;
896 return pw;
899 void
900 init_user_info ()
902 /* Find the user's real name by opening the process token and
903 looking up the name associated with the user-sid in that token.
905 Use the relative portion of the identifier authority value from
906 the user-sid as the user id value (same for group id using the
907 primary group sid from the process token). */
909 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
910 DWORD ulength = sizeof (uname), dlength = sizeof (domain), trash;
911 DWORD glength = sizeof (gname);
912 HANDLE token = NULL;
913 SID_NAME_USE user_type;
914 unsigned char buf[1024];
915 TOKEN_USER user_token;
916 TOKEN_PRIMARY_GROUP group_token;
918 if (open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
919 && get_token_information (token, TokenUser,
920 (PVOID)buf, sizeof (buf), &trash)
921 && (memcpy (&user_token, buf, sizeof (user_token)),
922 lookup_account_sid (NULL, user_token.User.Sid, uname, &ulength,
923 domain, &dlength, &user_type)))
925 strcpy (dflt_passwd.pw_name, uname);
926 /* Determine a reasonable uid value. */
927 if (xstrcasecmp ("administrator", uname) == 0)
929 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
930 dflt_passwd.pw_gid = 513; /* well-known None gid */
932 else
934 /* Use the last sub-authority value of the RID, the relative
935 portion of the SID, as user/group ID. */
936 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
938 /* Get group id and name. */
939 if (get_token_information (token, TokenPrimaryGroup,
940 (PVOID)buf, sizeof (buf), &trash))
942 memcpy (&group_token, buf, sizeof (group_token));
943 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
944 dlength = sizeof (domain);
945 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
946 gname, &glength, NULL, &dlength,
947 &user_type))
948 strcpy (dflt_group_name, gname);
950 else
951 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
954 /* If security calls are not supported (presumably because we
955 are running under Windows 95), fallback to this. */
956 else if (GetUserName (uname, &ulength))
958 strcpy (dflt_passwd.pw_name, uname);
959 if (xstrcasecmp ("administrator", uname) == 0)
960 dflt_passwd.pw_uid = 0;
961 else
962 dflt_passwd.pw_uid = 123;
963 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
965 else
967 strcpy (dflt_passwd.pw_name, "unknown");
968 dflt_passwd.pw_uid = 123;
969 dflt_passwd.pw_gid = 123;
971 dflt_group.gr_gid = dflt_passwd.pw_gid;
973 /* Ensure HOME and SHELL are defined. */
974 if (getenv ("HOME") == NULL)
975 abort ();
976 if (getenv ("SHELL") == NULL)
977 abort ();
979 /* Set dir and shell from environment variables. */
980 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
981 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
983 if (token)
984 CloseHandle (token);
988 random ()
990 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
991 return ((rand () << 15) | rand ());
994 void
995 srandom (int seed)
997 srand (seed);
1001 /* Normalize filename by converting all path separators to
1002 the specified separator. Also conditionally convert upper
1003 case path name components to lower case. */
1005 static void
1006 normalize_filename (fp, path_sep)
1007 register char *fp;
1008 char path_sep;
1010 char sep;
1011 char *elem;
1013 /* Always lower-case drive letters a-z, even if the filesystem
1014 preserves case in filenames.
1015 This is so filenames can be compared by string comparison
1016 functions that are case-sensitive. Even case-preserving filesystems
1017 do not distinguish case in drive letters. */
1018 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
1020 *fp += 'a' - 'A';
1021 fp += 2;
1024 if (NILP (Vw32_downcase_file_names))
1026 while (*fp)
1028 if (*fp == '/' || *fp == '\\')
1029 *fp = path_sep;
1030 fp++;
1032 return;
1035 sep = path_sep; /* convert to this path separator */
1036 elem = fp; /* start of current path element */
1038 do {
1039 if (*fp >= 'a' && *fp <= 'z')
1040 elem = 0; /* don't convert this element */
1042 if (*fp == 0 || *fp == ':')
1044 sep = *fp; /* restore current separator (or 0) */
1045 *fp = '/'; /* after conversion of this element */
1048 if (*fp == '/' || *fp == '\\')
1050 if (elem && elem != fp)
1052 *fp = 0; /* temporary end of string */
1053 _strlwr (elem); /* while we convert to lower case */
1055 *fp = sep; /* convert (or restore) path separator */
1056 elem = fp + 1; /* next element starts after separator */
1057 sep = path_sep;
1059 } while (*fp++);
1062 /* Destructively turn backslashes into slashes. */
1063 void
1064 dostounix_filename (p)
1065 register char *p;
1067 normalize_filename (p, '/');
1070 /* Destructively turn slashes into backslashes. */
1071 void
1072 unixtodos_filename (p)
1073 register char *p;
1075 normalize_filename (p, '\\');
1078 /* Remove all CR's that are followed by a LF.
1079 (From msdos.c...probably should figure out a way to share it,
1080 although this code isn't going to ever change.) */
1082 crlf_to_lf (n, buf)
1083 register int n;
1084 register unsigned char *buf;
1086 unsigned char *np = buf;
1087 unsigned char *startp = buf;
1088 unsigned char *endp = buf + n;
1090 if (n == 0)
1091 return n;
1092 while (buf < endp - 1)
1094 if (*buf == 0x0d)
1096 if (*(++buf) != 0x0a)
1097 *np++ = 0x0d;
1099 else
1100 *np++ = *buf++;
1102 if (buf < endp)
1103 *np++ = *buf++;
1104 return np - startp;
1107 /* Parse the root part of file name, if present. Return length and
1108 optionally store pointer to char after root. */
1109 static int
1110 parse_root (char * name, char ** pPath)
1112 char * start = name;
1114 if (name == NULL)
1115 return 0;
1117 /* find the root name of the volume if given */
1118 if (isalpha (name[0]) && name[1] == ':')
1120 /* skip past drive specifier */
1121 name += 2;
1122 if (IS_DIRECTORY_SEP (name[0]))
1123 name++;
1125 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1127 int slashes = 2;
1128 name += 2;
1131 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1132 break;
1133 name++;
1135 while ( *name );
1136 if (IS_DIRECTORY_SEP (name[0]))
1137 name++;
1140 if (pPath)
1141 *pPath = name;
1143 return name - start;
1146 /* Get long base name for name; name is assumed to be absolute. */
1147 static int
1148 get_long_basename (char * name, char * buf, int size)
1150 WIN32_FIND_DATA find_data;
1151 HANDLE dir_handle;
1152 int len = 0;
1154 /* must be valid filename, no wild cards or other invalid characters */
1155 if (_mbspbrk (name, "*?|<>\""))
1156 return 0;
1158 dir_handle = FindFirstFile (name, &find_data);
1159 if (dir_handle != INVALID_HANDLE_VALUE)
1161 if ((len = strlen (find_data.cFileName)) < size)
1162 memcpy (buf, find_data.cFileName, len + 1);
1163 else
1164 len = 0;
1165 FindClose (dir_handle);
1167 return len;
1170 /* Get long name for file, if possible (assumed to be absolute). */
1171 BOOL
1172 w32_get_long_filename (char * name, char * buf, int size)
1174 char * o = buf;
1175 char * p;
1176 char * q;
1177 char full[ MAX_PATH ];
1178 int len;
1180 len = strlen (name);
1181 if (len >= MAX_PATH)
1182 return FALSE;
1184 /* Use local copy for destructive modification. */
1185 memcpy (full, name, len+1);
1186 unixtodos_filename (full);
1188 /* Copy root part verbatim. */
1189 len = parse_root (full, &p);
1190 memcpy (o, full, len);
1191 o += len;
1192 *o = '\0';
1193 size -= len;
1195 while (p != NULL && *p)
1197 q = p;
1198 p = strchr (q, '\\');
1199 if (p) *p = '\0';
1200 len = get_long_basename (full, o, size);
1201 if (len > 0)
1203 o += len;
1204 size -= len;
1205 if (p != NULL)
1207 *p++ = '\\';
1208 if (size < 2)
1209 return FALSE;
1210 *o++ = '\\';
1211 size--;
1212 *o = '\0';
1215 else
1216 return FALSE;
1219 return TRUE;
1223 is_unc_volume (const char *filename)
1225 const char *ptr = filename;
1227 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1228 return 0;
1230 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1231 return 0;
1233 return 1;
1236 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1239 sigsetmask (int signal_mask)
1241 return 0;
1245 sigmask (int sig)
1247 return 0;
1251 sigblock (int sig)
1253 return 0;
1257 sigunblock (int sig)
1259 return 0;
1263 setpgrp (int pid, int gid)
1265 return 0;
1269 alarm (int seconds)
1271 return 0;
1274 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1276 LPBYTE
1277 w32_get_resource (key, lpdwtype)
1278 char *key;
1279 LPDWORD lpdwtype;
1281 LPBYTE lpvalue;
1282 HKEY hrootkey = NULL;
1283 DWORD cbData;
1285 /* Check both the current user and the local machine to see if
1286 we have any resources. */
1288 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1290 lpvalue = NULL;
1292 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1293 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1294 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1296 RegCloseKey (hrootkey);
1297 return (lpvalue);
1300 xfree (lpvalue);
1302 RegCloseKey (hrootkey);
1305 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1307 lpvalue = NULL;
1309 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1310 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1311 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1313 RegCloseKey (hrootkey);
1314 return (lpvalue);
1317 xfree (lpvalue);
1319 RegCloseKey (hrootkey);
1322 return (NULL);
1325 char *get_emacs_configuration (void);
1326 extern Lisp_Object Vsystem_configuration;
1328 void
1329 init_environment (char ** argv)
1331 static const char * const tempdirs[] = {
1332 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1335 int i;
1337 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1339 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1340 temporary files and assume "/tmp" if $TMPDIR is unset, which
1341 will break on DOS/Windows. Refuse to work if we cannot find
1342 a directory, not even "c:/", usable for that purpose. */
1343 for (i = 0; i < imax ; i++)
1345 const char *tmp = tempdirs[i];
1347 if (*tmp == '$')
1348 tmp = getenv (tmp + 1);
1349 /* Note that `access' can lie to us if the directory resides on a
1350 read-only filesystem, like CD-ROM or a write-protected floppy.
1351 The only way to be really sure is to actually create a file and
1352 see if it succeeds. But I think that's too much to ask. */
1353 if (tmp && _access (tmp, D_OK) == 0)
1355 char * var = alloca (strlen (tmp) + 8);
1356 sprintf (var, "TMPDIR=%s", tmp);
1357 _putenv (strdup (var));
1358 break;
1361 if (i >= imax)
1362 cmd_error_internal
1363 (Fcons (Qerror,
1364 Fcons (build_string ("no usable temporary directories found!!"),
1365 Qnil)),
1366 "While setting TMPDIR: ");
1368 /* Check for environment variables and use registry settings if they
1369 don't exist. Fallback on default values where applicable. */
1371 int i;
1372 LPBYTE lpval;
1373 DWORD dwType;
1374 char locale_name[32];
1375 struct stat ignored;
1376 char default_home[MAX_PATH];
1378 static const struct env_entry
1380 char * name;
1381 char * def_value;
1382 } dflt_envvars[] =
1384 {"HOME", "C:/"},
1385 {"PRELOAD_WINSOCK", NULL},
1386 {"emacs_dir", "C:/emacs"},
1387 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1388 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1389 {"EMACSDATA", "%emacs_dir%/etc"},
1390 {"EMACSPATH", "%emacs_dir%/bin"},
1391 /* We no longer set INFOPATH because Info-default-directory-list
1392 is then ignored. */
1393 /* {"INFOPATH", "%emacs_dir%/info"}, */
1394 {"EMACSDOC", "%emacs_dir%/etc"},
1395 {"TERM", "cmd"},
1396 {"LANG", NULL},
1399 #define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1401 /* We need to copy dflt_envvars[] and work on the copy because we
1402 don't want the dumped Emacs to inherit the values of
1403 environment variables we saw during dumping (which could be on
1404 a different system). The defaults above must be left intact. */
1405 struct env_entry env_vars[N_ENV_VARS];
1407 for (i = 0; i < N_ENV_VARS; i++)
1408 env_vars[i] = dflt_envvars[i];
1410 /* For backwards compatibility, check if a .emacs file exists in C:/
1411 If not, then we can try to default to the appdata directory under the
1412 user's profile, which is more likely to be writable. */
1413 if (stat ("C:/.emacs", &ignored) < 0)
1415 HRESULT profile_result;
1416 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1417 of Windows 95 and NT4 that have not been updated to include
1418 MSIE 5. Also we don't link with shell32.dll by default. */
1419 HMODULE shell32_dll;
1420 ShGetFolderPath_fn get_folder_path;
1421 shell32_dll = GetModuleHandle ("shell32.dll");
1422 get_folder_path = (ShGetFolderPath_fn)
1423 GetProcAddress (shell32_dll, "SHGetFolderPathA");
1425 if (get_folder_path != NULL)
1427 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1428 0, default_home);
1430 /* If we can't get the appdata dir, revert to old behavior. */
1431 if (profile_result == S_OK)
1432 env_vars[0].def_value = default_home;
1435 /* Unload shell32.dll, it is not needed anymore. */
1436 FreeLibrary (shell32_dll);
1439 /* Get default locale info and use it for LANG. */
1440 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1441 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1442 locale_name, sizeof (locale_name)))
1444 for (i = 0; i < N_ENV_VARS; i++)
1446 if (strcmp (env_vars[i].name, "LANG") == 0)
1448 env_vars[i].def_value = locale_name;
1449 break;
1454 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1456 /* Treat emacs_dir specially: set it unconditionally based on our
1457 location, if it appears that we are running from the bin subdir
1458 of a standard installation. */
1460 char *p;
1461 char modname[MAX_PATH];
1463 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1464 abort ();
1465 if ((p = strrchr (modname, '\\')) == NULL)
1466 abort ();
1467 *p = 0;
1469 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1471 char buf[SET_ENV_BUF_SIZE];
1473 *p = 0;
1474 for (p = modname; *p; p++)
1475 if (*p == '\\') *p = '/';
1477 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
1478 _putenv (strdup (buf));
1480 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1482 /* FIXME: should use substring of get_emacs_configuration ().
1483 But I don't think the Windows build supports alpha, mips etc
1484 anymore, so have taken the easy option for now. */
1485 else if (p && xstrcasecmp (p, "\\i386") == 0)
1487 *p = 0;
1488 p = strrchr (modname, '\\');
1489 if (p != NULL)
1491 *p = 0;
1492 p = strrchr (modname, '\\');
1493 if (p && xstrcasecmp (p, "\\src") == 0)
1495 char buf[SET_ENV_BUF_SIZE];
1497 *p = 0;
1498 for (p = modname; *p; p++)
1499 if (*p == '\\') *p = '/';
1501 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
1502 _putenv (strdup (buf));
1508 for (i = 0; i < N_ENV_VARS; i++)
1510 if (!getenv (env_vars[i].name))
1512 int dont_free = 0;
1514 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1515 /* Also ignore empty environment variables. */
1516 || *lpval == 0)
1518 xfree (lpval);
1519 lpval = env_vars[i].def_value;
1520 dwType = REG_EXPAND_SZ;
1521 dont_free = 1;
1524 if (lpval)
1526 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1528 if (dwType == REG_EXPAND_SZ)
1529 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
1530 else if (dwType == REG_SZ)
1531 strcpy (buf1, lpval);
1532 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1534 _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name,
1535 buf1);
1536 _putenv (strdup (buf2));
1539 if (!dont_free)
1540 xfree (lpval);
1546 /* Rebuild system configuration to reflect invoking system. */
1547 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1549 /* Another special case: on NT, the PATH variable is actually named
1550 "Path" although cmd.exe (perhaps NT itself) arranges for
1551 environment variable lookup and setting to be case insensitive.
1552 However, Emacs assumes a fully case sensitive environment, so we
1553 need to change "Path" to "PATH" to match the expectations of
1554 various elisp packages. We do this by the sneaky method of
1555 modifying the string in the C runtime environ entry.
1557 The same applies to COMSPEC. */
1559 char ** envp;
1561 for (envp = environ; *envp; envp++)
1562 if (_strnicmp (*envp, "PATH=", 5) == 0)
1563 memcpy (*envp, "PATH=", 5);
1564 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1565 memcpy (*envp, "COMSPEC=", 8);
1568 /* Remember the initial working directory for getwd, then make the
1569 real wd be the location of emacs.exe to avoid conflicts when
1570 renaming or deleting directories. (We also don't call chdir when
1571 running subprocesses for the same reason.) */
1572 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1573 abort ();
1576 char *p;
1577 static char modname[MAX_PATH];
1579 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1580 abort ();
1581 if ((p = strrchr (modname, '\\')) == NULL)
1582 abort ();
1583 *p = 0;
1585 SetCurrentDirectory (modname);
1587 /* Ensure argv[0] has the full path to Emacs. */
1588 *p = '\\';
1589 argv[0] = modname;
1592 /* Determine if there is a middle mouse button, to allow parse_button
1593 to decide whether right mouse events should be mouse-2 or
1594 mouse-3. */
1595 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1597 init_user_info ();
1600 char *
1601 emacs_root_dir (void)
1603 static char root_dir[FILENAME_MAX];
1604 const char *p;
1606 p = getenv ("emacs_dir");
1607 if (p == NULL)
1608 abort ();
1609 strcpy (root_dir, p);
1610 root_dir[parse_root (root_dir, NULL)] = '\0';
1611 dostounix_filename (root_dir);
1612 return root_dir;
1615 /* We don't have scripts to automatically determine the system configuration
1616 for Emacs before it's compiled, and we don't want to have to make the
1617 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1618 routine. */
1620 char *
1621 get_emacs_configuration (void)
1623 char *arch, *oem, *os;
1624 int build_num;
1625 static char configuration_buffer[32];
1627 /* Determine the processor type. */
1628 switch (get_processor_type ())
1631 #ifdef PROCESSOR_INTEL_386
1632 case PROCESSOR_INTEL_386:
1633 case PROCESSOR_INTEL_486:
1634 case PROCESSOR_INTEL_PENTIUM:
1635 arch = "i386";
1636 break;
1637 #endif
1639 #ifdef PROCESSOR_MIPS_R2000
1640 case PROCESSOR_MIPS_R2000:
1641 case PROCESSOR_MIPS_R3000:
1642 case PROCESSOR_MIPS_R4000:
1643 arch = "mips";
1644 break;
1645 #endif
1647 #ifdef PROCESSOR_ALPHA_21064
1648 case PROCESSOR_ALPHA_21064:
1649 arch = "alpha";
1650 break;
1651 #endif
1653 default:
1654 arch = "unknown";
1655 break;
1658 /* Use the OEM field to reflect the compiler/library combination. */
1659 #ifdef _MSC_VER
1660 #define COMPILER_NAME "msvc"
1661 #else
1662 #ifdef __GNUC__
1663 #define COMPILER_NAME "mingw"
1664 #else
1665 #define COMPILER_NAME "unknown"
1666 #endif
1667 #endif
1668 oem = COMPILER_NAME;
1670 switch (osinfo_cache.dwPlatformId) {
1671 case VER_PLATFORM_WIN32_NT:
1672 os = "nt";
1673 build_num = osinfo_cache.dwBuildNumber;
1674 break;
1675 case VER_PLATFORM_WIN32_WINDOWS:
1676 if (osinfo_cache.dwMinorVersion == 0) {
1677 os = "windows95";
1678 } else {
1679 os = "windows98";
1681 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1682 break;
1683 case VER_PLATFORM_WIN32s:
1684 /* Not supported, should not happen. */
1685 os = "windows32s";
1686 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1687 break;
1688 default:
1689 os = "unknown";
1690 build_num = 0;
1691 break;
1694 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1695 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1696 get_w32_major_version (), get_w32_minor_version (), build_num);
1697 } else {
1698 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1701 return configuration_buffer;
1704 char *
1705 get_emacs_configuration_options (void)
1707 static char options_buffer[256];
1709 /* Work out the effective configure options for this build. */
1710 #ifdef _MSC_VER
1711 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1712 #else
1713 #ifdef __GNUC__
1714 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1715 #else
1716 #define COMPILER_VERSION ""
1717 #endif
1718 #endif
1720 sprintf (options_buffer, COMPILER_VERSION);
1721 #ifdef EMACSDEBUG
1722 strcat (options_buffer, " --no-opt");
1723 #endif
1724 #ifdef USER_CFLAGS
1725 strcat (options_buffer, " --cflags");
1726 strcat (options_buffer, USER_CFLAGS);
1727 #endif
1728 #ifdef USER_LDFLAGS
1729 strcat (options_buffer, " --ldflags");
1730 strcat (options_buffer, USER_LDFLAGS);
1731 #endif
1732 return options_buffer;
1736 #include <sys/timeb.h>
1738 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1739 void
1740 gettimeofday (struct timeval *tv, struct timezone *tz)
1742 struct _timeb tb;
1743 _ftime (&tb);
1745 tv->tv_sec = tb.time;
1746 tv->tv_usec = tb.millitm * 1000L;
1747 if (tz)
1749 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
1750 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
1754 /* ------------------------------------------------------------------------- */
1755 /* IO support and wrapper functions for W32 API. */
1756 /* ------------------------------------------------------------------------- */
1758 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1759 on network directories, so we handle that case here.
1760 (Ulrich Leodolter, 1/11/95). */
1761 char *
1762 sys_ctime (const time_t *t)
1764 char *str = (char *) ctime (t);
1765 return (str ? str : "Sun Jan 01 00:00:00 1970");
1768 /* Emulate sleep...we could have done this with a define, but that
1769 would necessitate including windows.h in the files that used it.
1770 This is much easier. */
1771 void
1772 sys_sleep (int seconds)
1774 Sleep (seconds * 1000);
1777 /* Internal MSVC functions for low-level descriptor munging */
1778 extern int __cdecl _set_osfhnd (int fd, long h);
1779 extern int __cdecl _free_osfhnd (int fd);
1781 /* parallel array of private info on file handles */
1782 filedesc fd_info [ MAXDESC ];
1784 typedef struct volume_info_data {
1785 struct volume_info_data * next;
1787 /* time when info was obtained */
1788 DWORD timestamp;
1790 /* actual volume info */
1791 char * root_dir;
1792 DWORD serialnum;
1793 DWORD maxcomp;
1794 DWORD flags;
1795 char * name;
1796 char * type;
1797 } volume_info_data;
1799 /* Global referenced by various functions. */
1800 static volume_info_data volume_info;
1802 /* Vector to indicate which drives are local and fixed (for which cached
1803 data never expires). */
1804 static BOOL fixed_drives[26];
1806 /* Consider cached volume information to be stale if older than 10s,
1807 at least for non-local drives. Info for fixed drives is never stale. */
1808 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
1809 #define VOLINFO_STILL_VALID( root_dir, info ) \
1810 ( ( isalpha (root_dir[0]) && \
1811 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
1812 || GetTickCount () - info->timestamp < 10000 )
1814 /* Cache support functions. */
1816 /* Simple linked list with linear search is sufficient. */
1817 static volume_info_data *volume_cache = NULL;
1819 static volume_info_data *
1820 lookup_volume_info (char * root_dir)
1822 volume_info_data * info;
1824 for (info = volume_cache; info; info = info->next)
1825 if (xstrcasecmp (info->root_dir, root_dir) == 0)
1826 break;
1827 return info;
1830 static void
1831 add_volume_info (char * root_dir, volume_info_data * info)
1833 info->root_dir = xstrdup (root_dir);
1834 info->next = volume_cache;
1835 volume_cache = info;
1839 /* Wrapper for GetVolumeInformation, which uses caching to avoid
1840 performance penalty (~2ms on 486 for local drives, 7.5ms for local
1841 cdrom drive, ~5-10ms or more for remote drives on LAN). */
1842 volume_info_data *
1843 GetCachedVolumeInformation (char * root_dir)
1845 volume_info_data * info;
1846 char default_root[ MAX_PATH ];
1848 /* NULL for root_dir means use root from current directory. */
1849 if (root_dir == NULL)
1851 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
1852 return NULL;
1853 parse_root (default_root, &root_dir);
1854 *root_dir = 0;
1855 root_dir = default_root;
1858 /* Local fixed drives can be cached permanently. Removable drives
1859 cannot be cached permanently, since the volume name and serial
1860 number (if nothing else) can change. Remote drives should be
1861 treated as if they are removable, since there is no sure way to
1862 tell whether they are or not. Also, the UNC association of drive
1863 letters mapped to remote volumes can be changed at any time (even
1864 by other processes) without notice.
1866 As a compromise, so we can benefit from caching info for remote
1867 volumes, we use a simple expiry mechanism to invalidate cache
1868 entries that are more than ten seconds old. */
1870 #if 0
1871 /* No point doing this, because WNetGetConnection is even slower than
1872 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
1873 GetDriveType is about the only call of this type which does not
1874 involve network access, and so is extremely quick). */
1876 /* Map drive letter to UNC if remote. */
1877 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
1879 char remote_name[ 256 ];
1880 char drive[3] = { root_dir[0], ':' };
1882 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
1883 == NO_ERROR)
1884 /* do something */ ;
1886 #endif
1888 info = lookup_volume_info (root_dir);
1890 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
1892 char name[ 256 ];
1893 DWORD serialnum;
1894 DWORD maxcomp;
1895 DWORD flags;
1896 char type[ 256 ];
1898 /* Info is not cached, or is stale. */
1899 if (!GetVolumeInformation (root_dir,
1900 name, sizeof (name),
1901 &serialnum,
1902 &maxcomp,
1903 &flags,
1904 type, sizeof (type)))
1905 return NULL;
1907 /* Cache the volume information for future use, overwriting existing
1908 entry if present. */
1909 if (info == NULL)
1911 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
1912 add_volume_info (root_dir, info);
1914 else
1916 xfree (info->name);
1917 xfree (info->type);
1920 info->name = xstrdup (name);
1921 info->serialnum = serialnum;
1922 info->maxcomp = maxcomp;
1923 info->flags = flags;
1924 info->type = xstrdup (type);
1925 info->timestamp = GetTickCount ();
1928 return info;
1931 /* Get information on the volume where name is held; set path pointer to
1932 start of pathname in name (past UNC header\volume header if present). */
1934 get_volume_info (const char * name, const char ** pPath)
1936 char temp[MAX_PATH];
1937 char *rootname = NULL; /* default to current volume */
1938 volume_info_data * info;
1940 if (name == NULL)
1941 return FALSE;
1943 /* find the root name of the volume if given */
1944 if (isalpha (name[0]) && name[1] == ':')
1946 rootname = temp;
1947 temp[0] = *name++;
1948 temp[1] = *name++;
1949 temp[2] = '\\';
1950 temp[3] = 0;
1952 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1954 char *str = temp;
1955 int slashes = 4;
1956 rootname = temp;
1959 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1960 break;
1961 *str++ = *name++;
1963 while ( *name );
1965 *str++ = '\\';
1966 *str = 0;
1969 if (pPath)
1970 *pPath = name;
1972 info = GetCachedVolumeInformation (rootname);
1973 if (info != NULL)
1975 /* Set global referenced by other functions. */
1976 volume_info = *info;
1977 return TRUE;
1979 return FALSE;
1982 /* Determine if volume is FAT format (ie. only supports short 8.3
1983 names); also set path pointer to start of pathname in name. */
1985 is_fat_volume (const char * name, const char ** pPath)
1987 if (get_volume_info (name, pPath))
1988 return (volume_info.maxcomp == 12);
1989 return FALSE;
1992 /* Map filename to a valid 8.3 name if necessary. */
1993 const char *
1994 map_w32_filename (const char * name, const char ** pPath)
1996 static char shortname[MAX_PATH];
1997 char * str = shortname;
1998 char c;
1999 char * path;
2000 const char * save_name = name;
2002 if (strlen (name) >= MAX_PATH)
2004 /* Return a filename which will cause callers to fail. */
2005 strcpy (shortname, "?");
2006 return shortname;
2009 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2011 register int left = 8; /* maximum number of chars in part */
2012 register int extn = 0; /* extension added? */
2013 register int dots = 2; /* maximum number of dots allowed */
2015 while (name < path)
2016 *str++ = *name++; /* skip past UNC header */
2018 while ((c = *name++))
2020 switch ( c )
2022 case '\\':
2023 case '/':
2024 *str++ = '\\';
2025 extn = 0; /* reset extension flags */
2026 dots = 2; /* max 2 dots */
2027 left = 8; /* max length 8 for main part */
2028 break;
2029 case ':':
2030 *str++ = ':';
2031 extn = 0; /* reset extension flags */
2032 dots = 2; /* max 2 dots */
2033 left = 8; /* max length 8 for main part */
2034 break;
2035 case '.':
2036 if ( dots )
2038 /* Convert path components of the form .xxx to _xxx,
2039 but leave . and .. as they are. This allows .emacs
2040 to be read as _emacs, for example. */
2042 if (! *name ||
2043 *name == '.' ||
2044 IS_DIRECTORY_SEP (*name))
2046 *str++ = '.';
2047 dots--;
2049 else
2051 *str++ = '_';
2052 left--;
2053 dots = 0;
2056 else if ( !extn )
2058 *str++ = '.';
2059 extn = 1; /* we've got an extension */
2060 left = 3; /* 3 chars in extension */
2062 else
2064 /* any embedded dots after the first are converted to _ */
2065 *str++ = '_';
2067 break;
2068 case '~':
2069 case '#': /* don't lose these, they're important */
2070 if ( ! left )
2071 str[-1] = c; /* replace last character of part */
2072 /* FALLTHRU */
2073 default:
2074 if ( left )
2076 *str++ = tolower (c); /* map to lower case (looks nicer) */
2077 left--;
2078 dots = 0; /* started a path component */
2080 break;
2083 *str = '\0';
2085 else
2087 strcpy (shortname, name);
2088 unixtodos_filename (shortname);
2091 if (pPath)
2092 *pPath = shortname + (path - save_name);
2094 return shortname;
2097 static int
2098 is_exec (const char * name)
2100 char * p = strrchr (name, '.');
2101 return
2102 (p != NULL
2103 && (xstrcasecmp (p, ".exe") == 0 ||
2104 xstrcasecmp (p, ".com") == 0 ||
2105 xstrcasecmp (p, ".bat") == 0 ||
2106 xstrcasecmp (p, ".cmd") == 0));
2109 /* Emulate the Unix directory procedures opendir, closedir,
2110 and readdir. We can't use the procedures supplied in sysdep.c,
2111 so we provide them here. */
2113 struct direct dir_static; /* simulated directory contents */
2114 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2115 static int dir_is_fat;
2116 static char dir_pathname[MAXPATHLEN+1];
2117 static WIN32_FIND_DATA dir_find_data;
2119 /* Support shares on a network resource as subdirectories of a read-only
2120 root directory. */
2121 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2122 HANDLE open_unc_volume (const char *);
2123 char *read_unc_volume (HANDLE, char *, int);
2124 void close_unc_volume (HANDLE);
2126 DIR *
2127 opendir (char *filename)
2129 DIR *dirp;
2131 /* Opening is done by FindFirstFile. However, a read is inherent to
2132 this operation, so we defer the open until read time. */
2134 if (dir_find_handle != INVALID_HANDLE_VALUE)
2135 return NULL;
2136 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2137 return NULL;
2139 if (is_unc_volume (filename))
2141 wnet_enum_handle = open_unc_volume (filename);
2142 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2143 return NULL;
2146 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2147 return NULL;
2149 dirp->dd_fd = 0;
2150 dirp->dd_loc = 0;
2151 dirp->dd_size = 0;
2153 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2154 dir_pathname[MAXPATHLEN] = '\0';
2155 dir_is_fat = is_fat_volume (filename, NULL);
2157 return dirp;
2160 void
2161 closedir (DIR *dirp)
2163 /* If we have a find-handle open, close it. */
2164 if (dir_find_handle != INVALID_HANDLE_VALUE)
2166 FindClose (dir_find_handle);
2167 dir_find_handle = INVALID_HANDLE_VALUE;
2169 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2171 close_unc_volume (wnet_enum_handle);
2172 wnet_enum_handle = INVALID_HANDLE_VALUE;
2174 xfree ((char *) dirp);
2177 struct direct *
2178 readdir (DIR *dirp)
2180 int downcase = !NILP (Vw32_downcase_file_names);
2182 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2184 if (!read_unc_volume (wnet_enum_handle,
2185 dir_find_data.cFileName,
2186 MAX_PATH))
2187 return NULL;
2189 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2190 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2192 char filename[MAXNAMLEN + 3];
2193 int ln;
2195 strcpy (filename, dir_pathname);
2196 ln = strlen (filename) - 1;
2197 if (!IS_DIRECTORY_SEP (filename[ln]))
2198 strcat (filename, "\\");
2199 strcat (filename, "*");
2201 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2203 if (dir_find_handle == INVALID_HANDLE_VALUE)
2204 return NULL;
2206 else
2208 if (!FindNextFile (dir_find_handle, &dir_find_data))
2209 return NULL;
2212 /* Emacs never uses this value, so don't bother making it match
2213 value returned by stat(). */
2214 dir_static.d_ino = 1;
2216 strcpy (dir_static.d_name, dir_find_data.cFileName);
2218 /* If the file name in cFileName[] includes `?' characters, it means
2219 the original file name used characters that cannot be represented
2220 by the current ANSI codepage. To avoid total lossage, retrieve
2221 the short 8+3 alias of the long file name. */
2222 if (_mbspbrk (dir_static.d_name, "?"))
2224 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2225 downcase = 1; /* 8+3 aliases are returned in all caps */
2227 dir_static.d_namlen = strlen (dir_static.d_name);
2228 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
2229 dir_static.d_namlen - dir_static.d_namlen % 4;
2231 /* If the file name in cFileName[] includes `?' characters, it means
2232 the original file name used characters that cannot be represented
2233 by the current ANSI codepage. To avoid total lossage, retrieve
2234 the short 8+3 alias of the long file name. */
2235 if (_mbspbrk (dir_find_data.cFileName, "?"))
2237 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2238 /* 8+3 aliases are returned in all caps, which could break
2239 various alists that look at filenames' extensions. */
2240 downcase = 1;
2242 else
2243 strcpy (dir_static.d_name, dir_find_data.cFileName);
2244 dir_static.d_namlen = strlen (dir_static.d_name);
2245 if (dir_is_fat)
2246 _strlwr (dir_static.d_name);
2247 else if (downcase)
2249 register char *p;
2250 for (p = dir_static.d_name; *p; p++)
2251 if (*p >= 'a' && *p <= 'z')
2252 break;
2253 if (!*p)
2254 _strlwr (dir_static.d_name);
2257 return &dir_static;
2260 HANDLE
2261 open_unc_volume (const char *path)
2263 NETRESOURCE nr;
2264 HANDLE henum;
2265 int result;
2267 nr.dwScope = RESOURCE_GLOBALNET;
2268 nr.dwType = RESOURCETYPE_DISK;
2269 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2270 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2271 nr.lpLocalName = NULL;
2272 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
2273 nr.lpComment = NULL;
2274 nr.lpProvider = NULL;
2276 result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2277 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2279 if (result == NO_ERROR)
2280 return henum;
2281 else
2282 return INVALID_HANDLE_VALUE;
2285 char *
2286 read_unc_volume (HANDLE henum, char *readbuf, int size)
2288 DWORD count;
2289 int result;
2290 DWORD bufsize = 512;
2291 char *buffer;
2292 char *ptr;
2294 count = 1;
2295 buffer = alloca (bufsize);
2296 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
2297 if (result != NO_ERROR)
2298 return NULL;
2300 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2301 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2302 ptr += 2;
2303 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2304 ptr++;
2306 strncpy (readbuf, ptr, size);
2307 return readbuf;
2310 void
2311 close_unc_volume (HANDLE henum)
2313 if (henum != INVALID_HANDLE_VALUE)
2314 WNetCloseEnum (henum);
2317 DWORD
2318 unc_volume_file_attributes (const char *path)
2320 HANDLE henum;
2321 DWORD attrs;
2323 henum = open_unc_volume (path);
2324 if (henum == INVALID_HANDLE_VALUE)
2325 return -1;
2327 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2329 close_unc_volume (henum);
2331 return attrs;
2334 /* Ensure a network connection is authenticated. */
2335 static void
2336 logon_network_drive (const char *path)
2338 NETRESOURCE resource;
2339 char share[MAX_PATH];
2340 int i, n_slashes;
2341 char drive[4];
2343 sprintf (drive, "%c:\\", path[0]);
2345 /* Only logon to networked drives. */
2346 if ((!IS_DIRECTORY_SEP (path[0]) || !IS_DIRECTORY_SEP (path[1]))
2347 && GetDriveType (drive) != DRIVE_REMOTE)
2348 return;
2350 n_slashes = 2;
2351 strncpy (share, path, MAX_PATH);
2352 /* Truncate to just server and share name. */
2353 for (i = 2; i < MAX_PATH; i++)
2355 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2357 share[i] = '\0';
2358 break;
2362 resource.dwType = RESOURCETYPE_DISK;
2363 resource.lpLocalName = NULL;
2364 resource.lpRemoteName = share;
2365 resource.lpProvider = NULL;
2367 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2370 /* Shadow some MSVC runtime functions to map requests for long filenames
2371 to reasonable short names if necessary. This was originally added to
2372 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2373 long file names. */
2376 sys_access (const char * path, int mode)
2378 DWORD attributes;
2380 /* MSVC implementation doesn't recognize D_OK. */
2381 path = map_w32_filename (path, NULL);
2382 if (is_unc_volume (path))
2384 attributes = unc_volume_file_attributes (path);
2385 if (attributes == -1) {
2386 errno = EACCES;
2387 return -1;
2390 else if ((attributes = GetFileAttributes (path)) == -1)
2392 /* Should try mapping GetLastError to errno; for now just indicate
2393 that path doesn't exist. */
2394 errno = EACCES;
2395 return -1;
2397 if ((mode & X_OK) != 0 && !is_exec (path))
2399 errno = EACCES;
2400 return -1;
2402 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2404 errno = EACCES;
2405 return -1;
2407 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2409 errno = EACCES;
2410 return -1;
2412 return 0;
2416 sys_chdir (const char * path)
2418 return _chdir (map_w32_filename (path, NULL));
2422 sys_chmod (const char * path, int mode)
2424 return _chmod (map_w32_filename (path, NULL), mode);
2428 sys_chown (const char *path, uid_t owner, gid_t group)
2430 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2431 return -1;
2432 return 0;
2436 sys_creat (const char * path, int mode)
2438 return _creat (map_w32_filename (path, NULL), mode);
2441 FILE *
2442 sys_fopen(const char * path, const char * mode)
2444 int fd;
2445 int oflag;
2446 const char * mode_save = mode;
2448 /* Force all file handles to be non-inheritable. This is necessary to
2449 ensure child processes don't unwittingly inherit handles that might
2450 prevent future file access. */
2452 if (mode[0] == 'r')
2453 oflag = O_RDONLY;
2454 else if (mode[0] == 'w' || mode[0] == 'a')
2455 oflag = O_WRONLY | O_CREAT | O_TRUNC;
2456 else
2457 return NULL;
2459 /* Only do simplistic option parsing. */
2460 while (*++mode)
2461 if (mode[0] == '+')
2463 oflag &= ~(O_RDONLY | O_WRONLY);
2464 oflag |= O_RDWR;
2466 else if (mode[0] == 'b')
2468 oflag &= ~O_TEXT;
2469 oflag |= O_BINARY;
2471 else if (mode[0] == 't')
2473 oflag &= ~O_BINARY;
2474 oflag |= O_TEXT;
2476 else break;
2478 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2479 if (fd < 0)
2480 return NULL;
2482 return _fdopen (fd, mode_save);
2485 /* This only works on NTFS volumes, but is useful to have. */
2487 sys_link (const char * old, const char * new)
2489 HANDLE fileh;
2490 int result = -1;
2491 char oldname[MAX_PATH], newname[MAX_PATH];
2493 if (old == NULL || new == NULL)
2495 errno = ENOENT;
2496 return -1;
2499 strcpy (oldname, map_w32_filename (old, NULL));
2500 strcpy (newname, map_w32_filename (new, NULL));
2502 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2503 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2504 if (fileh != INVALID_HANDLE_VALUE)
2506 int wlen;
2508 /* Confusingly, the "alternate" stream name field does not apply
2509 when restoring a hard link, and instead contains the actual
2510 stream data for the link (ie. the name of the link to create).
2511 The WIN32_STREAM_ID structure before the cStreamName field is
2512 the stream header, which is then immediately followed by the
2513 stream data. */
2515 struct {
2516 WIN32_STREAM_ID wid;
2517 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2518 } data;
2520 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2521 data.wid.cStreamName, MAX_PATH);
2522 if (wlen > 0)
2524 LPVOID context = NULL;
2525 DWORD wbytes = 0;
2527 data.wid.dwStreamId = BACKUP_LINK;
2528 data.wid.dwStreamAttributes = 0;
2529 data.wid.Size.LowPart = wlen * sizeof(WCHAR);
2530 data.wid.Size.HighPart = 0;
2531 data.wid.dwStreamNameSize = 0;
2533 if (BackupWrite (fileh, (LPBYTE)&data,
2534 offsetof (WIN32_STREAM_ID, cStreamName)
2535 + data.wid.Size.LowPart,
2536 &wbytes, FALSE, FALSE, &context)
2537 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2539 /* succeeded */
2540 result = 0;
2542 else
2544 /* Should try mapping GetLastError to errno; for now just
2545 indicate a general error (eg. links not supported). */
2546 errno = EINVAL; // perhaps EMLINK?
2550 CloseHandle (fileh);
2552 else
2553 errno = ENOENT;
2555 return result;
2559 sys_mkdir (const char * path)
2561 return _mkdir (map_w32_filename (path, NULL));
2564 /* Because of long name mapping issues, we need to implement this
2565 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2566 a unique name, instead of setting the input template to an empty
2567 string.
2569 Standard algorithm seems to be use pid or tid with a letter on the
2570 front (in place of the 6 X's) and cycle through the letters to find a
2571 unique name. We extend that to allow any reasonable character as the
2572 first of the 6 X's. */
2573 char *
2574 sys_mktemp (char * template)
2576 char * p;
2577 int i;
2578 unsigned uid = GetCurrentThreadId ();
2579 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2581 if (template == NULL)
2582 return NULL;
2583 p = template + strlen (template);
2584 i = 5;
2585 /* replace up to the last 5 X's with uid in decimal */
2586 while (--p >= template && p[0] == 'X' && --i >= 0)
2588 p[0] = '0' + uid % 10;
2589 uid /= 10;
2592 if (i < 0 && p[0] == 'X')
2594 i = 0;
2597 int save_errno = errno;
2598 p[0] = first_char[i];
2599 if (sys_access (template, 0) < 0)
2601 errno = save_errno;
2602 return template;
2605 while (++i < sizeof (first_char));
2608 /* Template is badly formed or else we can't generate a unique name,
2609 so return empty string */
2610 template[0] = 0;
2611 return template;
2615 sys_open (const char * path, int oflag, int mode)
2617 const char* mpath = map_w32_filename (path, NULL);
2618 /* Try to open file without _O_CREAT, to be able to write to hidden
2619 and system files. Force all file handles to be
2620 non-inheritable. */
2621 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2622 if (res >= 0)
2623 return res;
2624 return _open (mpath, oflag | _O_NOINHERIT, mode);
2628 sys_rename (const char * oldname, const char * newname)
2630 BOOL result;
2631 char temp[MAX_PATH];
2633 /* MoveFile on Windows 95 doesn't correctly change the short file name
2634 alias in a number of circumstances (it is not easy to predict when
2635 just by looking at oldname and newname, unfortunately). In these
2636 cases, renaming through a temporary name avoids the problem.
2638 A second problem on Windows 95 is that renaming through a temp name when
2639 newname is uppercase fails (the final long name ends up in
2640 lowercase, although the short alias might be uppercase) UNLESS the
2641 long temp name is not 8.3.
2643 So, on Windows 95 we always rename through a temp name, and we make sure
2644 the temp name has a long extension to ensure correct renaming. */
2646 strcpy (temp, map_w32_filename (oldname, NULL));
2648 if (os_subtype == OS_WIN95)
2650 char * o;
2651 char * p;
2652 int i = 0;
2654 oldname = map_w32_filename (oldname, NULL);
2655 if (o = strrchr (oldname, '\\'))
2656 o++;
2657 else
2658 o = (char *) oldname;
2660 if (p = strrchr (temp, '\\'))
2661 p++;
2662 else
2663 p = temp;
2667 /* Force temp name to require a manufactured 8.3 alias - this
2668 seems to make the second rename work properly. */
2669 sprintf (p, "_.%s.%u", o, i);
2670 i++;
2671 result = rename (oldname, temp);
2673 /* This loop must surely terminate! */
2674 while (result < 0 && errno == EEXIST);
2675 if (result < 0)
2676 return -1;
2679 /* Emulate Unix behavior - newname is deleted if it already exists
2680 (at least if it is a file; don't do this for directories).
2682 Since we mustn't do this if we are just changing the case of the
2683 file name (we would end up deleting the file we are trying to
2684 rename!), we let rename detect if the destination file already
2685 exists - that way we avoid the possible pitfalls of trying to
2686 determine ourselves whether two names really refer to the same
2687 file, which is not always possible in the general case. (Consider
2688 all the permutations of shared or subst'd drives, etc.) */
2690 newname = map_w32_filename (newname, NULL);
2691 result = rename (temp, newname);
2693 if (result < 0
2694 && errno == EEXIST
2695 && _chmod (newname, 0666) == 0
2696 && _unlink (newname) == 0)
2697 result = rename (temp, newname);
2699 return result;
2703 sys_rmdir (const char * path)
2705 return _rmdir (map_w32_filename (path, NULL));
2709 sys_unlink (const char * path)
2711 path = map_w32_filename (path, NULL);
2713 /* On Unix, unlink works without write permission. */
2714 _chmod (path, 0666);
2715 return _unlink (path);
2718 static FILETIME utc_base_ft;
2719 static long double utc_base;
2720 static int init = 0;
2722 static long double
2723 convert_time_raw (FILETIME ft)
2725 return
2726 (long double) ft.dwHighDateTime
2727 * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
2730 static time_t
2731 convert_time (FILETIME ft)
2733 long double ret;
2735 if (!init)
2737 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2738 SYSTEMTIME st;
2740 st.wYear = 1970;
2741 st.wMonth = 1;
2742 st.wDay = 1;
2743 st.wHour = 0;
2744 st.wMinute = 0;
2745 st.wSecond = 0;
2746 st.wMilliseconds = 0;
2748 SystemTimeToFileTime (&st, &utc_base_ft);
2749 utc_base = (long double) utc_base_ft.dwHighDateTime
2750 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
2751 init = 1;
2754 if (CompareFileTime (&ft, &utc_base_ft) < 0)
2755 return 0;
2757 return (time_t) ((convert_time_raw (ft) - utc_base) * 1e-7L);
2761 void
2762 convert_from_time_t (time_t time, FILETIME * pft)
2764 long double tmp;
2766 if (!init)
2768 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2769 SYSTEMTIME st;
2771 st.wYear = 1970;
2772 st.wMonth = 1;
2773 st.wDay = 1;
2774 st.wHour = 0;
2775 st.wMinute = 0;
2776 st.wSecond = 0;
2777 st.wMilliseconds = 0;
2779 SystemTimeToFileTime (&st, &utc_base_ft);
2780 utc_base = (long double) utc_base_ft.dwHighDateTime
2781 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
2782 init = 1;
2785 /* time in 100ns units since 1-Jan-1601 */
2786 tmp = (long double) time * 1e7 + utc_base;
2787 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
2788 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
2791 #if 0
2792 /* No reason to keep this; faking inode values either by hashing or even
2793 using the file index from GetInformationByHandle, is not perfect and
2794 so by default Emacs doesn't use the inode values on Windows.
2795 Instead, we now determine file-truename correctly (except for
2796 possible drive aliasing etc). */
2798 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
2799 static unsigned
2800 hashval (const unsigned char * str)
2802 unsigned h = 0;
2803 while (*str)
2805 h = (h << 4) + *str++;
2806 h ^= (h >> 28);
2808 return h;
2811 /* Return the hash value of the canonical pathname, excluding the
2812 drive/UNC header, to get a hopefully unique inode number. */
2813 static DWORD
2814 generate_inode_val (const char * name)
2816 char fullname[ MAX_PATH ];
2817 char * p;
2818 unsigned hash;
2820 /* Get the truly canonical filename, if it exists. (Note: this
2821 doesn't resolve aliasing due to subst commands, or recognise hard
2822 links. */
2823 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
2824 abort ();
2826 parse_root (fullname, &p);
2827 /* Normal W32 filesystems are still case insensitive. */
2828 _strlwr (p);
2829 return hashval (p);
2832 #endif
2834 static PSECURITY_DESCRIPTOR
2835 get_file_security_desc (const char *fname)
2837 PSECURITY_DESCRIPTOR psd = NULL;
2838 DWORD sd_len, err;
2839 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
2840 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
2842 if (!get_file_security (fname, si, psd, 0, &sd_len))
2844 err = GetLastError ();
2845 if (err != ERROR_INSUFFICIENT_BUFFER)
2846 return NULL;
2849 psd = xmalloc (sd_len);
2850 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
2852 xfree (psd);
2853 return NULL;
2856 return psd;
2859 static DWORD
2860 get_rid (PSID sid)
2862 unsigned n_subauthorities;
2864 /* Use the last sub-authority value of the RID, the relative
2865 portion of the SID, as user/group ID. */
2866 n_subauthorities = *get_sid_sub_authority_count (sid);
2867 if (n_subauthorities < 1)
2868 return 0; /* the "World" RID */
2869 return *get_sid_sub_authority (sid, n_subauthorities - 1);
2872 /* Caching SID and account values for faster lokup. */
2874 #ifdef __GNUC__
2875 # define FLEXIBLE_ARRAY_MEMBER
2876 #else
2877 # define FLEXIBLE_ARRAY_MEMBER 1
2878 #endif
2880 struct w32_id {
2881 int rid;
2882 struct w32_id *next;
2883 char name[GNLEN+1];
2884 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
2887 static struct w32_id *w32_idlist;
2889 static int
2890 w32_cached_id (PSID sid, int *id, char *name)
2892 struct w32_id *tail, *found;
2894 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
2896 if (equal_sid ((PSID)tail->sid, sid))
2898 found = tail;
2899 break;
2902 if (found)
2904 *id = found->rid;
2905 strcpy (name, found->name);
2906 return 1;
2908 else
2909 return 0;
2912 static void
2913 w32_add_to_cache (PSID sid, int id, char *name)
2915 DWORD sid_len;
2916 struct w32_id *new_entry;
2918 /* We don't want to leave behind stale cache from when Emacs was
2919 dumped. */
2920 if (initialized)
2922 sid_len = get_length_sid (sid);
2923 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
2924 if (new_entry)
2926 new_entry->rid = id;
2927 strcpy (new_entry->name, name);
2928 copy_sid (sid_len, (PSID)new_entry->sid, sid);
2929 new_entry->next = w32_idlist;
2930 w32_idlist = new_entry;
2935 #define UID 1
2936 #define GID 2
2938 static int
2939 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
2940 int *id, char *nm, int what)
2942 PSID sid = NULL;
2943 char machine[MAX_COMPUTERNAME_LENGTH+1];
2944 BOOL dflt;
2945 SID_NAME_USE ignore;
2946 char name[UNLEN+1];
2947 DWORD name_len = sizeof (name);
2948 char domain[1024];
2949 DWORD domain_len = sizeof(domain);
2950 char *mp = NULL;
2951 int use_dflt = 0;
2952 int result;
2954 if (what == UID)
2955 result = get_security_descriptor_owner (psd, &sid, &dflt);
2956 else if (what == GID)
2957 result = get_security_descriptor_group (psd, &sid, &dflt);
2958 else
2959 result = 0;
2961 if (!result || !is_valid_sid (sid))
2962 use_dflt = 1;
2963 else if (!w32_cached_id (sid, id, nm))
2965 /* If FNAME is a UNC, we need to lookup account on the
2966 specified machine. */
2967 if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
2968 && fname[2] != '\0')
2970 const char *s;
2971 char *p;
2973 for (s = fname + 2, p = machine;
2974 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
2975 *p = *s;
2976 *p = '\0';
2977 mp = machine;
2980 if (!lookup_account_sid (mp, sid, name, &name_len,
2981 domain, &domain_len, &ignore)
2982 || name_len > UNLEN+1)
2983 use_dflt = 1;
2984 else
2986 *id = get_rid (sid);
2987 strcpy (nm, name);
2988 w32_add_to_cache (sid, *id, name);
2991 return use_dflt;
2994 static void
2995 get_file_owner_and_group (
2996 PSECURITY_DESCRIPTOR psd,
2997 const char *fname,
2998 struct stat *st)
3000 int dflt_usr = 0, dflt_grp = 0;
3002 if (!psd)
3004 dflt_usr = 1;
3005 dflt_grp = 1;
3007 else
3009 if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
3010 dflt_usr = 1;
3011 if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
3012 dflt_grp = 1;
3014 /* Consider files to belong to current user/group, if we cannot get
3015 more accurate information. */
3016 if (dflt_usr)
3018 st->st_uid = dflt_passwd.pw_uid;
3019 strcpy (st->st_uname, dflt_passwd.pw_name);
3021 if (dflt_grp)
3023 st->st_gid = dflt_passwd.pw_gid;
3024 strcpy (st->st_gname, dflt_group.gr_name);
3028 /* MSVC stat function can't cope with UNC names and has other bugs, so
3029 replace it with our own. This also allows us to calculate consistent
3030 inode values without hacks in the main Emacs code. */
3032 stat (const char * path, struct stat * buf)
3034 char *name, *r;
3035 char drive_root[4];
3036 UINT devtype;
3037 WIN32_FIND_DATA wfd;
3038 HANDLE fh;
3039 unsigned __int64 fake_inode;
3040 int permission;
3041 int len;
3042 int rootdir = FALSE;
3043 PSECURITY_DESCRIPTOR psd = NULL;
3045 if (path == NULL || buf == NULL)
3047 errno = EFAULT;
3048 return -1;
3051 name = (char *) map_w32_filename (path, &path);
3052 /* Must be valid filename, no wild cards or other invalid
3053 characters. We use _mbspbrk to support multibyte strings that
3054 might look to strpbrk as if they included literal *, ?, and other
3055 characters mentioned below that are disallowed by Windows
3056 filesystems. */
3057 if (_mbspbrk (name, "*?|<>\""))
3059 errno = ENOENT;
3060 return -1;
3063 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3064 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3065 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3067 r[1] = r[2] = '\0';
3070 /* Remove trailing directory separator, unless name is the root
3071 directory of a drive or UNC volume in which case ensure there
3072 is a trailing separator. */
3073 len = strlen (name);
3074 rootdir = (path >= name + len - 1
3075 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3076 name = strcpy (alloca (len + 2), name);
3078 if (is_unc_volume (name))
3080 DWORD attrs = unc_volume_file_attributes (name);
3082 if (attrs == -1)
3083 return -1;
3085 memset (&wfd, 0, sizeof (wfd));
3086 wfd.dwFileAttributes = attrs;
3087 wfd.ftCreationTime = utc_base_ft;
3088 wfd.ftLastAccessTime = utc_base_ft;
3089 wfd.ftLastWriteTime = utc_base_ft;
3090 strcpy (wfd.cFileName, name);
3092 else if (rootdir)
3094 if (!IS_DIRECTORY_SEP (name[len-1]))
3095 strcat (name, "\\");
3096 if (GetDriveType (name) < 2)
3098 errno = ENOENT;
3099 return -1;
3101 memset (&wfd, 0, sizeof (wfd));
3102 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
3103 wfd.ftCreationTime = utc_base_ft;
3104 wfd.ftLastAccessTime = utc_base_ft;
3105 wfd.ftLastWriteTime = utc_base_ft;
3106 strcpy (wfd.cFileName, name);
3108 else
3110 if (IS_DIRECTORY_SEP (name[len-1]))
3111 name[len - 1] = 0;
3113 /* (This is hacky, but helps when doing file completions on
3114 network drives.) Optimize by using information available from
3115 active readdir if possible. */
3116 len = strlen (dir_pathname);
3117 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3118 len--;
3119 if (dir_find_handle != INVALID_HANDLE_VALUE
3120 && strnicmp (name, dir_pathname, len) == 0
3121 && IS_DIRECTORY_SEP (name[len])
3122 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3124 /* This was the last entry returned by readdir. */
3125 wfd = dir_find_data;
3127 else
3129 logon_network_drive (name);
3131 fh = FindFirstFile (name, &wfd);
3132 if (fh == INVALID_HANDLE_VALUE)
3134 errno = ENOENT;
3135 return -1;
3137 FindClose (fh);
3141 /* GetDriveType needs the root directory of NAME's drive. */
3142 if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
3143 devtype = GetDriveType (NULL); /* use root of current diectory */
3144 else
3146 strncpy (drive_root, name, 3);
3147 drive_root[3] = '\0';
3148 devtype = GetDriveType (drive_root);
3151 if (!(NILP (Vw32_get_true_file_attributes)
3152 || (EQ (Vw32_get_true_file_attributes, Qlocal)
3153 && devtype != DRIVE_FIXED && devtype != DRIVE_RAMDISK))
3154 /* No access rights required to get info. */
3155 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
3156 FILE_FLAG_BACKUP_SEMANTICS, NULL))
3157 != INVALID_HANDLE_VALUE)
3159 /* This is more accurate in terms of gettting the correct number
3160 of links, but is quite slow (it is noticeable when Emacs is
3161 making a list of file name completions). */
3162 BY_HANDLE_FILE_INFORMATION info;
3164 if (GetFileInformationByHandle (fh, &info))
3166 buf->st_nlink = info.nNumberOfLinks;
3167 /* Might as well use file index to fake inode values, but this
3168 is not guaranteed to be unique unless we keep a handle open
3169 all the time (even then there are situations where it is
3170 not unique). Reputedly, there are at most 48 bits of info
3171 (on NTFS, presumably less on FAT). */
3172 fake_inode = info.nFileIndexHigh;
3173 fake_inode <<= 32;
3174 fake_inode += info.nFileIndexLow;
3176 else
3178 buf->st_nlink = 1;
3179 fake_inode = 0;
3182 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3184 buf->st_mode = S_IFDIR;
3186 else
3188 switch (GetFileType (fh))
3190 case FILE_TYPE_DISK:
3191 buf->st_mode = S_IFREG;
3192 break;
3193 case FILE_TYPE_PIPE:
3194 buf->st_mode = S_IFIFO;
3195 break;
3196 case FILE_TYPE_CHAR:
3197 case FILE_TYPE_UNKNOWN:
3198 default:
3199 buf->st_mode = S_IFCHR;
3202 CloseHandle (fh);
3203 psd = get_file_security_desc (name);
3204 get_file_owner_and_group (psd, name, buf);
3206 else
3208 /* Don't bother to make this information more accurate. */
3209 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
3210 S_IFDIR : S_IFREG;
3211 buf->st_nlink = 1;
3212 fake_inode = 0;
3214 get_file_owner_and_group (NULL, name, buf);
3216 xfree (psd);
3218 #if 0
3219 /* Not sure if there is any point in this. */
3220 if (!NILP (Vw32_generate_fake_inodes))
3221 fake_inode = generate_inode_val (name);
3222 else if (fake_inode == 0)
3224 /* For want of something better, try to make everything unique. */
3225 static DWORD gen_num = 0;
3226 fake_inode = ++gen_num;
3228 #endif
3230 /* MSVC defines _ino_t to be short; other libc's might not. */
3231 if (sizeof (buf->st_ino) == 2)
3232 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3233 else
3234 buf->st_ino = fake_inode;
3236 /* volume_info is set indirectly by map_w32_filename */
3237 buf->st_dev = volume_info.serialnum;
3238 buf->st_rdev = volume_info.serialnum;
3241 buf->st_size = wfd.nFileSizeHigh;
3242 buf->st_size <<= 32;
3243 buf->st_size += wfd.nFileSizeLow;
3245 /* Convert timestamps to Unix format. */
3246 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
3247 buf->st_atime = convert_time (wfd.ftLastAccessTime);
3248 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3249 buf->st_ctime = convert_time (wfd.ftCreationTime);
3250 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3252 /* determine rwx permissions */
3253 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3254 permission = S_IREAD;
3255 else
3256 permission = S_IREAD | S_IWRITE;
3258 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3259 permission |= S_IEXEC;
3260 else if (is_exec (name))
3261 permission |= S_IEXEC;
3263 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3265 return 0;
3268 /* Provide fstat and utime as well as stat for consistent handling of
3269 file timestamps. */
3271 fstat (int desc, struct stat * buf)
3273 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3274 BY_HANDLE_FILE_INFORMATION info;
3275 unsigned __int64 fake_inode;
3276 int permission;
3278 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3280 case FILE_TYPE_DISK:
3281 buf->st_mode = S_IFREG;
3282 if (!GetFileInformationByHandle (fh, &info))
3284 errno = EACCES;
3285 return -1;
3287 break;
3288 case FILE_TYPE_PIPE:
3289 buf->st_mode = S_IFIFO;
3290 goto non_disk;
3291 case FILE_TYPE_CHAR:
3292 case FILE_TYPE_UNKNOWN:
3293 default:
3294 buf->st_mode = S_IFCHR;
3295 non_disk:
3296 memset (&info, 0, sizeof (info));
3297 info.dwFileAttributes = 0;
3298 info.ftCreationTime = utc_base_ft;
3299 info.ftLastAccessTime = utc_base_ft;
3300 info.ftLastWriteTime = utc_base_ft;
3303 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3304 buf->st_mode = S_IFDIR;
3306 buf->st_nlink = info.nNumberOfLinks;
3307 /* Might as well use file index to fake inode values, but this
3308 is not guaranteed to be unique unless we keep a handle open
3309 all the time (even then there are situations where it is
3310 not unique). Reputedly, there are at most 48 bits of info
3311 (on NTFS, presumably less on FAT). */
3312 fake_inode = info.nFileIndexHigh;
3313 fake_inode <<= 32;
3314 fake_inode += info.nFileIndexLow;
3316 /* MSVC defines _ino_t to be short; other libc's might not. */
3317 if (sizeof (buf->st_ino) == 2)
3318 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3319 else
3320 buf->st_ino = fake_inode;
3322 /* Consider files to belong to current user.
3323 FIXME: this should use GetSecurityInfo API, but it is only
3324 available for _WIN32_WINNT >= 0x501. */
3325 buf->st_uid = dflt_passwd.pw_uid;
3326 buf->st_gid = dflt_passwd.pw_gid;
3327 strcpy (buf->st_uname, dflt_passwd.pw_name);
3328 strcpy (buf->st_gname, dflt_group.gr_name);
3330 buf->st_dev = info.dwVolumeSerialNumber;
3331 buf->st_rdev = info.dwVolumeSerialNumber;
3333 buf->st_size = info.nFileSizeHigh;
3334 buf->st_size <<= 32;
3335 buf->st_size += info.nFileSizeLow;
3337 /* Convert timestamps to Unix format. */
3338 buf->st_mtime = convert_time (info.ftLastWriteTime);
3339 buf->st_atime = convert_time (info.ftLastAccessTime);
3340 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3341 buf->st_ctime = convert_time (info.ftCreationTime);
3342 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3344 /* determine rwx permissions */
3345 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3346 permission = S_IREAD;
3347 else
3348 permission = S_IREAD | S_IWRITE;
3350 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3351 permission |= S_IEXEC;
3352 else
3354 #if 0 /* no way of knowing the filename */
3355 char * p = strrchr (name, '.');
3356 if (p != NULL &&
3357 (xstrcasecmp (p, ".exe") == 0 ||
3358 xstrcasecmp (p, ".com") == 0 ||
3359 xstrcasecmp (p, ".bat") == 0 ||
3360 xstrcasecmp (p, ".cmd") == 0))
3361 permission |= S_IEXEC;
3362 #endif
3365 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3367 return 0;
3371 utime (const char *name, struct utimbuf *times)
3373 struct utimbuf deftime;
3374 HANDLE fh;
3375 FILETIME mtime;
3376 FILETIME atime;
3378 if (times == NULL)
3380 deftime.modtime = deftime.actime = time (NULL);
3381 times = &deftime;
3384 /* Need write access to set times. */
3385 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
3386 0, OPEN_EXISTING, 0, NULL);
3387 if (fh)
3389 convert_from_time_t (times->actime, &atime);
3390 convert_from_time_t (times->modtime, &mtime);
3391 if (!SetFileTime (fh, NULL, &atime, &mtime))
3393 CloseHandle (fh);
3394 errno = EACCES;
3395 return -1;
3397 CloseHandle (fh);
3399 else
3401 errno = EINVAL;
3402 return -1;
3404 return 0;
3408 /* Support for browsing other processes and their attributes. See
3409 process.c for the Lisp bindings. */
3411 /* Helper wrapper functions. */
3413 HANDLE WINAPI create_toolhelp32_snapshot(
3414 DWORD Flags,
3415 DWORD Ignored)
3417 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
3419 if (g_b_init_create_toolhelp32_snapshot == 0)
3421 g_b_init_create_toolhelp32_snapshot = 1;
3422 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
3423 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3424 "CreateToolhelp32Snapshot");
3426 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
3428 return INVALID_HANDLE_VALUE;
3430 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
3433 BOOL WINAPI process32_first(
3434 HANDLE hSnapshot,
3435 LPPROCESSENTRY32 lppe)
3437 static Process32First_Proc s_pfn_Process32_First = NULL;
3439 if (g_b_init_process32_first == 0)
3441 g_b_init_process32_first = 1;
3442 s_pfn_Process32_First = (Process32First_Proc)
3443 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3444 "Process32First");
3446 if (s_pfn_Process32_First == NULL)
3448 return FALSE;
3450 return (s_pfn_Process32_First (hSnapshot, lppe));
3453 BOOL WINAPI process32_next(
3454 HANDLE hSnapshot,
3455 LPPROCESSENTRY32 lppe)
3457 static Process32Next_Proc s_pfn_Process32_Next = NULL;
3459 if (g_b_init_process32_next == 0)
3461 g_b_init_process32_next = 1;
3462 s_pfn_Process32_Next = (Process32Next_Proc)
3463 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3464 "Process32Next");
3466 if (s_pfn_Process32_Next == NULL)
3468 return FALSE;
3470 return (s_pfn_Process32_Next (hSnapshot, lppe));
3473 BOOL WINAPI open_thread_token (
3474 HANDLE ThreadHandle,
3475 DWORD DesiredAccess,
3476 BOOL OpenAsSelf,
3477 PHANDLE TokenHandle)
3479 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
3480 HMODULE hm_advapi32 = NULL;
3481 if (is_windows_9x () == TRUE)
3483 SetLastError (ERROR_NOT_SUPPORTED);
3484 return FALSE;
3486 if (g_b_init_open_thread_token == 0)
3488 g_b_init_open_thread_token = 1;
3489 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3490 s_pfn_Open_Thread_Token =
3491 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
3493 if (s_pfn_Open_Thread_Token == NULL)
3495 SetLastError (ERROR_NOT_SUPPORTED);
3496 return FALSE;
3498 return (
3499 s_pfn_Open_Thread_Token (
3500 ThreadHandle,
3501 DesiredAccess,
3502 OpenAsSelf,
3503 TokenHandle)
3507 BOOL WINAPI impersonate_self (
3508 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
3510 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
3511 HMODULE hm_advapi32 = NULL;
3512 if (is_windows_9x () == TRUE)
3514 return FALSE;
3516 if (g_b_init_impersonate_self == 0)
3518 g_b_init_impersonate_self = 1;
3519 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3520 s_pfn_Impersonate_Self =
3521 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
3523 if (s_pfn_Impersonate_Self == NULL)
3525 return FALSE;
3527 return s_pfn_Impersonate_Self (ImpersonationLevel);
3530 BOOL WINAPI revert_to_self (void)
3532 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
3533 HMODULE hm_advapi32 = NULL;
3534 if (is_windows_9x () == TRUE)
3536 return FALSE;
3538 if (g_b_init_revert_to_self == 0)
3540 g_b_init_revert_to_self = 1;
3541 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3542 s_pfn_Revert_To_Self =
3543 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
3545 if (s_pfn_Revert_To_Self == NULL)
3547 return FALSE;
3549 return s_pfn_Revert_To_Self ();
3552 BOOL WINAPI get_process_memory_info (
3553 HANDLE h_proc,
3554 PPROCESS_MEMORY_COUNTERS mem_counters,
3555 DWORD bufsize)
3557 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
3558 HMODULE hm_psapi = NULL;
3559 if (is_windows_9x () == TRUE)
3561 return FALSE;
3563 if (g_b_init_get_process_memory_info == 0)
3565 g_b_init_get_process_memory_info = 1;
3566 hm_psapi = LoadLibrary ("Psapi.dll");
3567 if (hm_psapi)
3568 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
3569 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
3571 if (s_pfn_Get_Process_Memory_Info == NULL)
3573 return FALSE;
3575 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
3578 BOOL WINAPI get_process_working_set_size (
3579 HANDLE h_proc,
3580 DWORD *minrss,
3581 DWORD *maxrss)
3583 static GetProcessWorkingSetSize_Proc
3584 s_pfn_Get_Process_Working_Set_Size = NULL;
3586 if (is_windows_9x () == TRUE)
3588 return FALSE;
3590 if (g_b_init_get_process_working_set_size == 0)
3592 g_b_init_get_process_working_set_size = 1;
3593 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
3594 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3595 "GetProcessWorkingSetSize");
3597 if (s_pfn_Get_Process_Working_Set_Size == NULL)
3599 return FALSE;
3601 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
3604 BOOL WINAPI global_memory_status (
3605 MEMORYSTATUS *buf)
3607 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
3609 if (is_windows_9x () == TRUE)
3611 return FALSE;
3613 if (g_b_init_global_memory_status == 0)
3615 g_b_init_global_memory_status = 1;
3616 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
3617 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3618 "GlobalMemoryStatus");
3620 if (s_pfn_Global_Memory_Status == NULL)
3622 return FALSE;
3624 return s_pfn_Global_Memory_Status (buf);
3627 BOOL WINAPI global_memory_status_ex (
3628 MEMORY_STATUS_EX *buf)
3630 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
3632 if (is_windows_9x () == TRUE)
3634 return FALSE;
3636 if (g_b_init_global_memory_status_ex == 0)
3638 g_b_init_global_memory_status_ex = 1;
3639 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
3640 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3641 "GlobalMemoryStatusEx");
3643 if (s_pfn_Global_Memory_Status_Ex == NULL)
3645 return FALSE;
3647 return s_pfn_Global_Memory_Status_Ex (buf);
3650 Lisp_Object
3651 w32_list_system_processes ()
3653 struct gcpro gcpro1;
3654 Lisp_Object proclist = Qnil;
3655 HANDLE h_snapshot;
3657 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
3659 if (h_snapshot != INVALID_HANDLE_VALUE)
3661 PROCESSENTRY32 proc_entry;
3662 DWORD proc_id;
3663 BOOL res;
3665 GCPRO1 (proclist);
3667 proc_entry.dwSize = sizeof (PROCESSENTRY32);
3668 for (res = process32_first (h_snapshot, &proc_entry); res;
3669 res = process32_next (h_snapshot, &proc_entry))
3671 proc_id = proc_entry.th32ProcessID;
3672 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
3675 CloseHandle (h_snapshot);
3676 UNGCPRO;
3677 proclist = Fnreverse (proclist);
3680 return proclist;
3683 static int
3684 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
3686 TOKEN_PRIVILEGES priv;
3687 DWORD priv_size = sizeof (priv);
3688 DWORD opriv_size = sizeof (*old_priv);
3689 HANDLE h_token = NULL;
3690 HANDLE h_thread = GetCurrentThread ();
3691 int ret_val = 0;
3692 BOOL res;
3694 res = open_thread_token (h_thread,
3695 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3696 FALSE, &h_token);
3697 if (!res && GetLastError () == ERROR_NO_TOKEN)
3699 if (impersonate_self (SecurityImpersonation))
3700 res = open_thread_token (h_thread,
3701 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3702 FALSE, &h_token);
3704 if (res)
3706 priv.PrivilegeCount = 1;
3707 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
3708 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
3709 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
3710 old_priv, &opriv_size)
3711 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3712 ret_val = 1;
3714 if (h_token)
3715 CloseHandle (h_token);
3717 return ret_val;
3720 static int
3721 restore_privilege (TOKEN_PRIVILEGES *priv)
3723 DWORD priv_size = sizeof (*priv);
3724 HANDLE h_token = NULL;
3725 int ret_val = 0;
3727 if (open_thread_token (GetCurrentThread (),
3728 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3729 FALSE, &h_token))
3731 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
3732 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3733 ret_val = 1;
3735 if (h_token)
3736 CloseHandle (h_token);
3738 return ret_val;
3741 static Lisp_Object
3742 ltime (time_sec, time_usec)
3743 long time_sec, time_usec;
3745 return list3 (make_number ((time_sec >> 16) & 0xffff),
3746 make_number (time_sec & 0xffff),
3747 make_number (time_usec));
3750 static int
3751 process_times (h_proc, ctime, etime, stime, utime, pcpu)
3752 HANDLE h_proc;
3753 Lisp_Object *ctime, *etime, *stime, *utime;
3754 double *pcpu;
3756 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
3757 long ctime_sec, ctime_usec, stime_sec, stime_usec, utime_sec, utime_usec;
3758 long etime_sec, etime_usec;
3759 long double tem1, tem2, tem;
3761 if (!h_proc
3762 || !get_process_times_fn
3763 || !(*get_process_times_fn)(h_proc, &ft_creation, &ft_exit,
3764 &ft_kernel, &ft_user))
3765 return 0;
3767 GetSystemTimeAsFileTime (&ft_current);
3769 tem1 = convert_time_raw (ft_kernel) * 0.1L;
3770 stime_usec = fmodl (tem1, 1000000.0L);
3771 stime_sec = tem1 * 0.000001L;
3772 *stime = ltime (stime_sec, stime_usec);
3773 tem2 = convert_time_raw (ft_user) * 0.1L;
3774 utime_usec = fmodl (tem2, 1000000.0L);
3775 utime_sec = tem2 * 0.000001L;
3776 *utime = ltime (utime_sec, utime_usec);
3777 tem = convert_time_raw (ft_creation);
3778 /* Process no 4 (System) returns zero creation time. */
3779 if (tem)
3780 tem = (tem - utc_base) * 0.1;
3781 ctime_usec = fmodl (tem, 1000000.0L);
3782 ctime_sec = tem * 0.000001L;
3783 *ctime = ltime (ctime_sec, ctime_usec);
3784 if (tem)
3785 tem = (convert_time_raw (ft_current) - utc_base) * 0.1L - tem;
3786 etime_usec = fmodl (tem, 1000000.0L);
3787 etime_sec = tem * 0.000001L;
3788 *etime = ltime (etime_sec, etime_usec);
3790 if (tem)
3792 *pcpu = 100.0 * (tem1 + tem2) / tem;
3793 if (*pcpu > 100)
3794 *pcpu = 100.0;
3796 else
3797 *pcpu = 0;
3799 return 1;
3802 Lisp_Object
3803 w32_system_process_attributes (pid)
3804 Lisp_Object pid;
3806 struct gcpro gcpro1, gcpro2, gcpro3;
3807 Lisp_Object attrs = Qnil;
3808 Lisp_Object cmd_str, decoded_cmd, tem;
3809 HANDLE h_snapshot, h_proc;
3810 DWORD proc_id;
3811 int found_proc = 0;
3812 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
3813 DWORD ulength = sizeof (uname), dlength = sizeof (domain), trash;
3814 DWORD glength = sizeof (gname);
3815 HANDLE token = NULL;
3816 SID_NAME_USE user_type;
3817 unsigned char buf[1024];
3818 TOKEN_USER user_token;
3819 TOKEN_PRIMARY_GROUP group_token;
3820 int euid;
3821 int egid;
3822 DWORD sess;
3823 PROCESS_MEMORY_COUNTERS mem;
3824 PROCESS_MEMORY_COUNTERS_EX mem_ex;
3825 DWORD minrss, maxrss;
3826 MEMORYSTATUS memst;
3827 MEMORY_STATUS_EX memstex;
3828 double totphys = 0.0;
3829 Lisp_Object ctime, stime, utime, etime;
3830 double pcpu;
3832 CHECK_NUMBER_OR_FLOAT (pid);
3833 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
3835 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
3837 GCPRO3 (attrs, decoded_cmd, tem);
3839 if (h_snapshot != INVALID_HANDLE_VALUE)
3841 PROCESSENTRY32 pe;
3842 BOOL res;
3844 pe.dwSize = sizeof (PROCESSENTRY32);
3845 for (res = process32_first (h_snapshot, &pe); res;
3846 res = process32_next (h_snapshot, &pe))
3848 if (proc_id == pe.th32ProcessID)
3850 if (proc_id == 0)
3851 decoded_cmd = build_string ("Idle");
3852 else
3854 /* Decode the command name from locale-specific
3855 encoding. */
3856 cmd_str = make_unibyte_string (pe.szExeFile,
3857 strlen (pe.szExeFile));
3858 decoded_cmd =
3859 code_convert_string_norecord (cmd_str,
3860 Vlocale_coding_system, 0);
3862 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
3863 attrs = Fcons (Fcons (Qppid,
3864 make_fixnum_or_float (pe.th32ParentProcessID)),
3865 attrs);
3866 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
3867 attrs);
3868 attrs = Fcons (Fcons (Qthcount,
3869 make_fixnum_or_float (pe.cntThreads)),
3870 attrs);
3871 found_proc = 1;
3872 break;
3876 CloseHandle (h_snapshot);
3879 if (!found_proc)
3881 UNGCPRO;
3882 return Qnil;
3885 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
3886 FALSE, proc_id);
3887 /* If we were denied a handle to the process, try again after
3888 enabling the SeDebugPrivilege in our process. */
3889 if (!h_proc)
3891 TOKEN_PRIVILEGES priv_current;
3893 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
3895 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
3896 FALSE, proc_id);
3897 restore_privilege (&priv_current);
3898 revert_to_self ();
3901 if (h_proc
3902 && open_process_token (h_proc, TOKEN_QUERY, &token)
3903 && get_token_information (token, TokenUser,
3904 (PVOID)buf, sizeof (buf), &trash))
3906 memcpy (&user_token, buf, sizeof (user_token));
3907 if (w32_cached_id (user_token.User.Sid, &euid, uname))
3908 ulength = strlen (uname);
3909 else
3911 lookup_account_sid (NULL, user_token.User.Sid, uname, &ulength,
3912 domain, &dlength, &user_type);
3913 euid = get_rid (user_token.User.Sid);
3914 w32_add_to_cache (user_token.User.Sid, euid, uname);
3916 /* Determine a reasonable euid and gid values. */
3917 if (xstrcasecmp ("administrator", uname) == 0)
3919 euid = 500; /* well-known Administrator uid */
3920 egid = 513; /* well-known None gid */
3922 else
3924 /* Get group id and name. */
3925 if (get_token_information (token, TokenPrimaryGroup,
3926 (PVOID)buf, sizeof (buf), &trash))
3928 memcpy (&group_token, buf, sizeof (group_token));
3929 if (w32_cached_id (group_token.PrimaryGroup, &egid, gname))
3930 glength = strlen (gname);
3931 else
3933 dlength = sizeof (domain);
3934 lookup_account_sid (NULL, group_token.PrimaryGroup,
3935 gname, &glength, NULL, &dlength,
3936 &user_type);
3937 egid = get_rid (group_token.PrimaryGroup);
3938 w32_add_to_cache (group_token.PrimaryGroup, egid, gname);
3941 else
3942 egid = euid;
3945 else if (!is_windows_9x ())
3947 /* We couldn't open the process token, presumably because of
3948 insufficient access rights. Assume this process is run by
3949 the system. */
3950 strcpy (uname, "SYSTEM");
3951 strcpy (gname, "None");
3952 euid = 18; /* SYSTEM */
3953 egid = 513; /* None */
3954 glength = strlen (gname);
3955 ulength = strlen (uname);
3957 /* If we are running under Windows 9X, where security calls are not
3958 supported, we assume all processes are run by the current
3959 user. */
3960 else if (GetUserName (uname, &ulength))
3962 if (xstrcasecmp ("administrator", uname) == 0)
3963 euid = 0;
3964 else
3965 euid = 123;
3966 egid = euid;
3967 strcpy (gname, "None");
3968 glength = strlen (gname);
3969 ulength = strlen (uname);
3971 else
3973 euid = 123;
3974 egid = 123;
3975 strcpy (uname, "administrator");
3976 ulength = strlen (uname);
3977 strcpy (gname, "None");
3978 glength = strlen (gname);
3980 if (token)
3981 CloseHandle (token);
3983 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
3984 tem = make_unibyte_string (uname, ulength);
3985 attrs = Fcons (Fcons (Quser,
3986 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
3987 attrs);
3988 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
3989 tem = make_unibyte_string (gname, glength);
3990 attrs = Fcons (Fcons (Qgroup,
3991 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
3992 attrs);
3994 if (global_memory_status_ex (&memstex))
3995 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
3996 totphys = memstex.ullTotalPhys / 1024.0;
3997 #else
3998 /* Visual Studio 6 cannot convert an unsigned __int64 type to
3999 double, so we need to do this for it... */
4001 DWORD tot_hi = memstex.ullTotalPhys >> 32;
4002 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
4003 DWORD tot_lo = memstex.ullTotalPhys % 1024;
4005 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
4007 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4008 else if (global_memory_status (&memst))
4009 totphys = memst.dwTotalPhys / 1024.0;
4011 if (h_proc
4012 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
4013 sizeof (mem_ex)))
4015 DWORD rss = mem_ex.WorkingSetSize / 1024;
4017 attrs = Fcons (Fcons (Qmajflt,
4018 make_fixnum_or_float (mem_ex.PageFaultCount)),
4019 attrs);
4020 attrs = Fcons (Fcons (Qvsize,
4021 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
4022 attrs);
4023 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4024 if (totphys)
4025 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4027 else if (h_proc
4028 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
4030 DWORD rss = mem_ex.WorkingSetSize / 1024;
4032 attrs = Fcons (Fcons (Qmajflt,
4033 make_fixnum_or_float (mem.PageFaultCount)),
4034 attrs);
4035 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4036 if (totphys)
4037 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4039 else if (h_proc
4040 && get_process_working_set_size (h_proc, &minrss, &maxrss))
4042 DWORD rss = maxrss / 1024;
4044 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
4045 if (totphys)
4046 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4049 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &pcpu))
4051 attrs = Fcons (Fcons (Qutime, utime), attrs);
4052 attrs = Fcons (Fcons (Qstime, stime), attrs);
4053 attrs = Fcons (Fcons (Qstart, ctime), attrs);
4054 attrs = Fcons (Fcons (Qetime, etime), attrs);
4055 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
4058 /* FIXME: Retrieve command line by walking the PEB of the process. */
4060 if (h_proc)
4061 CloseHandle (h_proc);
4062 UNGCPRO;
4063 return attrs;
4067 #ifdef HAVE_SOCKETS
4069 /* Wrappers for winsock functions to map between our file descriptors
4070 and winsock's handles; also set h_errno for convenience.
4072 To allow Emacs to run on systems which don't have winsock support
4073 installed, we dynamically link to winsock on startup if present, and
4074 otherwise provide the minimum necessary functionality
4075 (eg. gethostname). */
4077 /* function pointers for relevant socket functions */
4078 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
4079 void (PASCAL *pfn_WSASetLastError) (int iError);
4080 int (PASCAL *pfn_WSAGetLastError) (void);
4081 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
4082 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
4083 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
4084 int (PASCAL *pfn_socket) (int af, int type, int protocol);
4085 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
4086 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
4087 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
4088 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
4089 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
4090 int (PASCAL *pfn_closesocket) (SOCKET s);
4091 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
4092 int (PASCAL *pfn_WSACleanup) (void);
4094 u_short (PASCAL *pfn_htons) (u_short hostshort);
4095 u_short (PASCAL *pfn_ntohs) (u_short netshort);
4096 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
4097 int (PASCAL *pfn_gethostname) (char * name, int namelen);
4098 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
4099 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
4100 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
4101 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
4102 const char * optval, int optlen);
4103 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
4104 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
4105 int * namelen);
4106 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
4107 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
4108 struct sockaddr * from, int * fromlen);
4109 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
4110 const struct sockaddr * to, int tolen);
4112 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4113 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
4114 #ifndef HANDLE_FLAG_INHERIT
4115 #define HANDLE_FLAG_INHERIT 1
4116 #endif
4118 HANDLE winsock_lib;
4119 static int winsock_inuse;
4121 BOOL
4122 term_winsock (void)
4124 if (winsock_lib != NULL && winsock_inuse == 0)
4126 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4127 after WSAStartup returns successfully, but it seems reasonable
4128 to allow unloading winsock anyway in that case. */
4129 if (pfn_WSACleanup () == 0 ||
4130 pfn_WSAGetLastError () == WSAENETDOWN)
4132 if (FreeLibrary (winsock_lib))
4133 winsock_lib = NULL;
4134 return TRUE;
4137 return FALSE;
4140 BOOL
4141 init_winsock (int load_now)
4143 WSADATA winsockData;
4145 if (winsock_lib != NULL)
4146 return TRUE;
4148 pfn_SetHandleInformation = NULL;
4149 pfn_SetHandleInformation
4150 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4151 "SetHandleInformation");
4153 winsock_lib = LoadLibrary ("Ws2_32.dll");
4155 if (winsock_lib != NULL)
4157 /* dynamically link to socket functions */
4159 #define LOAD_PROC(fn) \
4160 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4161 goto fail;
4163 LOAD_PROC( WSAStartup );
4164 LOAD_PROC( WSASetLastError );
4165 LOAD_PROC( WSAGetLastError );
4166 LOAD_PROC( WSAEventSelect );
4167 LOAD_PROC( WSACreateEvent );
4168 LOAD_PROC( WSACloseEvent );
4169 LOAD_PROC( socket );
4170 LOAD_PROC( bind );
4171 LOAD_PROC( connect );
4172 LOAD_PROC( ioctlsocket );
4173 LOAD_PROC( recv );
4174 LOAD_PROC( send );
4175 LOAD_PROC( closesocket );
4176 LOAD_PROC( shutdown );
4177 LOAD_PROC( htons );
4178 LOAD_PROC( ntohs );
4179 LOAD_PROC( inet_addr );
4180 LOAD_PROC( gethostname );
4181 LOAD_PROC( gethostbyname );
4182 LOAD_PROC( getservbyname );
4183 LOAD_PROC( getpeername );
4184 LOAD_PROC( WSACleanup );
4185 LOAD_PROC( setsockopt );
4186 LOAD_PROC( listen );
4187 LOAD_PROC( getsockname );
4188 LOAD_PROC( accept );
4189 LOAD_PROC( recvfrom );
4190 LOAD_PROC( sendto );
4191 #undef LOAD_PROC
4193 /* specify version 1.1 of winsock */
4194 if (pfn_WSAStartup (0x101, &winsockData) == 0)
4196 if (winsockData.wVersion != 0x101)
4197 goto fail;
4199 if (!load_now)
4201 /* Report that winsock exists and is usable, but leave
4202 socket functions disabled. I am assuming that calling
4203 WSAStartup does not require any network interaction,
4204 and in particular does not cause or require a dial-up
4205 connection to be established. */
4207 pfn_WSACleanup ();
4208 FreeLibrary (winsock_lib);
4209 winsock_lib = NULL;
4211 winsock_inuse = 0;
4212 return TRUE;
4215 fail:
4216 FreeLibrary (winsock_lib);
4217 winsock_lib = NULL;
4220 return FALSE;
4224 int h_errno = 0;
4226 /* function to set h_errno for compatibility; map winsock error codes to
4227 normal system codes where they overlap (non-overlapping definitions
4228 are already in <sys/socket.h> */
4229 static void
4230 set_errno ()
4232 if (winsock_lib == NULL)
4233 h_errno = EINVAL;
4234 else
4235 h_errno = pfn_WSAGetLastError ();
4237 switch (h_errno)
4239 case WSAEACCES: h_errno = EACCES; break;
4240 case WSAEBADF: h_errno = EBADF; break;
4241 case WSAEFAULT: h_errno = EFAULT; break;
4242 case WSAEINTR: h_errno = EINTR; break;
4243 case WSAEINVAL: h_errno = EINVAL; break;
4244 case WSAEMFILE: h_errno = EMFILE; break;
4245 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
4246 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
4248 errno = h_errno;
4251 static void
4252 check_errno ()
4254 if (h_errno == 0 && winsock_lib != NULL)
4255 pfn_WSASetLastError (0);
4258 /* Extend strerror to handle the winsock-specific error codes. */
4259 struct {
4260 int errnum;
4261 char * msg;
4262 } _wsa_errlist[] = {
4263 WSAEINTR , "Interrupted function call",
4264 WSAEBADF , "Bad file descriptor",
4265 WSAEACCES , "Permission denied",
4266 WSAEFAULT , "Bad address",
4267 WSAEINVAL , "Invalid argument",
4268 WSAEMFILE , "Too many open files",
4270 WSAEWOULDBLOCK , "Resource temporarily unavailable",
4271 WSAEINPROGRESS , "Operation now in progress",
4272 WSAEALREADY , "Operation already in progress",
4273 WSAENOTSOCK , "Socket operation on non-socket",
4274 WSAEDESTADDRREQ , "Destination address required",
4275 WSAEMSGSIZE , "Message too long",
4276 WSAEPROTOTYPE , "Protocol wrong type for socket",
4277 WSAENOPROTOOPT , "Bad protocol option",
4278 WSAEPROTONOSUPPORT , "Protocol not supported",
4279 WSAESOCKTNOSUPPORT , "Socket type not supported",
4280 WSAEOPNOTSUPP , "Operation not supported",
4281 WSAEPFNOSUPPORT , "Protocol family not supported",
4282 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
4283 WSAEADDRINUSE , "Address already in use",
4284 WSAEADDRNOTAVAIL , "Cannot assign requested address",
4285 WSAENETDOWN , "Network is down",
4286 WSAENETUNREACH , "Network is unreachable",
4287 WSAENETRESET , "Network dropped connection on reset",
4288 WSAECONNABORTED , "Software caused connection abort",
4289 WSAECONNRESET , "Connection reset by peer",
4290 WSAENOBUFS , "No buffer space available",
4291 WSAEISCONN , "Socket is already connected",
4292 WSAENOTCONN , "Socket is not connected",
4293 WSAESHUTDOWN , "Cannot send after socket shutdown",
4294 WSAETOOMANYREFS , "Too many references", /* not sure */
4295 WSAETIMEDOUT , "Connection timed out",
4296 WSAECONNREFUSED , "Connection refused",
4297 WSAELOOP , "Network loop", /* not sure */
4298 WSAENAMETOOLONG , "Name is too long",
4299 WSAEHOSTDOWN , "Host is down",
4300 WSAEHOSTUNREACH , "No route to host",
4301 WSAENOTEMPTY , "Buffer not empty", /* not sure */
4302 WSAEPROCLIM , "Too many processes",
4303 WSAEUSERS , "Too many users", /* not sure */
4304 WSAEDQUOT , "Double quote in host name", /* really not sure */
4305 WSAESTALE , "Data is stale", /* not sure */
4306 WSAEREMOTE , "Remote error", /* not sure */
4308 WSASYSNOTREADY , "Network subsystem is unavailable",
4309 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
4310 WSANOTINITIALISED , "Winsock not initialized successfully",
4311 WSAEDISCON , "Graceful shutdown in progress",
4312 #ifdef WSAENOMORE
4313 WSAENOMORE , "No more operations allowed", /* not sure */
4314 WSAECANCELLED , "Operation cancelled", /* not sure */
4315 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
4316 WSAEINVALIDPROVIDER , "Invalid service provider version number",
4317 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
4318 WSASYSCALLFAILURE , "System call failure",
4319 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
4320 WSATYPE_NOT_FOUND , "Class type not found",
4321 WSA_E_NO_MORE , "No more resources available", /* really not sure */
4322 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
4323 WSAEREFUSED , "Operation refused", /* not sure */
4324 #endif
4326 WSAHOST_NOT_FOUND , "Host not found",
4327 WSATRY_AGAIN , "Authoritative host not found during name lookup",
4328 WSANO_RECOVERY , "Non-recoverable error during name lookup",
4329 WSANO_DATA , "Valid name, no data record of requested type",
4331 -1, NULL
4334 char *
4335 sys_strerror(int error_no)
4337 int i;
4338 static char unknown_msg[40];
4340 if (error_no >= 0 && error_no < sys_nerr)
4341 return sys_errlist[error_no];
4343 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
4344 if (_wsa_errlist[i].errnum == error_no)
4345 return _wsa_errlist[i].msg;
4347 sprintf(unknown_msg, "Unidentified error: %d", error_no);
4348 return unknown_msg;
4351 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4352 but I believe the method of keeping the socket handle separate (and
4353 insuring it is not inheritable) is the correct one. */
4355 //#define SOCK_REPLACE_HANDLE
4357 #ifdef SOCK_REPLACE_HANDLE
4358 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
4359 #else
4360 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4361 #endif
4363 int socket_to_fd (SOCKET s);
4366 sys_socket(int af, int type, int protocol)
4368 SOCKET s;
4370 if (winsock_lib == NULL)
4372 h_errno = ENETDOWN;
4373 return INVALID_SOCKET;
4376 check_errno ();
4378 /* call the real socket function */
4379 s = pfn_socket (af, type, protocol);
4381 if (s != INVALID_SOCKET)
4382 return socket_to_fd (s);
4384 set_errno ();
4385 return -1;
4388 /* Convert a SOCKET to a file descriptor. */
4390 socket_to_fd (SOCKET s)
4392 int fd;
4393 child_process * cp;
4395 /* Although under NT 3.5 _open_osfhandle will accept a socket
4396 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4397 that does not work under NT 3.1. However, we can get the same
4398 effect by using a backdoor function to replace an existing
4399 descriptor handle with the one we want. */
4401 /* allocate a file descriptor (with appropriate flags) */
4402 fd = _open ("NUL:", _O_RDWR);
4403 if (fd >= 0)
4405 #ifdef SOCK_REPLACE_HANDLE
4406 /* now replace handle to NUL with our socket handle */
4407 CloseHandle ((HANDLE) _get_osfhandle (fd));
4408 _free_osfhnd (fd);
4409 _set_osfhnd (fd, s);
4410 /* setmode (fd, _O_BINARY); */
4411 #else
4412 /* Make a non-inheritable copy of the socket handle. Note
4413 that it is possible that sockets aren't actually kernel
4414 handles, which appears to be the case on Windows 9x when
4415 the MS Proxy winsock client is installed. */
4417 /* Apparently there is a bug in NT 3.51 with some service
4418 packs, which prevents using DuplicateHandle to make a
4419 socket handle non-inheritable (causes WSACleanup to
4420 hang). The work-around is to use SetHandleInformation
4421 instead if it is available and implemented. */
4422 if (pfn_SetHandleInformation)
4424 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
4426 else
4428 HANDLE parent = GetCurrentProcess ();
4429 HANDLE new_s = INVALID_HANDLE_VALUE;
4431 if (DuplicateHandle (parent,
4432 (HANDLE) s,
4433 parent,
4434 &new_s,
4436 FALSE,
4437 DUPLICATE_SAME_ACCESS))
4439 /* It is possible that DuplicateHandle succeeds even
4440 though the socket wasn't really a kernel handle,
4441 because a real handle has the same value. So
4442 test whether the new handle really is a socket. */
4443 long nonblocking = 0;
4444 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
4446 pfn_closesocket (s);
4447 s = (SOCKET) new_s;
4449 else
4451 CloseHandle (new_s);
4456 fd_info[fd].hnd = (HANDLE) s;
4457 #endif
4459 /* set our own internal flags */
4460 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
4462 cp = new_child ();
4463 if (cp)
4465 cp->fd = fd;
4466 cp->status = STATUS_READ_ACKNOWLEDGED;
4468 /* attach child_process to fd_info */
4469 if (fd_info[ fd ].cp != NULL)
4471 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
4472 abort ();
4475 fd_info[ fd ].cp = cp;
4477 /* success! */
4478 winsock_inuse++; /* count open sockets */
4479 return fd;
4482 /* clean up */
4483 _close (fd);
4485 pfn_closesocket (s);
4486 h_errno = EMFILE;
4487 return -1;
4492 sys_bind (int s, const struct sockaddr * addr, int namelen)
4494 if (winsock_lib == NULL)
4496 h_errno = ENOTSOCK;
4497 return SOCKET_ERROR;
4500 check_errno ();
4501 if (fd_info[s].flags & FILE_SOCKET)
4503 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
4504 if (rc == SOCKET_ERROR)
4505 set_errno ();
4506 return rc;
4508 h_errno = ENOTSOCK;
4509 return SOCKET_ERROR;
4514 sys_connect (int s, const struct sockaddr * name, int namelen)
4516 if (winsock_lib == NULL)
4518 h_errno = ENOTSOCK;
4519 return SOCKET_ERROR;
4522 check_errno ();
4523 if (fd_info[s].flags & FILE_SOCKET)
4525 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
4526 if (rc == SOCKET_ERROR)
4527 set_errno ();
4528 return rc;
4530 h_errno = ENOTSOCK;
4531 return SOCKET_ERROR;
4534 u_short
4535 sys_htons (u_short hostshort)
4537 return (winsock_lib != NULL) ?
4538 pfn_htons (hostshort) : hostshort;
4541 u_short
4542 sys_ntohs (u_short netshort)
4544 return (winsock_lib != NULL) ?
4545 pfn_ntohs (netshort) : netshort;
4548 unsigned long
4549 sys_inet_addr (const char * cp)
4551 return (winsock_lib != NULL) ?
4552 pfn_inet_addr (cp) : INADDR_NONE;
4556 sys_gethostname (char * name, int namelen)
4558 if (winsock_lib != NULL)
4559 return pfn_gethostname (name, namelen);
4561 if (namelen > MAX_COMPUTERNAME_LENGTH)
4562 return !GetComputerName (name, (DWORD *)&namelen);
4564 h_errno = EFAULT;
4565 return SOCKET_ERROR;
4568 struct hostent *
4569 sys_gethostbyname(const char * name)
4571 struct hostent * host;
4573 if (winsock_lib == NULL)
4575 h_errno = ENETDOWN;
4576 return NULL;
4579 check_errno ();
4580 host = pfn_gethostbyname (name);
4581 if (!host)
4582 set_errno ();
4583 return host;
4586 struct servent *
4587 sys_getservbyname(const char * name, const char * proto)
4589 struct servent * serv;
4591 if (winsock_lib == NULL)
4593 h_errno = ENETDOWN;
4594 return NULL;
4597 check_errno ();
4598 serv = pfn_getservbyname (name, proto);
4599 if (!serv)
4600 set_errno ();
4601 return serv;
4605 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
4607 if (winsock_lib == NULL)
4609 h_errno = ENETDOWN;
4610 return SOCKET_ERROR;
4613 check_errno ();
4614 if (fd_info[s].flags & FILE_SOCKET)
4616 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
4617 if (rc == SOCKET_ERROR)
4618 set_errno ();
4619 return rc;
4621 h_errno = ENOTSOCK;
4622 return SOCKET_ERROR;
4627 sys_shutdown (int s, int how)
4629 if (winsock_lib == NULL)
4631 h_errno = ENETDOWN;
4632 return SOCKET_ERROR;
4635 check_errno ();
4636 if (fd_info[s].flags & FILE_SOCKET)
4638 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
4639 if (rc == SOCKET_ERROR)
4640 set_errno ();
4641 return rc;
4643 h_errno = ENOTSOCK;
4644 return SOCKET_ERROR;
4648 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
4650 if (winsock_lib == NULL)
4652 h_errno = ENETDOWN;
4653 return SOCKET_ERROR;
4656 check_errno ();
4657 if (fd_info[s].flags & FILE_SOCKET)
4659 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
4660 (const char *)optval, optlen);
4661 if (rc == SOCKET_ERROR)
4662 set_errno ();
4663 return rc;
4665 h_errno = ENOTSOCK;
4666 return SOCKET_ERROR;
4670 sys_listen (int s, int backlog)
4672 if (winsock_lib == NULL)
4674 h_errno = ENETDOWN;
4675 return SOCKET_ERROR;
4678 check_errno ();
4679 if (fd_info[s].flags & FILE_SOCKET)
4681 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
4682 if (rc == SOCKET_ERROR)
4683 set_errno ();
4684 else
4685 fd_info[s].flags |= FILE_LISTEN;
4686 return rc;
4688 h_errno = ENOTSOCK;
4689 return SOCKET_ERROR;
4693 sys_getsockname (int s, struct sockaddr * name, int * namelen)
4695 if (winsock_lib == NULL)
4697 h_errno = ENETDOWN;
4698 return SOCKET_ERROR;
4701 check_errno ();
4702 if (fd_info[s].flags & FILE_SOCKET)
4704 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
4705 if (rc == SOCKET_ERROR)
4706 set_errno ();
4707 return rc;
4709 h_errno = ENOTSOCK;
4710 return SOCKET_ERROR;
4714 sys_accept (int s, struct sockaddr * addr, int * addrlen)
4716 if (winsock_lib == NULL)
4718 h_errno = ENETDOWN;
4719 return -1;
4722 check_errno ();
4723 if (fd_info[s].flags & FILE_LISTEN)
4725 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
4726 int fd = -1;
4727 if (t == INVALID_SOCKET)
4728 set_errno ();
4729 else
4730 fd = socket_to_fd (t);
4732 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
4733 ResetEvent (fd_info[s].cp->char_avail);
4734 return fd;
4736 h_errno = ENOTSOCK;
4737 return -1;
4741 sys_recvfrom (int s, char * buf, int len, int flags,
4742 struct sockaddr * from, int * fromlen)
4744 if (winsock_lib == NULL)
4746 h_errno = ENETDOWN;
4747 return SOCKET_ERROR;
4750 check_errno ();
4751 if (fd_info[s].flags & FILE_SOCKET)
4753 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
4754 if (rc == SOCKET_ERROR)
4755 set_errno ();
4756 return rc;
4758 h_errno = ENOTSOCK;
4759 return SOCKET_ERROR;
4763 sys_sendto (int s, const char * buf, int len, int flags,
4764 const struct sockaddr * to, int tolen)
4766 if (winsock_lib == NULL)
4768 h_errno = ENETDOWN;
4769 return SOCKET_ERROR;
4772 check_errno ();
4773 if (fd_info[s].flags & FILE_SOCKET)
4775 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
4776 if (rc == SOCKET_ERROR)
4777 set_errno ();
4778 return rc;
4780 h_errno = ENOTSOCK;
4781 return SOCKET_ERROR;
4784 /* Windows does not have an fcntl function. Provide an implementation
4785 solely for making sockets non-blocking. */
4787 fcntl (int s, int cmd, int options)
4789 if (winsock_lib == NULL)
4791 h_errno = ENETDOWN;
4792 return -1;
4795 check_errno ();
4796 if (fd_info[s].flags & FILE_SOCKET)
4798 if (cmd == F_SETFL && options == O_NDELAY)
4800 unsigned long nblock = 1;
4801 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
4802 if (rc == SOCKET_ERROR)
4803 set_errno();
4804 /* Keep track of the fact that we set this to non-blocking. */
4805 fd_info[s].flags |= FILE_NDELAY;
4806 return rc;
4808 else
4810 h_errno = EINVAL;
4811 return SOCKET_ERROR;
4814 h_errno = ENOTSOCK;
4815 return SOCKET_ERROR;
4818 #endif /* HAVE_SOCKETS */
4821 /* Shadow main io functions: we need to handle pipes and sockets more
4822 intelligently, and implement non-blocking mode as well. */
4825 sys_close (int fd)
4827 int rc;
4829 if (fd < 0)
4831 errno = EBADF;
4832 return -1;
4835 if (fd < MAXDESC && fd_info[fd].cp)
4837 child_process * cp = fd_info[fd].cp;
4839 fd_info[fd].cp = NULL;
4841 if (CHILD_ACTIVE (cp))
4843 /* if last descriptor to active child_process then cleanup */
4844 int i;
4845 for (i = 0; i < MAXDESC; i++)
4847 if (i == fd)
4848 continue;
4849 if (fd_info[i].cp == cp)
4850 break;
4852 if (i == MAXDESC)
4854 #ifdef HAVE_SOCKETS
4855 if (fd_info[fd].flags & FILE_SOCKET)
4857 #ifndef SOCK_REPLACE_HANDLE
4858 if (winsock_lib == NULL) abort ();
4860 pfn_shutdown (SOCK_HANDLE (fd), 2);
4861 rc = pfn_closesocket (SOCK_HANDLE (fd));
4862 #endif
4863 winsock_inuse--; /* count open sockets */
4865 #endif
4866 delete_child (cp);
4871 /* Note that sockets do not need special treatment here (at least on
4872 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
4873 closesocket is equivalent to CloseHandle, which is to be expected
4874 because socket handles are fully fledged kernel handles. */
4875 rc = _close (fd);
4877 if (rc == 0 && fd < MAXDESC)
4878 fd_info[fd].flags = 0;
4880 return rc;
4884 sys_dup (int fd)
4886 int new_fd;
4888 new_fd = _dup (fd);
4889 if (new_fd >= 0 && new_fd < MAXDESC)
4891 /* duplicate our internal info as well */
4892 fd_info[new_fd] = fd_info[fd];
4894 return new_fd;
4899 sys_dup2 (int src, int dst)
4901 int rc;
4903 if (dst < 0 || dst >= MAXDESC)
4905 errno = EBADF;
4906 return -1;
4909 /* make sure we close the destination first if it's a pipe or socket */
4910 if (src != dst && fd_info[dst].flags != 0)
4911 sys_close (dst);
4913 rc = _dup2 (src, dst);
4914 if (rc == 0)
4916 /* duplicate our internal info as well */
4917 fd_info[dst] = fd_info[src];
4919 return rc;
4922 /* Unix pipe() has only one arg */
4924 sys_pipe (int * phandles)
4926 int rc;
4927 unsigned flags;
4929 /* make pipe handles non-inheritable; when we spawn a child, we
4930 replace the relevant handle with an inheritable one. Also put
4931 pipes into binary mode; we will do text mode translation ourselves
4932 if required. */
4933 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
4935 if (rc == 0)
4937 /* Protect against overflow, since Windows can open more handles than
4938 our fd_info array has room for. */
4939 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
4941 _close (phandles[0]);
4942 _close (phandles[1]);
4943 rc = -1;
4945 else
4947 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
4948 fd_info[phandles[0]].flags = flags;
4950 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
4951 fd_info[phandles[1]].flags = flags;
4955 return rc;
4958 /* From ntproc.c */
4959 extern int w32_pipe_read_delay;
4961 /* Function to do blocking read of one byte, needed to implement
4962 select. It is only allowed on sockets and pipes. */
4964 _sys_read_ahead (int fd)
4966 child_process * cp;
4967 int rc;
4969 if (fd < 0 || fd >= MAXDESC)
4970 return STATUS_READ_ERROR;
4972 cp = fd_info[fd].cp;
4974 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
4975 return STATUS_READ_ERROR;
4977 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
4978 || (fd_info[fd].flags & FILE_READ) == 0)
4980 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
4981 abort ();
4984 cp->status = STATUS_READ_IN_PROGRESS;
4986 if (fd_info[fd].flags & FILE_PIPE)
4988 rc = _read (fd, &cp->chr, sizeof (char));
4990 /* Give subprocess time to buffer some more output for us before
4991 reporting that input is available; we need this because Windows 95
4992 connects DOS programs to pipes by making the pipe appear to be
4993 the normal console stdout - as a result most DOS programs will
4994 write to stdout without buffering, ie. one character at a
4995 time. Even some W32 programs do this - "dir" in a command
4996 shell on NT is very slow if we don't do this. */
4997 if (rc > 0)
4999 int wait = w32_pipe_read_delay;
5001 if (wait > 0)
5002 Sleep (wait);
5003 else if (wait < 0)
5004 while (++wait <= 0)
5005 /* Yield remainder of our time slice, effectively giving a
5006 temporary priority boost to the child process. */
5007 Sleep (0);
5010 else if (fd_info[fd].flags & FILE_SERIAL)
5012 HANDLE hnd = fd_info[fd].hnd;
5013 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5014 COMMTIMEOUTS ct;
5016 /* Configure timeouts for blocking read. */
5017 if (!GetCommTimeouts (hnd, &ct))
5018 return STATUS_READ_ERROR;
5019 ct.ReadIntervalTimeout = 0;
5020 ct.ReadTotalTimeoutMultiplier = 0;
5021 ct.ReadTotalTimeoutConstant = 0;
5022 if (!SetCommTimeouts (hnd, &ct))
5023 return STATUS_READ_ERROR;
5025 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
5027 if (GetLastError () != ERROR_IO_PENDING)
5028 return STATUS_READ_ERROR;
5029 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5030 return STATUS_READ_ERROR;
5033 #ifdef HAVE_SOCKETS
5034 else if (fd_info[fd].flags & FILE_SOCKET)
5036 unsigned long nblock = 0;
5037 /* We always want this to block, so temporarily disable NDELAY. */
5038 if (fd_info[fd].flags & FILE_NDELAY)
5039 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5041 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
5043 if (fd_info[fd].flags & FILE_NDELAY)
5045 nblock = 1;
5046 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5049 #endif
5051 if (rc == sizeof (char))
5052 cp->status = STATUS_READ_SUCCEEDED;
5053 else
5054 cp->status = STATUS_READ_FAILED;
5056 return cp->status;
5060 _sys_wait_accept (int fd)
5062 HANDLE hEv;
5063 child_process * cp;
5064 int rc;
5066 if (fd < 0 || fd >= MAXDESC)
5067 return STATUS_READ_ERROR;
5069 cp = fd_info[fd].cp;
5071 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5072 return STATUS_READ_ERROR;
5074 cp->status = STATUS_READ_FAILED;
5076 hEv = pfn_WSACreateEvent ();
5077 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
5078 if (rc != SOCKET_ERROR)
5080 rc = WaitForSingleObject (hEv, INFINITE);
5081 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
5082 if (rc == WAIT_OBJECT_0)
5083 cp->status = STATUS_READ_SUCCEEDED;
5085 pfn_WSACloseEvent (hEv);
5087 return cp->status;
5091 sys_read (int fd, char * buffer, unsigned int count)
5093 int nchars;
5094 int to_read;
5095 DWORD waiting;
5096 char * orig_buffer = buffer;
5098 if (fd < 0)
5100 errno = EBADF;
5101 return -1;
5104 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5106 child_process *cp = fd_info[fd].cp;
5108 if ((fd_info[fd].flags & FILE_READ) == 0)
5110 errno = EBADF;
5111 return -1;
5114 nchars = 0;
5116 /* re-read CR carried over from last read */
5117 if (fd_info[fd].flags & FILE_LAST_CR)
5119 if (fd_info[fd].flags & FILE_BINARY) abort ();
5120 *buffer++ = 0x0d;
5121 count--;
5122 nchars++;
5123 fd_info[fd].flags &= ~FILE_LAST_CR;
5126 /* presence of a child_process structure means we are operating in
5127 non-blocking mode - otherwise we just call _read directly.
5128 Note that the child_process structure might be missing because
5129 reap_subprocess has been called; in this case the pipe is
5130 already broken, so calling _read on it is okay. */
5131 if (cp)
5133 int current_status = cp->status;
5135 switch (current_status)
5137 case STATUS_READ_FAILED:
5138 case STATUS_READ_ERROR:
5139 /* report normal EOF if nothing in buffer */
5140 if (nchars <= 0)
5141 fd_info[fd].flags |= FILE_AT_EOF;
5142 return nchars;
5144 case STATUS_READ_READY:
5145 case STATUS_READ_IN_PROGRESS:
5146 DebPrint (("sys_read called when read is in progress\n"));
5147 errno = EWOULDBLOCK;
5148 return -1;
5150 case STATUS_READ_SUCCEEDED:
5151 /* consume read-ahead char */
5152 *buffer++ = cp->chr;
5153 count--;
5154 nchars++;
5155 cp->status = STATUS_READ_ACKNOWLEDGED;
5156 ResetEvent (cp->char_avail);
5158 case STATUS_READ_ACKNOWLEDGED:
5159 break;
5161 default:
5162 DebPrint (("sys_read: bad status %d\n", current_status));
5163 errno = EBADF;
5164 return -1;
5167 if (fd_info[fd].flags & FILE_PIPE)
5169 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
5170 to_read = min (waiting, (DWORD) count);
5172 if (to_read > 0)
5173 nchars += _read (fd, buffer, to_read);
5175 else if (fd_info[fd].flags & FILE_SERIAL)
5177 HANDLE hnd = fd_info[fd].hnd;
5178 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5179 DWORD err = 0;
5180 int rc = 0;
5181 COMMTIMEOUTS ct;
5183 if (count > 0)
5185 /* Configure timeouts for non-blocking read. */
5186 if (!GetCommTimeouts (hnd, &ct))
5188 errno = EIO;
5189 return -1;
5191 ct.ReadIntervalTimeout = MAXDWORD;
5192 ct.ReadTotalTimeoutMultiplier = 0;
5193 ct.ReadTotalTimeoutConstant = 0;
5194 if (!SetCommTimeouts (hnd, &ct))
5196 errno = EIO;
5197 return -1;
5200 if (!ResetEvent (ovl->hEvent))
5202 errno = EIO;
5203 return -1;
5205 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
5207 if (GetLastError () != ERROR_IO_PENDING)
5209 errno = EIO;
5210 return -1;
5212 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5214 errno = EIO;
5215 return -1;
5218 nchars += rc;
5221 #ifdef HAVE_SOCKETS
5222 else /* FILE_SOCKET */
5224 if (winsock_lib == NULL) abort ();
5226 /* do the equivalent of a non-blocking read */
5227 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
5228 if (waiting == 0 && nchars == 0)
5230 h_errno = errno = EWOULDBLOCK;
5231 return -1;
5234 if (waiting)
5236 /* always use binary mode for sockets */
5237 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
5238 if (res == SOCKET_ERROR)
5240 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
5241 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5242 set_errno ();
5243 return -1;
5245 nchars += res;
5248 #endif
5250 else
5252 int nread = _read (fd, buffer, count);
5253 if (nread >= 0)
5254 nchars += nread;
5255 else if (nchars == 0)
5256 nchars = nread;
5259 if (nchars <= 0)
5260 fd_info[fd].flags |= FILE_AT_EOF;
5261 /* Perform text mode translation if required. */
5262 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
5264 nchars = crlf_to_lf (nchars, orig_buffer);
5265 /* If buffer contains only CR, return that. To be absolutely
5266 sure we should attempt to read the next char, but in
5267 practice a CR to be followed by LF would not appear by
5268 itself in the buffer. */
5269 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
5271 fd_info[fd].flags |= FILE_LAST_CR;
5272 nchars--;
5276 else
5277 nchars = _read (fd, buffer, count);
5279 return nchars;
5282 /* From w32xfns.c */
5283 extern HANDLE interrupt_handle;
5285 /* For now, don't bother with a non-blocking mode */
5287 sys_write (int fd, const void * buffer, unsigned int count)
5289 int nchars;
5291 if (fd < 0)
5293 errno = EBADF;
5294 return -1;
5297 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5299 if ((fd_info[fd].flags & FILE_WRITE) == 0)
5301 errno = EBADF;
5302 return -1;
5305 /* Perform text mode translation if required. */
5306 if ((fd_info[fd].flags & FILE_BINARY) == 0)
5308 char * tmpbuf = alloca (count * 2);
5309 unsigned char * src = (void *)buffer;
5310 unsigned char * dst = tmpbuf;
5311 int nbytes = count;
5313 while (1)
5315 unsigned char *next;
5316 /* copy next line or remaining bytes */
5317 next = _memccpy (dst, src, '\n', nbytes);
5318 if (next)
5320 /* copied one line ending with '\n' */
5321 int copied = next - dst;
5322 nbytes -= copied;
5323 src += copied;
5324 /* insert '\r' before '\n' */
5325 next[-1] = '\r';
5326 next[0] = '\n';
5327 dst = next + 1;
5328 count++;
5330 else
5331 /* copied remaining partial line -> now finished */
5332 break;
5334 buffer = tmpbuf;
5338 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
5340 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
5341 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
5342 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
5343 DWORD active = 0;
5345 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
5347 if (GetLastError () != ERROR_IO_PENDING)
5349 errno = EIO;
5350 return -1;
5352 if (detect_input_pending ())
5353 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
5354 QS_ALLINPUT);
5355 else
5356 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
5357 if (active == WAIT_OBJECT_0)
5358 { /* User pressed C-g, cancel write, then leave. Don't bother
5359 cleaning up as we may only get stuck in buggy drivers. */
5360 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
5361 CancelIo (hnd);
5362 errno = EIO;
5363 return -1;
5365 if (active == WAIT_OBJECT_0 + 1
5366 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
5368 errno = EIO;
5369 return -1;
5373 else
5374 #ifdef HAVE_SOCKETS
5375 if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
5377 unsigned long nblock = 0;
5378 if (winsock_lib == NULL) abort ();
5380 /* TODO: implement select() properly so non-blocking I/O works. */
5381 /* For now, make sure the write blocks. */
5382 if (fd_info[fd].flags & FILE_NDELAY)
5383 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5385 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
5387 /* Set the socket back to non-blocking if it was before,
5388 for other operations that support it. */
5389 if (fd_info[fd].flags & FILE_NDELAY)
5391 nblock = 1;
5392 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5395 if (nchars == SOCKET_ERROR)
5397 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
5398 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5399 set_errno ();
5402 else
5403 #endif
5404 nchars = _write (fd, buffer, count);
5406 return nchars;
5409 static void
5410 check_windows_init_file ()
5412 extern int noninteractive, inhibit_window_system;
5414 /* A common indication that Emacs is not installed properly is when
5415 it cannot find the Windows installation file. If this file does
5416 not exist in the expected place, tell the user. */
5418 if (!noninteractive && !inhibit_window_system)
5420 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
5421 Lisp_Object objs[2];
5422 Lisp_Object full_load_path;
5423 Lisp_Object init_file;
5424 int fd;
5426 objs[0] = Vload_path;
5427 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5428 full_load_path = Fappend (2, objs);
5429 init_file = build_string ("term/w32-win");
5430 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
5431 if (fd < 0)
5433 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
5434 char *init_file_name = SDATA (init_file);
5435 char *load_path = SDATA (load_path_print);
5436 char *buffer = alloca (1024
5437 + strlen (init_file_name)
5438 + strlen (load_path));
5440 sprintf (buffer,
5441 "The Emacs Windows initialization file \"%s.el\" "
5442 "could not be found in your Emacs installation. "
5443 "Emacs checked the following directories for this file:\n"
5444 "\n%s\n\n"
5445 "When Emacs cannot find this file, it usually means that it "
5446 "was not installed properly, or its distribution file was "
5447 "not unpacked properly.\nSee the README.W32 file in the "
5448 "top-level Emacs directory for more information.",
5449 init_file_name, load_path);
5450 MessageBox (NULL,
5451 buffer,
5452 "Emacs Abort Dialog",
5453 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
5454 /* Use the low-level Emacs abort. */
5455 #undef abort
5456 abort ();
5458 else
5460 _close (fd);
5465 void
5466 term_ntproc ()
5468 #ifdef HAVE_SOCKETS
5469 /* shutdown the socket interface if necessary */
5470 term_winsock ();
5471 #endif
5473 term_w32select ();
5476 void
5477 init_ntproc ()
5479 #ifdef HAVE_SOCKETS
5480 /* Initialise the socket interface now if available and requested by
5481 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5482 delayed until open-network-stream is called (w32-has-winsock can
5483 also be used to dynamically load or reload winsock).
5485 Conveniently, init_environment is called before us, so
5486 PRELOAD_WINSOCK can be set in the registry. */
5488 /* Always initialize this correctly. */
5489 winsock_lib = NULL;
5491 if (getenv ("PRELOAD_WINSOCK") != NULL)
5492 init_winsock (TRUE);
5493 #endif
5495 /* Initial preparation for subprocess support: replace our standard
5496 handles with non-inheritable versions. */
5498 HANDLE parent;
5499 HANDLE stdin_save = INVALID_HANDLE_VALUE;
5500 HANDLE stdout_save = INVALID_HANDLE_VALUE;
5501 HANDLE stderr_save = INVALID_HANDLE_VALUE;
5503 parent = GetCurrentProcess ();
5505 /* ignore errors when duplicating and closing; typically the
5506 handles will be invalid when running as a gui program. */
5507 DuplicateHandle (parent,
5508 GetStdHandle (STD_INPUT_HANDLE),
5509 parent,
5510 &stdin_save,
5512 FALSE,
5513 DUPLICATE_SAME_ACCESS);
5515 DuplicateHandle (parent,
5516 GetStdHandle (STD_OUTPUT_HANDLE),
5517 parent,
5518 &stdout_save,
5520 FALSE,
5521 DUPLICATE_SAME_ACCESS);
5523 DuplicateHandle (parent,
5524 GetStdHandle (STD_ERROR_HANDLE),
5525 parent,
5526 &stderr_save,
5528 FALSE,
5529 DUPLICATE_SAME_ACCESS);
5531 fclose (stdin);
5532 fclose (stdout);
5533 fclose (stderr);
5535 if (stdin_save != INVALID_HANDLE_VALUE)
5536 _open_osfhandle ((long) stdin_save, O_TEXT);
5537 else
5538 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
5539 _fdopen (0, "r");
5541 if (stdout_save != INVALID_HANDLE_VALUE)
5542 _open_osfhandle ((long) stdout_save, O_TEXT);
5543 else
5544 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5545 _fdopen (1, "w");
5547 if (stderr_save != INVALID_HANDLE_VALUE)
5548 _open_osfhandle ((long) stderr_save, O_TEXT);
5549 else
5550 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5551 _fdopen (2, "w");
5554 /* unfortunately, atexit depends on implementation of malloc */
5555 /* atexit (term_ntproc); */
5556 signal (SIGABRT, term_ntproc);
5558 /* determine which drives are fixed, for GetCachedVolumeInformation */
5560 /* GetDriveType must have trailing backslash. */
5561 char drive[] = "A:\\";
5563 /* Loop over all possible drive letters */
5564 while (*drive <= 'Z')
5566 /* Record if this drive letter refers to a fixed drive. */
5567 fixed_drives[DRIVE_INDEX (*drive)] =
5568 (GetDriveType (drive) == DRIVE_FIXED);
5570 (*drive)++;
5573 /* Reset the volume info cache. */
5574 volume_cache = NULL;
5577 /* Check to see if Emacs has been installed correctly. */
5578 check_windows_init_file ();
5582 shutdown_handler ensures that buffers' autosave files are
5583 up to date when the user logs off, or the system shuts down.
5585 BOOL WINAPI shutdown_handler(DWORD type)
5587 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5588 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
5589 || type == CTRL_LOGOFF_EVENT /* User logs off. */
5590 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
5592 /* Shut down cleanly, making sure autosave files are up to date. */
5593 shut_down_emacs (0, 0, Qnil);
5596 /* Allow other handlers to handle this signal. */
5597 return FALSE;
5601 globals_of_w32 is used to initialize those global variables that
5602 must always be initialized on startup even when the global variable
5603 initialized is non zero (see the function main in emacs.c).
5605 void
5606 globals_of_w32 ()
5608 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
5610 get_process_times_fn = (GetProcessTimes_Proc)
5611 GetProcAddress (kernel32, "GetProcessTimes");
5613 g_b_init_is_windows_9x = 0;
5614 g_b_init_open_process_token = 0;
5615 g_b_init_get_token_information = 0;
5616 g_b_init_lookup_account_sid = 0;
5617 g_b_init_get_sid_identifier_authority = 0;
5618 g_b_init_get_sid_sub_authority = 0;
5619 g_b_init_get_sid_sub_authority_count = 0;
5620 g_b_init_get_file_security = 0;
5621 g_b_init_get_security_descriptor_owner = 0;
5622 g_b_init_get_security_descriptor_group = 0;
5623 g_b_init_is_valid_sid = 0;
5624 g_b_init_create_toolhelp32_snapshot = 0;
5625 g_b_init_process32_first = 0;
5626 g_b_init_process32_next = 0;
5627 g_b_init_open_thread_token = 0;
5628 g_b_init_impersonate_self = 0;
5629 g_b_init_revert_to_self = 0;
5630 g_b_init_get_process_memory_info = 0;
5631 g_b_init_get_process_working_set_size = 0;
5632 g_b_init_global_memory_status = 0;
5633 g_b_init_global_memory_status_ex = 0;
5634 g_b_init_equal_sid = 0;
5635 g_b_init_copy_sid = 0;
5636 g_b_init_get_length_sid = 0;
5637 /* The following sets a handler for shutdown notifications for
5638 console apps. This actually applies to Emacs in both console and
5639 GUI modes, since we had to fool windows into thinking emacs is a
5640 console application to get console mode to work. */
5641 SetConsoleCtrlHandler(shutdown_handler, TRUE);
5643 /* "None" is the default group name on standalone workstations. */
5644 strcpy (dflt_group_name, "None");
5647 /* For make-serial-process */
5648 int serial_open (char *port)
5650 HANDLE hnd;
5651 child_process *cp;
5652 int fd = -1;
5654 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
5655 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
5656 if (hnd == INVALID_HANDLE_VALUE)
5657 error ("Could not open %s", port);
5658 fd = (int) _open_osfhandle ((int) hnd, 0);
5659 if (fd == -1)
5660 error ("Could not open %s", port);
5662 cp = new_child ();
5663 if (!cp)
5664 error ("Could not create child process");
5665 cp->fd = fd;
5666 cp->status = STATUS_READ_ACKNOWLEDGED;
5667 fd_info[ fd ].hnd = hnd;
5668 fd_info[ fd ].flags |=
5669 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
5670 if (fd_info[ fd ].cp != NULL)
5672 error ("fd_info[fd = %d] is already in use", fd);
5674 fd_info[ fd ].cp = cp;
5675 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5676 if (cp->ovl_read.hEvent == NULL)
5677 error ("Could not create read event");
5678 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5679 if (cp->ovl_write.hEvent == NULL)
5680 error ("Could not create write event");
5682 return fd;
5685 /* For serial-process-configure */
5686 void
5687 serial_configure (struct Lisp_Process *p,
5688 Lisp_Object contact)
5690 Lisp_Object childp2 = Qnil;
5691 Lisp_Object tem = Qnil;
5692 HANDLE hnd;
5693 DCB dcb;
5694 COMMTIMEOUTS ct;
5695 char summary[4] = "???"; /* This usually becomes "8N1". */
5697 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
5698 error ("Not a serial process");
5699 hnd = fd_info[ p->outfd ].hnd;
5701 childp2 = Fcopy_sequence (p->childp);
5703 /* Initialize timeouts for blocking read and blocking write. */
5704 if (!GetCommTimeouts (hnd, &ct))
5705 error ("GetCommTimeouts() failed");
5706 ct.ReadIntervalTimeout = 0;
5707 ct.ReadTotalTimeoutMultiplier = 0;
5708 ct.ReadTotalTimeoutConstant = 0;
5709 ct.WriteTotalTimeoutMultiplier = 0;
5710 ct.WriteTotalTimeoutConstant = 0;
5711 if (!SetCommTimeouts (hnd, &ct))
5712 error ("SetCommTimeouts() failed");
5713 /* Read port attributes and prepare default configuration. */
5714 memset (&dcb, 0, sizeof (dcb));
5715 dcb.DCBlength = sizeof (DCB);
5716 if (!GetCommState (hnd, &dcb))
5717 error ("GetCommState() failed");
5718 dcb.fBinary = TRUE;
5719 dcb.fNull = FALSE;
5720 dcb.fAbortOnError = FALSE;
5721 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
5722 dcb.ErrorChar = 0;
5723 dcb.EofChar = 0;
5724 dcb.EvtChar = 0;
5726 /* Configure speed. */
5727 if (!NILP (Fplist_member (contact, QCspeed)))
5728 tem = Fplist_get (contact, QCspeed);
5729 else
5730 tem = Fplist_get (p->childp, QCspeed);
5731 CHECK_NUMBER (tem);
5732 dcb.BaudRate = XINT (tem);
5733 childp2 = Fplist_put (childp2, QCspeed, tem);
5735 /* Configure bytesize. */
5736 if (!NILP (Fplist_member (contact, QCbytesize)))
5737 tem = Fplist_get (contact, QCbytesize);
5738 else
5739 tem = Fplist_get (p->childp, QCbytesize);
5740 if (NILP (tem))
5741 tem = make_number (8);
5742 CHECK_NUMBER (tem);
5743 if (XINT (tem) != 7 && XINT (tem) != 8)
5744 error (":bytesize must be nil (8), 7, or 8");
5745 dcb.ByteSize = XINT (tem);
5746 summary[0] = XINT (tem) + '0';
5747 childp2 = Fplist_put (childp2, QCbytesize, tem);
5749 /* Configure parity. */
5750 if (!NILP (Fplist_member (contact, QCparity)))
5751 tem = Fplist_get (contact, QCparity);
5752 else
5753 tem = Fplist_get (p->childp, QCparity);
5754 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
5755 error (":parity must be nil (no parity), `even', or `odd'");
5756 dcb.fParity = FALSE;
5757 dcb.Parity = NOPARITY;
5758 dcb.fErrorChar = FALSE;
5759 if (NILP (tem))
5761 summary[1] = 'N';
5763 else if (EQ (tem, Qeven))
5765 summary[1] = 'E';
5766 dcb.fParity = TRUE;
5767 dcb.Parity = EVENPARITY;
5768 dcb.fErrorChar = TRUE;
5770 else if (EQ (tem, Qodd))
5772 summary[1] = 'O';
5773 dcb.fParity = TRUE;
5774 dcb.Parity = ODDPARITY;
5775 dcb.fErrorChar = TRUE;
5777 childp2 = Fplist_put (childp2, QCparity, tem);
5779 /* Configure stopbits. */
5780 if (!NILP (Fplist_member (contact, QCstopbits)))
5781 tem = Fplist_get (contact, QCstopbits);
5782 else
5783 tem = Fplist_get (p->childp, QCstopbits);
5784 if (NILP (tem))
5785 tem = make_number (1);
5786 CHECK_NUMBER (tem);
5787 if (XINT (tem) != 1 && XINT (tem) != 2)
5788 error (":stopbits must be nil (1 stopbit), 1, or 2");
5789 summary[2] = XINT (tem) + '0';
5790 if (XINT (tem) == 1)
5791 dcb.StopBits = ONESTOPBIT;
5792 else if (XINT (tem) == 2)
5793 dcb.StopBits = TWOSTOPBITS;
5794 childp2 = Fplist_put (childp2, QCstopbits, tem);
5796 /* Configure flowcontrol. */
5797 if (!NILP (Fplist_member (contact, QCflowcontrol)))
5798 tem = Fplist_get (contact, QCflowcontrol);
5799 else
5800 tem = Fplist_get (p->childp, QCflowcontrol);
5801 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
5802 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
5803 dcb.fOutxCtsFlow = FALSE;
5804 dcb.fOutxDsrFlow = FALSE;
5805 dcb.fDtrControl = DTR_CONTROL_DISABLE;
5806 dcb.fDsrSensitivity = FALSE;
5807 dcb.fTXContinueOnXoff = FALSE;
5808 dcb.fOutX = FALSE;
5809 dcb.fInX = FALSE;
5810 dcb.fRtsControl = RTS_CONTROL_DISABLE;
5811 dcb.XonChar = 17; /* Control-Q */
5812 dcb.XoffChar = 19; /* Control-S */
5813 if (NILP (tem))
5815 /* Already configured. */
5817 else if (EQ (tem, Qhw))
5819 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
5820 dcb.fOutxCtsFlow = TRUE;
5822 else if (EQ (tem, Qsw))
5824 dcb.fOutX = TRUE;
5825 dcb.fInX = TRUE;
5827 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
5829 /* Activate configuration. */
5830 if (!SetCommState (hnd, &dcb))
5831 error ("SetCommState() failed");
5833 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
5834 p->childp = childp2;
5837 /* end of w32.c */
5839 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
5840 (do not change this comment) */