1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3 2007, 2008, 2009 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 */
26 #include <float.h> /* for DBL_EPSILON */
34 #include <sys/utime.h>
35 #include <mbstring.h> /* for _mbspbrk */
38 /* must include CRT headers *before* config.h */
73 #define _ANONYMOUS_UNION
74 #define _ANONYMOUS_STRUCT
77 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
78 use a different name to avoid compilation problems. */
79 typedef struct _MEMORY_STATUS_EX
{
82 DWORDLONG ullTotalPhys
;
83 DWORDLONG ullAvailPhys
;
84 DWORDLONG ullTotalPageFile
;
85 DWORDLONG ullAvailPageFile
;
86 DWORDLONG ullTotalVirtual
;
87 DWORDLONG ullAvailVirtual
;
88 DWORDLONG ullAvailExtendedVirtual
;
89 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
96 /* This either is not in psapi.h or guarded by higher value of
97 _WIN32_WINNT than what we use. */
98 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
100 DWORD PageFaultCount
;
101 DWORD PeakWorkingSetSize
;
102 DWORD WorkingSetSize
;
103 DWORD QuotaPeakPagedPoolUsage
;
104 DWORD QuotaPagedPoolUsage
;
105 DWORD QuotaPeakNonPagedPoolUsage
;
106 DWORD QuotaNonPagedPoolUsage
;
108 DWORD PeakPagefileUsage
;
110 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
112 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
113 #include <sys/socket.h>
137 #include "dispextern.h" /* for xstrcasecmp */
138 #include "coding.h" /* for Vlocale_coding_system */
140 /* For serial_configure and serial_open. */
143 extern Lisp_Object QCport
, QCspeed
, QCprocess
;
144 extern Lisp_Object QCbytesize
, QCstopbits
, QCparity
, Qodd
, Qeven
;
145 extern Lisp_Object QCflowcontrol
, Qhw
, Qsw
, QCsummary
;
147 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
148 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
150 void globals_of_w32 ();
151 static DWORD
get_rid (PSID
);
153 extern Lisp_Object Vw32_downcase_file_names
;
154 extern Lisp_Object Vw32_generate_fake_inodes
;
155 extern Lisp_Object Vw32_get_true_file_attributes
;
156 /* Defined in process.c for its own purpose. */
157 extern Lisp_Object Qlocal
;
159 extern int w32_num_mouse_buttons
;
162 /* Initialization states.
164 WARNING: If you add any more such variables for additional APIs,
165 you MUST add initialization for them to globals_of_w32
166 below. This is because these variables might get set
167 to non-NULL values during dumping, but the dumped Emacs
168 cannot reuse those values, because it could be run on a
169 different version of the OS, where API addresses are
171 static BOOL g_b_init_is_windows_9x
;
172 static BOOL g_b_init_open_process_token
;
173 static BOOL g_b_init_get_token_information
;
174 static BOOL g_b_init_lookup_account_sid
;
175 static BOOL g_b_init_get_sid_identifier_authority
;
176 static BOOL g_b_init_get_sid_sub_authority
;
177 static BOOL g_b_init_get_sid_sub_authority_count
;
178 static BOOL g_b_init_get_file_security
;
179 static BOOL g_b_init_get_security_descriptor_owner
;
180 static BOOL g_b_init_get_security_descriptor_group
;
181 static BOOL g_b_init_is_valid_sid
;
182 static BOOL g_b_init_create_toolhelp32_snapshot
;
183 static BOOL g_b_init_process32_first
;
184 static BOOL g_b_init_process32_next
;
185 static BOOL g_b_init_open_thread_token
;
186 static BOOL g_b_init_impersonate_self
;
187 static BOOL g_b_init_revert_to_self
;
188 static BOOL g_b_init_get_process_memory_info
;
189 static BOOL g_b_init_get_process_working_set_size
;
190 static BOOL g_b_init_global_memory_status
;
191 static BOOL g_b_init_global_memory_status_ex
;
192 static BOOL g_b_init_get_length_sid
;
193 static BOOL g_b_init_equal_sid
;
194 static BOOL g_b_init_copy_sid
;
195 static BOOL g_b_init_get_native_system_info
;
196 static BOOL g_b_init_get_system_times
;
199 BEGIN: Wrapper functions around OpenProcessToken
200 and other functions in advapi32.dll that are only
201 supported in Windows NT / 2k / XP
203 /* ** Function pointer typedefs ** */
204 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
205 HANDLE ProcessHandle
,
207 PHANDLE TokenHandle
);
208 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
210 TOKEN_INFORMATION_CLASS TokenInformationClass
,
211 LPVOID TokenInformation
,
212 DWORD TokenInformationLength
,
213 PDWORD ReturnLength
);
214 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
215 HANDLE process_handle
,
216 LPFILETIME creation_time
,
217 LPFILETIME exit_time
,
218 LPFILETIME kernel_time
,
219 LPFILETIME user_time
);
221 GetProcessTimes_Proc get_process_times_fn
= NULL
;
224 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
225 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
227 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
228 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
230 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
231 LPCTSTR lpSystemName
,
236 LPDWORD cbDomainName
,
237 PSID_NAME_USE peUse
);
238 typedef PSID_IDENTIFIER_AUTHORITY (WINAPI
* GetSidIdentifierAuthority_Proc
) (
240 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
243 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
245 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
247 SECURITY_INFORMATION RequestedInformation
,
248 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
250 LPDWORD lpnLengthNeeded
);
251 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
252 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
254 LPBOOL lpbOwnerDefaulted
);
255 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
256 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
258 LPBOOL lpbGroupDefaulted
);
259 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
261 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
263 DWORD th32ProcessID
);
264 typedef BOOL (WINAPI
* Process32First_Proc
) (
266 LPPROCESSENTRY32 lppe
);
267 typedef BOOL (WINAPI
* Process32Next_Proc
) (
269 LPPROCESSENTRY32 lppe
);
270 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
274 PHANDLE TokenHandle
);
275 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
276 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
277 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
278 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
280 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
282 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
284 DWORD
* lpMinimumWorkingSetSize
,
285 DWORD
* lpMaximumWorkingSetSize
);
286 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
287 LPMEMORYSTATUS lpBuffer
);
288 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
289 LPMEMORY_STATUS_EX lpBuffer
);
290 typedef BOOL (WINAPI
* CopySid_Proc
) (
291 DWORD nDestinationSidLength
,
292 PSID pDestinationSid
,
294 typedef BOOL (WINAPI
* EqualSid_Proc
) (
297 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
299 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
300 LPSYSTEM_INFO lpSystemInfo
);
301 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
302 LPFILETIME lpIdleTime
,
303 LPFILETIME lpKernelTime
,
304 LPFILETIME lpUserTime
);
308 /* ** A utility function ** */
312 static BOOL s_b_ret
=0;
313 OSVERSIONINFO os_ver
;
314 if (g_b_init_is_windows_9x
== 0)
316 g_b_init_is_windows_9x
= 1;
317 ZeroMemory(&os_ver
, sizeof(OSVERSIONINFO
));
318 os_ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
319 if (GetVersionEx (&os_ver
))
321 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
327 /* Get total user and system times for get-internal-run-time.
328 Returns a list of three integers if the times are provided by the OS
329 (NT derivatives), otherwise it returns the result of current-time. */
331 w32_get_internal_run_time ()
333 if (get_process_times_fn
)
335 FILETIME create
, exit
, kernel
, user
;
336 HANDLE proc
= GetCurrentProcess();
337 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
339 LARGE_INTEGER user_int
, kernel_int
, total
;
341 user_int
.LowPart
= user
.dwLowDateTime
;
342 user_int
.HighPart
= user
.dwHighDateTime
;
343 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
344 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
345 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
346 /* FILETIME is 100 nanosecond increments, Emacs only wants
347 microsecond resolution. */
348 total
.QuadPart
/= 10;
349 microseconds
= total
.QuadPart
% 1000000;
350 total
.QuadPart
/= 1000000;
352 /* Sanity check to make sure we can represent the result. */
353 if (total
.HighPart
== 0)
355 int secs
= total
.LowPart
;
357 return list3 (make_number ((secs
>> 16) & 0xffff),
358 make_number (secs
& 0xffff),
359 make_number (microseconds
));
364 return Fcurrent_time ();
367 /* ** The wrapper functions ** */
369 BOOL WINAPI
open_process_token (
370 HANDLE ProcessHandle
,
374 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
375 HMODULE hm_advapi32
= NULL
;
376 if (is_windows_9x () == TRUE
)
380 if (g_b_init_open_process_token
== 0)
382 g_b_init_open_process_token
= 1;
383 hm_advapi32
= LoadLibrary ("Advapi32.dll");
384 s_pfn_Open_Process_Token
=
385 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
387 if (s_pfn_Open_Process_Token
== NULL
)
392 s_pfn_Open_Process_Token (
399 BOOL WINAPI
get_token_information (
401 TOKEN_INFORMATION_CLASS TokenInformationClass
,
402 LPVOID TokenInformation
,
403 DWORD TokenInformationLength
,
406 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
407 HMODULE hm_advapi32
= NULL
;
408 if (is_windows_9x () == TRUE
)
412 if (g_b_init_get_token_information
== 0)
414 g_b_init_get_token_information
= 1;
415 hm_advapi32
= LoadLibrary ("Advapi32.dll");
416 s_pfn_Get_Token_Information
=
417 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
419 if (s_pfn_Get_Token_Information
== NULL
)
424 s_pfn_Get_Token_Information (
426 TokenInformationClass
,
428 TokenInformationLength
,
433 BOOL WINAPI
lookup_account_sid (
434 LPCTSTR lpSystemName
,
439 LPDWORD cbDomainName
,
442 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
443 HMODULE hm_advapi32
= NULL
;
444 if (is_windows_9x () == TRUE
)
448 if (g_b_init_lookup_account_sid
== 0)
450 g_b_init_lookup_account_sid
= 1;
451 hm_advapi32
= LoadLibrary ("Advapi32.dll");
452 s_pfn_Lookup_Account_Sid
=
453 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
455 if (s_pfn_Lookup_Account_Sid
== NULL
)
460 s_pfn_Lookup_Account_Sid (
471 PSID_IDENTIFIER_AUTHORITY WINAPI
get_sid_identifier_authority (
474 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority
= NULL
;
475 HMODULE hm_advapi32
= NULL
;
476 if (is_windows_9x () == TRUE
)
480 if (g_b_init_get_sid_identifier_authority
== 0)
482 g_b_init_get_sid_identifier_authority
= 1;
483 hm_advapi32
= LoadLibrary ("Advapi32.dll");
484 s_pfn_Get_Sid_Identifier_Authority
=
485 (GetSidIdentifierAuthority_Proc
) GetProcAddress (
486 hm_advapi32
, "GetSidIdentifierAuthority");
488 if (s_pfn_Get_Sid_Identifier_Authority
== NULL
)
492 return (s_pfn_Get_Sid_Identifier_Authority (pSid
));
495 PDWORD WINAPI
get_sid_sub_authority (
499 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
500 static DWORD zero
= 0U;
501 HMODULE hm_advapi32
= NULL
;
502 if (is_windows_9x () == TRUE
)
506 if (g_b_init_get_sid_sub_authority
== 0)
508 g_b_init_get_sid_sub_authority
= 1;
509 hm_advapi32
= LoadLibrary ("Advapi32.dll");
510 s_pfn_Get_Sid_Sub_Authority
=
511 (GetSidSubAuthority_Proc
) GetProcAddress (
512 hm_advapi32
, "GetSidSubAuthority");
514 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
518 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
521 PUCHAR WINAPI
get_sid_sub_authority_count (
524 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
525 static UCHAR zero
= 0U;
526 HMODULE hm_advapi32
= NULL
;
527 if (is_windows_9x () == TRUE
)
531 if (g_b_init_get_sid_sub_authority_count
== 0)
533 g_b_init_get_sid_sub_authority_count
= 1;
534 hm_advapi32
= LoadLibrary ("Advapi32.dll");
535 s_pfn_Get_Sid_Sub_Authority_Count
=
536 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
537 hm_advapi32
, "GetSidSubAuthorityCount");
539 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
543 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
546 BOOL WINAPI
get_file_security (
548 SECURITY_INFORMATION RequestedInformation
,
549 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
551 LPDWORD lpnLengthNeeded
)
553 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
554 HMODULE hm_advapi32
= NULL
;
555 if (is_windows_9x () == TRUE
)
559 if (g_b_init_get_file_security
== 0)
561 g_b_init_get_file_security
= 1;
562 hm_advapi32
= LoadLibrary ("Advapi32.dll");
563 s_pfn_Get_File_Security
=
564 (GetFileSecurity_Proc
) GetProcAddress (
565 hm_advapi32
, GetFileSecurity_Name
);
567 if (s_pfn_Get_File_Security
== NULL
)
571 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
572 pSecurityDescriptor
, nLength
,
576 BOOL WINAPI
get_security_descriptor_owner (
577 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
579 LPBOOL lpbOwnerDefaulted
)
581 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
582 HMODULE hm_advapi32
= NULL
;
583 if (is_windows_9x () == TRUE
)
587 if (g_b_init_get_security_descriptor_owner
== 0)
589 g_b_init_get_security_descriptor_owner
= 1;
590 hm_advapi32
= LoadLibrary ("Advapi32.dll");
591 s_pfn_Get_Security_Descriptor_Owner
=
592 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
593 hm_advapi32
, "GetSecurityDescriptorOwner");
595 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
599 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
603 BOOL WINAPI
get_security_descriptor_group (
604 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
606 LPBOOL lpbGroupDefaulted
)
608 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
609 HMODULE hm_advapi32
= NULL
;
610 if (is_windows_9x () == TRUE
)
614 if (g_b_init_get_security_descriptor_group
== 0)
616 g_b_init_get_security_descriptor_group
= 1;
617 hm_advapi32
= LoadLibrary ("Advapi32.dll");
618 s_pfn_Get_Security_Descriptor_Group
=
619 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
620 hm_advapi32
, "GetSecurityDescriptorGroup");
622 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
626 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
630 BOOL WINAPI
is_valid_sid (
633 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
634 HMODULE hm_advapi32
= NULL
;
635 if (is_windows_9x () == TRUE
)
639 if (g_b_init_is_valid_sid
== 0)
641 g_b_init_is_valid_sid
= 1;
642 hm_advapi32
= LoadLibrary ("Advapi32.dll");
644 (IsValidSid_Proc
) GetProcAddress (
645 hm_advapi32
, "IsValidSid");
647 if (s_pfn_Is_Valid_Sid
== NULL
)
651 return (s_pfn_Is_Valid_Sid (sid
));
654 BOOL WINAPI
equal_sid (
658 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
659 HMODULE hm_advapi32
= NULL
;
660 if (is_windows_9x () == TRUE
)
664 if (g_b_init_equal_sid
== 0)
666 g_b_init_equal_sid
= 1;
667 hm_advapi32
= LoadLibrary ("Advapi32.dll");
669 (EqualSid_Proc
) GetProcAddress (
670 hm_advapi32
, "EqualSid");
672 if (s_pfn_Equal_Sid
== NULL
)
676 return (s_pfn_Equal_Sid (sid1
, sid2
));
679 DWORD WINAPI
get_length_sid (
682 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
683 HMODULE hm_advapi32
= NULL
;
684 if (is_windows_9x () == TRUE
)
688 if (g_b_init_get_length_sid
== 0)
690 g_b_init_get_length_sid
= 1;
691 hm_advapi32
= LoadLibrary ("Advapi32.dll");
692 s_pfn_Get_Length_Sid
=
693 (GetLengthSid_Proc
) GetProcAddress (
694 hm_advapi32
, "GetLengthSid");
696 if (s_pfn_Get_Length_Sid
== NULL
)
700 return (s_pfn_Get_Length_Sid (sid
));
703 BOOL WINAPI
copy_sid (
708 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
709 HMODULE hm_advapi32
= NULL
;
710 if (is_windows_9x () == TRUE
)
714 if (g_b_init_copy_sid
== 0)
716 g_b_init_copy_sid
= 1;
717 hm_advapi32
= LoadLibrary ("Advapi32.dll");
719 (CopySid_Proc
) GetProcAddress (
720 hm_advapi32
, "CopySid");
722 if (s_pfn_Copy_Sid
== NULL
)
726 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
730 END: Wrapper functions around OpenProcessToken
731 and other functions in advapi32.dll that are only
732 supported in Windows NT / 2k / XP
735 void WINAPI
get_native_system_info (
736 LPSYSTEM_INFO lpSystemInfo
)
738 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
739 if (is_windows_9x () != TRUE
)
741 if (g_b_init_get_native_system_info
== 0)
743 g_b_init_get_native_system_info
= 1;
744 s_pfn_Get_Native_System_Info
=
745 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
746 "GetNativeSystemInfo");
748 if (s_pfn_Get_Native_System_Info
!= NULL
)
749 s_pfn_Get_Native_System_Info (lpSystemInfo
);
752 lpSystemInfo
->dwNumberOfProcessors
= -1;
755 BOOL WINAPI
get_system_times(
756 LPFILETIME lpIdleTime
,
757 LPFILETIME lpKernelTime
,
758 LPFILETIME lpUserTime
)
760 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
761 if (is_windows_9x () == TRUE
)
765 if (g_b_init_get_system_times
== 0)
767 g_b_init_get_system_times
= 1;
768 s_pfn_Get_System_times
=
769 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
772 if (s_pfn_Get_System_times
== NULL
)
774 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
777 /* Equivalent of strerror for W32 error codes. */
779 w32_strerror (int error_no
)
781 static char buf
[500];
784 error_no
= GetLastError ();
787 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
789 0, /* choose most suitable language */
790 buf
, sizeof (buf
), NULL
))
791 sprintf (buf
, "w32 error %u", error_no
);
795 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
796 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
798 This is called from alloc.c:valid_pointer_p. */
800 w32_valid_pointer_p (void *p
, int size
)
803 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
807 unsigned char *buf
= alloca (size
);
808 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
817 static char startup_dir
[MAXPATHLEN
];
819 /* Get the current working directory. */
824 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
828 /* Emacs doesn't actually change directory itself, and we want to
829 force our real wd to be where emacs.exe is to avoid unnecessary
830 conflicts when trying to rename or delete directories. */
831 strcpy (dir
, startup_dir
);
837 /* Emulate gethostname. */
839 gethostname (char *buffer
, int size
)
841 /* NT only allows small host names, so the buffer is
842 certainly large enough. */
843 return !GetComputerName (buffer
, &size
);
845 #endif /* HAVE_SOCKETS */
847 /* Emulate getloadavg. */
856 /* Number of processors on this machine. */
857 static unsigned num_of_processors
;
859 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
860 static struct load_sample samples
[16*60];
861 static int first_idx
= -1, last_idx
= -1;
862 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
867 int next_idx
= from
+ 1;
869 if (next_idx
>= max_idx
)
878 int prev_idx
= from
- 1;
881 prev_idx
= max_idx
- 1;
887 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
890 FILETIME ft_idle
, ft_user
, ft_kernel
;
892 /* Initialize the number of processors on this machine. */
893 if (num_of_processors
<= 0)
895 get_native_system_info (&sysinfo
);
896 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
897 if (num_of_processors
<= 0)
899 GetSystemInfo (&sysinfo
);
900 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
902 if (num_of_processors
<= 0)
903 num_of_processors
= 1;
906 /* TODO: Take into account threads that are ready to run, by
907 sampling the "\System\Processor Queue Length" performance
908 counter. The code below accounts only for threads that are
911 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
913 ULARGE_INTEGER uidle
, ukernel
, uuser
;
915 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
916 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
917 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
918 *idle
= uidle
.QuadPart
;
919 *kernel
= ukernel
.QuadPart
;
920 *user
= uuser
.QuadPart
;
930 /* Produce the load average for a given time interval, using the
931 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
932 1-minute, 5-minute, or 15-minute average, respectively. */
936 double retval
= -1.0;
939 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
940 time_t now
= samples
[last_idx
].sample_time
;
942 if (first_idx
!= last_idx
)
944 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
946 tdiff
= difftime (now
, samples
[idx
].sample_time
);
947 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
950 samples
[last_idx
].kernel
+ samples
[last_idx
].user
951 - (samples
[idx
].kernel
+ samples
[idx
].user
);
952 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
954 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
957 if (idx
== first_idx
)
966 getloadavg (double loadavg
[], int nelem
)
969 ULONGLONG idle
, kernel
, user
;
970 time_t now
= time (NULL
);
972 /* Store another sample. We ignore samples that are less than 1 sec
974 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
976 sample_system_load (&idle
, &kernel
, &user
);
977 last_idx
= buf_next (last_idx
);
978 samples
[last_idx
].sample_time
= now
;
979 samples
[last_idx
].idle
= idle
;
980 samples
[last_idx
].kernel
= kernel
;
981 samples
[last_idx
].user
= user
;
982 /* If the buffer has more that 15 min worth of samples, discard
985 first_idx
= last_idx
;
986 while (first_idx
!= last_idx
987 && (difftime (now
, samples
[first_idx
].sample_time
)
988 >= 15.0*60 + 2*DBL_EPSILON
*now
))
989 first_idx
= buf_next (first_idx
);
992 for (elem
= 0; elem
< nelem
; elem
++)
994 double avg
= getavg (elem
);
1004 /* Emulate getpwuid, getpwnam and others. */
1006 #define PASSWD_FIELD_SIZE 256
1008 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1009 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1010 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1011 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
1012 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
1014 static struct passwd dflt_passwd
=
1026 static char dflt_group_name
[GNLEN
+1];
1028 static struct group dflt_group
=
1030 /* When group information is not available, we return this as the
1031 group for all files. */
1039 return dflt_passwd
.pw_uid
;
1045 /* I could imagine arguing for checking to see whether the user is
1046 in the Administrators group and returning a UID of 0 for that
1047 case, but I don't know how wise that would be in the long run. */
1054 return dflt_passwd
.pw_gid
;
1064 getpwuid (unsigned uid
)
1066 if (uid
== dflt_passwd
.pw_uid
)
1067 return &dflt_passwd
;
1072 getgrgid (gid_t gid
)
1078 getpwnam (char *name
)
1082 pw
= getpwuid (getuid ());
1086 if (xstrcasecmp (name
, pw
->pw_name
))
1095 /* Find the user's real name by opening the process token and
1096 looking up the name associated with the user-sid in that token.
1098 Use the relative portion of the identifier authority value from
1099 the user-sid as the user id value (same for group id using the
1100 primary group sid from the process token). */
1102 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1103 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1104 DWORD glength
= sizeof (gname
);
1105 HANDLE token
= NULL
;
1106 SID_NAME_USE user_type
;
1107 unsigned char *buf
= NULL
;
1109 TOKEN_USER user_token
;
1110 TOKEN_PRIMARY_GROUP group_token
;
1113 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1116 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1117 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1119 buf
= xmalloc (blen
);
1120 result
= get_token_information (token
, TokenUser
,
1121 (LPVOID
)buf
, blen
, &needed
);
1124 memcpy (&user_token
, buf
, sizeof (user_token
));
1125 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1127 domain
, &dlength
, &user_type
);
1135 strcpy (dflt_passwd
.pw_name
, uname
);
1136 /* Determine a reasonable uid value. */
1137 if (xstrcasecmp ("administrator", uname
) == 0)
1139 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1140 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1144 /* Use the last sub-authority value of the RID, the relative
1145 portion of the SID, as user/group ID. */
1146 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1148 /* Get group id and name. */
1149 result
= get_token_information (token
, TokenPrimaryGroup
,
1150 (LPVOID
)buf
, blen
, &needed
);
1151 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1153 buf
= xrealloc (buf
, blen
= needed
);
1154 result
= get_token_information (token
, TokenPrimaryGroup
,
1155 (LPVOID
)buf
, blen
, &needed
);
1159 memcpy (&group_token
, buf
, sizeof (group_token
));
1160 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1161 dlength
= sizeof (domain
);
1162 /* If we can get at the real Primary Group name, use that.
1163 Otherwise, the default group name was already set to
1164 "None" in globals_of_w32. */
1165 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1166 gname
, &glength
, NULL
, &dlength
,
1168 strcpy (dflt_group_name
, gname
);
1171 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1174 /* If security calls are not supported (presumably because we
1175 are running under Windows 9X), fallback to this: */
1176 else if (GetUserName (uname
, &ulength
))
1178 strcpy (dflt_passwd
.pw_name
, uname
);
1179 if (xstrcasecmp ("administrator", uname
) == 0)
1180 dflt_passwd
.pw_uid
= 0;
1182 dflt_passwd
.pw_uid
= 123;
1183 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1187 strcpy (dflt_passwd
.pw_name
, "unknown");
1188 dflt_passwd
.pw_uid
= 123;
1189 dflt_passwd
.pw_gid
= 123;
1191 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1193 /* Ensure HOME and SHELL are defined. */
1194 if (getenv ("HOME") == NULL
)
1196 if (getenv ("SHELL") == NULL
)
1199 /* Set dir and shell from environment variables. */
1200 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1201 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1205 CloseHandle (token
);
1211 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1212 return ((rand () << 15) | rand ());
1222 /* Normalize filename by converting all path separators to
1223 the specified separator. Also conditionally convert upper
1224 case path name components to lower case. */
1227 normalize_filename (fp
, path_sep
)
1234 /* Always lower-case drive letters a-z, even if the filesystem
1235 preserves case in filenames.
1236 This is so filenames can be compared by string comparison
1237 functions that are case-sensitive. Even case-preserving filesystems
1238 do not distinguish case in drive letters. */
1239 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1245 if (NILP (Vw32_downcase_file_names
))
1249 if (*fp
== '/' || *fp
== '\\')
1256 sep
= path_sep
; /* convert to this path separator */
1257 elem
= fp
; /* start of current path element */
1260 if (*fp
>= 'a' && *fp
<= 'z')
1261 elem
= 0; /* don't convert this element */
1263 if (*fp
== 0 || *fp
== ':')
1265 sep
= *fp
; /* restore current separator (or 0) */
1266 *fp
= '/'; /* after conversion of this element */
1269 if (*fp
== '/' || *fp
== '\\')
1271 if (elem
&& elem
!= fp
)
1273 *fp
= 0; /* temporary end of string */
1274 _strlwr (elem
); /* while we convert to lower case */
1276 *fp
= sep
; /* convert (or restore) path separator */
1277 elem
= fp
+ 1; /* next element starts after separator */
1283 /* Destructively turn backslashes into slashes. */
1285 dostounix_filename (p
)
1288 normalize_filename (p
, '/');
1291 /* Destructively turn slashes into backslashes. */
1293 unixtodos_filename (p
)
1296 normalize_filename (p
, '\\');
1299 /* Remove all CR's that are followed by a LF.
1300 (From msdos.c...probably should figure out a way to share it,
1301 although this code isn't going to ever change.) */
1305 register unsigned char *buf
;
1307 unsigned char *np
= buf
;
1308 unsigned char *startp
= buf
;
1309 unsigned char *endp
= buf
+ n
;
1313 while (buf
< endp
- 1)
1317 if (*(++buf
) != 0x0a)
1328 /* Parse the root part of file name, if present. Return length and
1329 optionally store pointer to char after root. */
1331 parse_root (char * name
, char ** pPath
)
1333 char * start
= name
;
1338 /* find the root name of the volume if given */
1339 if (isalpha (name
[0]) && name
[1] == ':')
1341 /* skip past drive specifier */
1343 if (IS_DIRECTORY_SEP (name
[0]))
1346 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1352 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1357 if (IS_DIRECTORY_SEP (name
[0]))
1364 return name
- start
;
1367 /* Get long base name for name; name is assumed to be absolute. */
1369 get_long_basename (char * name
, char * buf
, int size
)
1371 WIN32_FIND_DATA find_data
;
1375 /* must be valid filename, no wild cards or other invalid characters */
1376 if (_mbspbrk (name
, "*?|<>\""))
1379 dir_handle
= FindFirstFile (name
, &find_data
);
1380 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1382 if ((len
= strlen (find_data
.cFileName
)) < size
)
1383 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1386 FindClose (dir_handle
);
1391 /* Get long name for file, if possible (assumed to be absolute). */
1393 w32_get_long_filename (char * name
, char * buf
, int size
)
1398 char full
[ MAX_PATH
];
1401 len
= strlen (name
);
1402 if (len
>= MAX_PATH
)
1405 /* Use local copy for destructive modification. */
1406 memcpy (full
, name
, len
+1);
1407 unixtodos_filename (full
);
1409 /* Copy root part verbatim. */
1410 len
= parse_root (full
, &p
);
1411 memcpy (o
, full
, len
);
1416 while (p
!= NULL
&& *p
)
1419 p
= strchr (q
, '\\');
1421 len
= get_long_basename (full
, o
, size
);
1444 is_unc_volume (const char *filename
)
1446 const char *ptr
= filename
;
1448 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1451 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1457 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1460 sigsetmask (int signal_mask
)
1478 sigunblock (int sig
)
1484 setpgrp (int pid
, int gid
)
1495 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1498 w32_get_resource (key
, lpdwtype
)
1503 HKEY hrootkey
= NULL
;
1506 /* Check both the current user and the local machine to see if
1507 we have any resources. */
1509 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1513 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1514 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1515 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1517 RegCloseKey (hrootkey
);
1523 RegCloseKey (hrootkey
);
1526 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1530 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1531 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1532 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1534 RegCloseKey (hrootkey
);
1540 RegCloseKey (hrootkey
);
1546 char *get_emacs_configuration (void);
1547 extern Lisp_Object Vsystem_configuration
;
1550 init_environment (char ** argv
)
1552 static const char * const tempdirs
[] = {
1553 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1558 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1560 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1561 temporary files and assume "/tmp" if $TMPDIR is unset, which
1562 will break on DOS/Windows. Refuse to work if we cannot find
1563 a directory, not even "c:/", usable for that purpose. */
1564 for (i
= 0; i
< imax
; i
++)
1566 const char *tmp
= tempdirs
[i
];
1569 tmp
= getenv (tmp
+ 1);
1570 /* Note that `access' can lie to us if the directory resides on a
1571 read-only filesystem, like CD-ROM or a write-protected floppy.
1572 The only way to be really sure is to actually create a file and
1573 see if it succeeds. But I think that's too much to ask. */
1574 if (tmp
&& _access (tmp
, D_OK
) == 0)
1576 char * var
= alloca (strlen (tmp
) + 8);
1577 sprintf (var
, "TMPDIR=%s", tmp
);
1578 _putenv (strdup (var
));
1585 Fcons (build_string ("no usable temporary directories found!!"),
1587 "While setting TMPDIR: ");
1589 /* Check for environment variables and use registry settings if they
1590 don't exist. Fallback on default values where applicable. */
1595 char locale_name
[32];
1596 struct stat ignored
;
1597 char default_home
[MAX_PATH
];
1599 static const struct env_entry
1606 {"PRELOAD_WINSOCK", NULL
},
1607 {"emacs_dir", "C:/emacs"},
1608 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1609 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1610 {"EMACSDATA", "%emacs_dir%/etc"},
1611 {"EMACSPATH", "%emacs_dir%/bin"},
1612 /* We no longer set INFOPATH because Info-default-directory-list
1614 /* {"INFOPATH", "%emacs_dir%/info"}, */
1615 {"EMACSDOC", "%emacs_dir%/etc"},
1620 #define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1622 /* We need to copy dflt_envvars[] and work on the copy because we
1623 don't want the dumped Emacs to inherit the values of
1624 environment variables we saw during dumping (which could be on
1625 a different system). The defaults above must be left intact. */
1626 struct env_entry env_vars
[N_ENV_VARS
];
1628 for (i
= 0; i
< N_ENV_VARS
; i
++)
1629 env_vars
[i
] = dflt_envvars
[i
];
1631 /* For backwards compatibility, check if a .emacs file exists in C:/
1632 If not, then we can try to default to the appdata directory under the
1633 user's profile, which is more likely to be writable. */
1634 if (stat ("C:/.emacs", &ignored
) < 0)
1636 HRESULT profile_result
;
1637 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1638 of Windows 95 and NT4 that have not been updated to include
1640 ShGetFolderPath_fn get_folder_path
;
1641 get_folder_path
= (ShGetFolderPath_fn
)
1642 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1644 if (get_folder_path
!= NULL
)
1646 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1649 /* If we can't get the appdata dir, revert to old behavior. */
1650 if (profile_result
== S_OK
)
1651 env_vars
[0].def_value
= default_home
;
1655 /* Get default locale info and use it for LANG. */
1656 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1657 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1658 locale_name
, sizeof (locale_name
)))
1660 for (i
= 0; i
< N_ENV_VARS
; i
++)
1662 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1664 env_vars
[i
].def_value
= locale_name
;
1670 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1672 /* Treat emacs_dir specially: set it unconditionally based on our
1673 location, if it appears that we are running from the bin subdir
1674 of a standard installation. */
1677 char modname
[MAX_PATH
];
1679 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1681 if ((p
= strrchr (modname
, '\\')) == NULL
)
1685 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1687 char buf
[SET_ENV_BUF_SIZE
];
1690 for (p
= modname
; *p
; p
++)
1691 if (*p
== '\\') *p
= '/';
1693 _snprintf (buf
, sizeof(buf
)-1, "emacs_dir=%s", modname
);
1694 _putenv (strdup (buf
));
1696 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1698 /* FIXME: should use substring of get_emacs_configuration ().
1699 But I don't think the Windows build supports alpha, mips etc
1700 anymore, so have taken the easy option for now. */
1701 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1704 p
= strrchr (modname
, '\\');
1708 p
= strrchr (modname
, '\\');
1709 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1711 char buf
[SET_ENV_BUF_SIZE
];
1714 for (p
= modname
; *p
; p
++)
1715 if (*p
== '\\') *p
= '/';
1717 _snprintf (buf
, sizeof(buf
)-1, "emacs_dir=%s", modname
);
1718 _putenv (strdup (buf
));
1724 for (i
= 0; i
< N_ENV_VARS
; i
++)
1726 if (!getenv (env_vars
[i
].name
))
1730 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1731 /* Also ignore empty environment variables. */
1735 lpval
= env_vars
[i
].def_value
;
1736 dwType
= REG_EXPAND_SZ
;
1742 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1744 if (dwType
== REG_EXPAND_SZ
)
1745 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof(buf1
));
1746 else if (dwType
== REG_SZ
)
1747 strcpy (buf1
, lpval
);
1748 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1750 _snprintf (buf2
, sizeof(buf2
)-1, "%s=%s", env_vars
[i
].name
,
1752 _putenv (strdup (buf2
));
1762 /* Rebuild system configuration to reflect invoking system. */
1763 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1765 /* Another special case: on NT, the PATH variable is actually named
1766 "Path" although cmd.exe (perhaps NT itself) arranges for
1767 environment variable lookup and setting to be case insensitive.
1768 However, Emacs assumes a fully case sensitive environment, so we
1769 need to change "Path" to "PATH" to match the expectations of
1770 various elisp packages. We do this by the sneaky method of
1771 modifying the string in the C runtime environ entry.
1773 The same applies to COMSPEC. */
1777 for (envp
= environ
; *envp
; envp
++)
1778 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1779 memcpy (*envp
, "PATH=", 5);
1780 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1781 memcpy (*envp
, "COMSPEC=", 8);
1784 /* Remember the initial working directory for getwd, then make the
1785 real wd be the location of emacs.exe to avoid conflicts when
1786 renaming or deleting directories. (We also don't call chdir when
1787 running subprocesses for the same reason.) */
1788 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1793 static char modname
[MAX_PATH
];
1795 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1797 if ((p
= strrchr (modname
, '\\')) == NULL
)
1801 SetCurrentDirectory (modname
);
1803 /* Ensure argv[0] has the full path to Emacs. */
1808 /* Determine if there is a middle mouse button, to allow parse_button
1809 to decide whether right mouse events should be mouse-2 or
1811 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1817 emacs_root_dir (void)
1819 static char root_dir
[FILENAME_MAX
];
1822 p
= getenv ("emacs_dir");
1825 strcpy (root_dir
, p
);
1826 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1827 dostounix_filename (root_dir
);
1831 /* We don't have scripts to automatically determine the system configuration
1832 for Emacs before it's compiled, and we don't want to have to make the
1833 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1837 get_emacs_configuration (void)
1839 char *arch
, *oem
, *os
;
1841 static char configuration_buffer
[32];
1843 /* Determine the processor type. */
1844 switch (get_processor_type ())
1847 #ifdef PROCESSOR_INTEL_386
1848 case PROCESSOR_INTEL_386
:
1849 case PROCESSOR_INTEL_486
:
1850 case PROCESSOR_INTEL_PENTIUM
:
1855 #ifdef PROCESSOR_MIPS_R2000
1856 case PROCESSOR_MIPS_R2000
:
1857 case PROCESSOR_MIPS_R3000
:
1858 case PROCESSOR_MIPS_R4000
:
1863 #ifdef PROCESSOR_ALPHA_21064
1864 case PROCESSOR_ALPHA_21064
:
1874 /* Use the OEM field to reflect the compiler/library combination. */
1876 #define COMPILER_NAME "msvc"
1879 #define COMPILER_NAME "mingw"
1881 #define COMPILER_NAME "unknown"
1884 oem
= COMPILER_NAME
;
1886 switch (osinfo_cache
.dwPlatformId
) {
1887 case VER_PLATFORM_WIN32_NT
:
1889 build_num
= osinfo_cache
.dwBuildNumber
;
1891 case VER_PLATFORM_WIN32_WINDOWS
:
1892 if (osinfo_cache
.dwMinorVersion
== 0) {
1897 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1899 case VER_PLATFORM_WIN32s
:
1900 /* Not supported, should not happen. */
1902 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1910 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1911 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1912 get_w32_major_version (), get_w32_minor_version (), build_num
);
1914 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1917 return configuration_buffer
;
1921 get_emacs_configuration_options (void)
1923 static char options_buffer
[256];
1925 /* Work out the effective configure options for this build. */
1927 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1930 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1932 #define COMPILER_VERSION ""
1936 sprintf (options_buffer
, COMPILER_VERSION
);
1938 strcat (options_buffer
, " --no-opt");
1941 strcat (options_buffer
, " --cflags");
1942 strcat (options_buffer
, USER_CFLAGS
);
1945 strcat (options_buffer
, " --ldflags");
1946 strcat (options_buffer
, USER_LDFLAGS
);
1948 return options_buffer
;
1952 #include <sys/timeb.h>
1954 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1956 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1961 tv
->tv_sec
= tb
.time
;
1962 tv
->tv_usec
= tb
.millitm
* 1000L;
1965 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1966 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1970 /* ------------------------------------------------------------------------- */
1971 /* IO support and wrapper functions for W32 API. */
1972 /* ------------------------------------------------------------------------- */
1974 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1975 on network directories, so we handle that case here.
1976 (Ulrich Leodolter, 1/11/95). */
1978 sys_ctime (const time_t *t
)
1980 char *str
= (char *) ctime (t
);
1981 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1984 /* Emulate sleep...we could have done this with a define, but that
1985 would necessitate including windows.h in the files that used it.
1986 This is much easier. */
1988 sys_sleep (int seconds
)
1990 Sleep (seconds
* 1000);
1993 /* Internal MSVC functions for low-level descriptor munging */
1994 extern int __cdecl
_set_osfhnd (int fd
, long h
);
1995 extern int __cdecl
_free_osfhnd (int fd
);
1997 /* parallel array of private info on file handles */
1998 filedesc fd_info
[ MAXDESC
];
2000 typedef struct volume_info_data
{
2001 struct volume_info_data
* next
;
2003 /* time when info was obtained */
2006 /* actual volume info */
2015 /* Global referenced by various functions. */
2016 static volume_info_data volume_info
;
2018 /* Vector to indicate which drives are local and fixed (for which cached
2019 data never expires). */
2020 static BOOL fixed_drives
[26];
2022 /* Consider cached volume information to be stale if older than 10s,
2023 at least for non-local drives. Info for fixed drives is never stale. */
2024 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2025 #define VOLINFO_STILL_VALID( root_dir, info ) \
2026 ( ( isalpha (root_dir[0]) && \
2027 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2028 || GetTickCount () - info->timestamp < 10000 )
2030 /* Cache support functions. */
2032 /* Simple linked list with linear search is sufficient. */
2033 static volume_info_data
*volume_cache
= NULL
;
2035 static volume_info_data
*
2036 lookup_volume_info (char * root_dir
)
2038 volume_info_data
* info
;
2040 for (info
= volume_cache
; info
; info
= info
->next
)
2041 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2047 add_volume_info (char * root_dir
, volume_info_data
* info
)
2049 info
->root_dir
= xstrdup (root_dir
);
2050 info
->next
= volume_cache
;
2051 volume_cache
= info
;
2055 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2056 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2057 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2059 GetCachedVolumeInformation (char * root_dir
)
2061 volume_info_data
* info
;
2062 char default_root
[ MAX_PATH
];
2064 /* NULL for root_dir means use root from current directory. */
2065 if (root_dir
== NULL
)
2067 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2069 parse_root (default_root
, &root_dir
);
2071 root_dir
= default_root
;
2074 /* Local fixed drives can be cached permanently. Removable drives
2075 cannot be cached permanently, since the volume name and serial
2076 number (if nothing else) can change. Remote drives should be
2077 treated as if they are removable, since there is no sure way to
2078 tell whether they are or not. Also, the UNC association of drive
2079 letters mapped to remote volumes can be changed at any time (even
2080 by other processes) without notice.
2082 As a compromise, so we can benefit from caching info for remote
2083 volumes, we use a simple expiry mechanism to invalidate cache
2084 entries that are more than ten seconds old. */
2087 /* No point doing this, because WNetGetConnection is even slower than
2088 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2089 GetDriveType is about the only call of this type which does not
2090 involve network access, and so is extremely quick). */
2092 /* Map drive letter to UNC if remote. */
2093 if ( isalpha( root_dir
[0] ) && !fixed
[ DRIVE_INDEX( root_dir
[0] ) ] )
2095 char remote_name
[ 256 ];
2096 char drive
[3] = { root_dir
[0], ':' };
2098 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2100 /* do something */ ;
2104 info
= lookup_volume_info (root_dir
);
2106 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2114 /* Info is not cached, or is stale. */
2115 if (!GetVolumeInformation (root_dir
,
2116 name
, sizeof (name
),
2120 type
, sizeof (type
)))
2123 /* Cache the volume information for future use, overwriting existing
2124 entry if present. */
2127 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2128 add_volume_info (root_dir
, info
);
2136 info
->name
= xstrdup (name
);
2137 info
->serialnum
= serialnum
;
2138 info
->maxcomp
= maxcomp
;
2139 info
->flags
= flags
;
2140 info
->type
= xstrdup (type
);
2141 info
->timestamp
= GetTickCount ();
2147 /* Get information on the volume where name is held; set path pointer to
2148 start of pathname in name (past UNC header\volume header if present). */
2150 get_volume_info (const char * name
, const char ** pPath
)
2152 char temp
[MAX_PATH
];
2153 char *rootname
= NULL
; /* default to current volume */
2154 volume_info_data
* info
;
2159 /* find the root name of the volume if given */
2160 if (isalpha (name
[0]) && name
[1] == ':')
2168 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2175 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2188 info
= GetCachedVolumeInformation (rootname
);
2191 /* Set global referenced by other functions. */
2192 volume_info
= *info
;
2198 /* Determine if volume is FAT format (ie. only supports short 8.3
2199 names); also set path pointer to start of pathname in name. */
2201 is_fat_volume (const char * name
, const char ** pPath
)
2203 if (get_volume_info (name
, pPath
))
2204 return (volume_info
.maxcomp
== 12);
2208 /* Map filename to a valid 8.3 name if necessary. */
2210 map_w32_filename (const char * name
, const char ** pPath
)
2212 static char shortname
[MAX_PATH
];
2213 char * str
= shortname
;
2216 const char * save_name
= name
;
2218 if (strlen (name
) >= MAX_PATH
)
2220 /* Return a filename which will cause callers to fail. */
2221 strcpy (shortname
, "?");
2225 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2227 register int left
= 8; /* maximum number of chars in part */
2228 register int extn
= 0; /* extension added? */
2229 register int dots
= 2; /* maximum number of dots allowed */
2232 *str
++ = *name
++; /* skip past UNC header */
2234 while ((c
= *name
++))
2241 extn
= 0; /* reset extension flags */
2242 dots
= 2; /* max 2 dots */
2243 left
= 8; /* max length 8 for main part */
2247 extn
= 0; /* reset extension flags */
2248 dots
= 2; /* max 2 dots */
2249 left
= 8; /* max length 8 for main part */
2254 /* Convert path components of the form .xxx to _xxx,
2255 but leave . and .. as they are. This allows .emacs
2256 to be read as _emacs, for example. */
2260 IS_DIRECTORY_SEP (*name
))
2275 extn
= 1; /* we've got an extension */
2276 left
= 3; /* 3 chars in extension */
2280 /* any embedded dots after the first are converted to _ */
2285 case '#': /* don't lose these, they're important */
2287 str
[-1] = c
; /* replace last character of part */
2292 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2294 dots
= 0; /* started a path component */
2303 strcpy (shortname
, name
);
2304 unixtodos_filename (shortname
);
2308 *pPath
= shortname
+ (path
- save_name
);
2314 is_exec (const char * name
)
2316 char * p
= strrchr (name
, '.');
2319 && (xstrcasecmp (p
, ".exe") == 0 ||
2320 xstrcasecmp (p
, ".com") == 0 ||
2321 xstrcasecmp (p
, ".bat") == 0 ||
2322 xstrcasecmp (p
, ".cmd") == 0));
2325 /* Emulate the Unix directory procedures opendir, closedir,
2326 and readdir. We can't use the procedures supplied in sysdep.c,
2327 so we provide them here. */
2329 struct direct dir_static
; /* simulated directory contents */
2330 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2331 static int dir_is_fat
;
2332 static char dir_pathname
[MAXPATHLEN
+1];
2333 static WIN32_FIND_DATA dir_find_data
;
2335 /* Support shares on a network resource as subdirectories of a read-only
2337 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2338 HANDLE
open_unc_volume (const char *);
2339 char *read_unc_volume (HANDLE
, char *, int);
2340 void close_unc_volume (HANDLE
);
2343 opendir (char *filename
)
2347 /* Opening is done by FindFirstFile. However, a read is inherent to
2348 this operation, so we defer the open until read time. */
2350 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2352 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2355 if (is_unc_volume (filename
))
2357 wnet_enum_handle
= open_unc_volume (filename
);
2358 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2362 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2369 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2370 dir_pathname
[MAXPATHLEN
] = '\0';
2371 dir_is_fat
= is_fat_volume (filename
, NULL
);
2377 closedir (DIR *dirp
)
2379 /* If we have a find-handle open, close it. */
2380 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2382 FindClose (dir_find_handle
);
2383 dir_find_handle
= INVALID_HANDLE_VALUE
;
2385 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2387 close_unc_volume (wnet_enum_handle
);
2388 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2390 xfree ((char *) dirp
);
2396 int downcase
= !NILP (Vw32_downcase_file_names
);
2398 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2400 if (!read_unc_volume (wnet_enum_handle
,
2401 dir_find_data
.cFileName
,
2405 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2406 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2408 char filename
[MAXNAMLEN
+ 3];
2411 strcpy (filename
, dir_pathname
);
2412 ln
= strlen (filename
) - 1;
2413 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2414 strcat (filename
, "\\");
2415 strcat (filename
, "*");
2417 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2419 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2424 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2428 /* Emacs never uses this value, so don't bother making it match
2429 value returned by stat(). */
2430 dir_static
.d_ino
= 1;
2432 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2434 /* If the file name in cFileName[] includes `?' characters, it means
2435 the original file name used characters that cannot be represented
2436 by the current ANSI codepage. To avoid total lossage, retrieve
2437 the short 8+3 alias of the long file name. */
2438 if (_mbspbrk (dir_static
.d_name
, "?"))
2440 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2441 downcase
= 1; /* 8+3 aliases are returned in all caps */
2443 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2444 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2445 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2447 /* If the file name in cFileName[] includes `?' characters, it means
2448 the original file name used characters that cannot be represented
2449 by the current ANSI codepage. To avoid total lossage, retrieve
2450 the short 8+3 alias of the long file name. */
2451 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2453 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2454 /* 8+3 aliases are returned in all caps, which could break
2455 various alists that look at filenames' extensions. */
2459 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2460 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2462 _strlwr (dir_static
.d_name
);
2466 for (p
= dir_static
.d_name
; *p
; p
++)
2467 if (*p
>= 'a' && *p
<= 'z')
2470 _strlwr (dir_static
.d_name
);
2477 open_unc_volume (const char *path
)
2483 nr
.dwScope
= RESOURCE_GLOBALNET
;
2484 nr
.dwType
= RESOURCETYPE_DISK
;
2485 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2486 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2487 nr
.lpLocalName
= NULL
;
2488 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2489 nr
.lpComment
= NULL
;
2490 nr
.lpProvider
= NULL
;
2492 result
= WNetOpenEnum(RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2493 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2495 if (result
== NO_ERROR
)
2498 return INVALID_HANDLE_VALUE
;
2502 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2506 DWORD bufsize
= 512;
2511 buffer
= alloca (bufsize
);
2512 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2513 if (result
!= NO_ERROR
)
2516 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2517 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2519 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2522 strncpy (readbuf
, ptr
, size
);
2527 close_unc_volume (HANDLE henum
)
2529 if (henum
!= INVALID_HANDLE_VALUE
)
2530 WNetCloseEnum (henum
);
2534 unc_volume_file_attributes (const char *path
)
2539 henum
= open_unc_volume (path
);
2540 if (henum
== INVALID_HANDLE_VALUE
)
2543 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2545 close_unc_volume (henum
);
2550 /* Ensure a network connection is authenticated. */
2552 logon_network_drive (const char *path
)
2554 NETRESOURCE resource
;
2555 char share
[MAX_PATH
];
2560 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2561 drvtype
= DRIVE_REMOTE
;
2562 else if (path
[0] == '\0' || path
[1] != ':')
2563 drvtype
= GetDriveType (NULL
);
2570 drvtype
= GetDriveType (drive
);
2573 /* Only logon to networked drives. */
2574 if (drvtype
!= DRIVE_REMOTE
)
2578 strncpy (share
, path
, MAX_PATH
);
2579 /* Truncate to just server and share name. */
2580 for (i
= 2; i
< MAX_PATH
; i
++)
2582 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2589 resource
.dwType
= RESOURCETYPE_DISK
;
2590 resource
.lpLocalName
= NULL
;
2591 resource
.lpRemoteName
= share
;
2592 resource
.lpProvider
= NULL
;
2594 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2597 /* Shadow some MSVC runtime functions to map requests for long filenames
2598 to reasonable short names if necessary. This was originally added to
2599 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2603 sys_access (const char * path
, int mode
)
2607 /* MSVC implementation doesn't recognize D_OK. */
2608 path
= map_w32_filename (path
, NULL
);
2609 if (is_unc_volume (path
))
2611 attributes
= unc_volume_file_attributes (path
);
2612 if (attributes
== -1) {
2617 else if ((attributes
= GetFileAttributes (path
)) == -1)
2619 /* Should try mapping GetLastError to errno; for now just indicate
2620 that path doesn't exist. */
2624 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2629 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2634 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2643 sys_chdir (const char * path
)
2645 return _chdir (map_w32_filename (path
, NULL
));
2649 sys_chmod (const char * path
, int mode
)
2651 return _chmod (map_w32_filename (path
, NULL
), mode
);
2655 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2657 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2663 sys_creat (const char * path
, int mode
)
2665 return _creat (map_w32_filename (path
, NULL
), mode
);
2669 sys_fopen(const char * path
, const char * mode
)
2673 const char * mode_save
= mode
;
2675 /* Force all file handles to be non-inheritable. This is necessary to
2676 ensure child processes don't unwittingly inherit handles that might
2677 prevent future file access. */
2681 else if (mode
[0] == 'w' || mode
[0] == 'a')
2682 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2686 /* Only do simplistic option parsing. */
2690 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2693 else if (mode
[0] == 'b')
2698 else if (mode
[0] == 't')
2705 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2709 return _fdopen (fd
, mode_save
);
2712 /* This only works on NTFS volumes, but is useful to have. */
2714 sys_link (const char * old
, const char * new)
2718 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2720 if (old
== NULL
|| new == NULL
)
2726 strcpy (oldname
, map_w32_filename (old
, NULL
));
2727 strcpy (newname
, map_w32_filename (new, NULL
));
2729 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2730 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2731 if (fileh
!= INVALID_HANDLE_VALUE
)
2735 /* Confusingly, the "alternate" stream name field does not apply
2736 when restoring a hard link, and instead contains the actual
2737 stream data for the link (ie. the name of the link to create).
2738 The WIN32_STREAM_ID structure before the cStreamName field is
2739 the stream header, which is then immediately followed by the
2743 WIN32_STREAM_ID wid
;
2744 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2747 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2748 data
.wid
.cStreamName
, MAX_PATH
);
2751 LPVOID context
= NULL
;
2754 data
.wid
.dwStreamId
= BACKUP_LINK
;
2755 data
.wid
.dwStreamAttributes
= 0;
2756 data
.wid
.Size
.LowPart
= wlen
* sizeof(WCHAR
);
2757 data
.wid
.Size
.HighPart
= 0;
2758 data
.wid
.dwStreamNameSize
= 0;
2760 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2761 offsetof (WIN32_STREAM_ID
, cStreamName
)
2762 + data
.wid
.Size
.LowPart
,
2763 &wbytes
, FALSE
, FALSE
, &context
)
2764 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2771 /* Should try mapping GetLastError to errno; for now just
2772 indicate a general error (eg. links not supported). */
2773 errno
= EINVAL
; // perhaps EMLINK?
2777 CloseHandle (fileh
);
2786 sys_mkdir (const char * path
)
2788 return _mkdir (map_w32_filename (path
, NULL
));
2791 /* Because of long name mapping issues, we need to implement this
2792 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2793 a unique name, instead of setting the input template to an empty
2796 Standard algorithm seems to be use pid or tid with a letter on the
2797 front (in place of the 6 X's) and cycle through the letters to find a
2798 unique name. We extend that to allow any reasonable character as the
2799 first of the 6 X's. */
2801 sys_mktemp (char * template)
2805 unsigned uid
= GetCurrentThreadId ();
2806 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2808 if (template == NULL
)
2810 p
= template + strlen (template);
2812 /* replace up to the last 5 X's with uid in decimal */
2813 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2815 p
[0] = '0' + uid
% 10;
2819 if (i
< 0 && p
[0] == 'X')
2824 int save_errno
= errno
;
2825 p
[0] = first_char
[i
];
2826 if (sys_access (template, 0) < 0)
2832 while (++i
< sizeof (first_char
));
2835 /* Template is badly formed or else we can't generate a unique name,
2836 so return empty string */
2842 sys_open (const char * path
, int oflag
, int mode
)
2844 const char* mpath
= map_w32_filename (path
, NULL
);
2845 /* Try to open file without _O_CREAT, to be able to write to hidden
2846 and system files. Force all file handles to be
2848 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2851 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2855 sys_rename (const char * oldname
, const char * newname
)
2858 char temp
[MAX_PATH
];
2860 /* MoveFile on Windows 95 doesn't correctly change the short file name
2861 alias in a number of circumstances (it is not easy to predict when
2862 just by looking at oldname and newname, unfortunately). In these
2863 cases, renaming through a temporary name avoids the problem.
2865 A second problem on Windows 95 is that renaming through a temp name when
2866 newname is uppercase fails (the final long name ends up in
2867 lowercase, although the short alias might be uppercase) UNLESS the
2868 long temp name is not 8.3.
2870 So, on Windows 95 we always rename through a temp name, and we make sure
2871 the temp name has a long extension to ensure correct renaming. */
2873 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2875 if (os_subtype
== OS_WIN95
)
2881 oldname
= map_w32_filename (oldname
, NULL
);
2882 if (o
= strrchr (oldname
, '\\'))
2885 o
= (char *) oldname
;
2887 if (p
= strrchr (temp
, '\\'))
2894 /* Force temp name to require a manufactured 8.3 alias - this
2895 seems to make the second rename work properly. */
2896 sprintf (p
, "_.%s.%u", o
, i
);
2898 result
= rename (oldname
, temp
);
2900 /* This loop must surely terminate! */
2901 while (result
< 0 && errno
== EEXIST
);
2906 /* Emulate Unix behavior - newname is deleted if it already exists
2907 (at least if it is a file; don't do this for directories).
2909 Since we mustn't do this if we are just changing the case of the
2910 file name (we would end up deleting the file we are trying to
2911 rename!), we let rename detect if the destination file already
2912 exists - that way we avoid the possible pitfalls of trying to
2913 determine ourselves whether two names really refer to the same
2914 file, which is not always possible in the general case. (Consider
2915 all the permutations of shared or subst'd drives, etc.) */
2917 newname
= map_w32_filename (newname
, NULL
);
2918 result
= rename (temp
, newname
);
2922 && _chmod (newname
, 0666) == 0
2923 && _unlink (newname
) == 0)
2924 result
= rename (temp
, newname
);
2930 sys_rmdir (const char * path
)
2932 return _rmdir (map_w32_filename (path
, NULL
));
2936 sys_unlink (const char * path
)
2938 path
= map_w32_filename (path
, NULL
);
2940 /* On Unix, unlink works without write permission. */
2941 _chmod (path
, 0666);
2942 return _unlink (path
);
2945 static FILETIME utc_base_ft
;
2946 static ULONGLONG utc_base
; /* In 100ns units */
2947 static int init
= 0;
2949 #define FILETIME_TO_U64(result, ft) \
2951 ULARGE_INTEGER uiTemp; \
2952 uiTemp.LowPart = (ft).dwLowDateTime; \
2953 uiTemp.HighPart = (ft).dwHighDateTime; \
2954 result = uiTemp.QuadPart; \
2958 initialize_utc_base ()
2960 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2969 st
.wMilliseconds
= 0;
2971 SystemTimeToFileTime (&st
, &utc_base_ft
);
2972 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2976 convert_time (FILETIME ft
)
2982 initialize_utc_base();
2986 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2989 FILETIME_TO_U64 (tmp
, ft
);
2990 return (time_t) ((tmp
- utc_base
) / 10000000L);
2995 convert_from_time_t (time_t time
, FILETIME
* pft
)
3001 initialize_utc_base ();
3005 /* time in 100ns units since 1-Jan-1601 */
3006 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3007 pft
->dwHighDateTime
= tmp
.HighPart
;
3008 pft
->dwLowDateTime
= tmp
.LowPart
;
3012 /* No reason to keep this; faking inode values either by hashing or even
3013 using the file index from GetInformationByHandle, is not perfect and
3014 so by default Emacs doesn't use the inode values on Windows.
3015 Instead, we now determine file-truename correctly (except for
3016 possible drive aliasing etc). */
3018 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3020 hashval (const unsigned char * str
)
3025 h
= (h
<< 4) + *str
++;
3031 /* Return the hash value of the canonical pathname, excluding the
3032 drive/UNC header, to get a hopefully unique inode number. */
3034 generate_inode_val (const char * name
)
3036 char fullname
[ MAX_PATH
];
3040 /* Get the truly canonical filename, if it exists. (Note: this
3041 doesn't resolve aliasing due to subst commands, or recognise hard
3043 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3046 parse_root (fullname
, &p
);
3047 /* Normal W32 filesystems are still case insensitive. */
3054 static PSECURITY_DESCRIPTOR
3055 get_file_security_desc (const char *fname
)
3057 PSECURITY_DESCRIPTOR psd
= NULL
;
3059 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3060 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3062 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3064 err
= GetLastError ();
3065 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3069 psd
= xmalloc (sd_len
);
3070 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3082 unsigned n_subauthorities
;
3084 /* Use the last sub-authority value of the RID, the relative
3085 portion of the SID, as user/group ID. */
3086 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3087 if (n_subauthorities
< 1)
3088 return 0; /* the "World" RID */
3089 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3092 /* Caching SID and account values for faster lokup. */
3095 # define FLEXIBLE_ARRAY_MEMBER
3097 # define FLEXIBLE_ARRAY_MEMBER 1
3102 struct w32_id
*next
;
3104 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3107 static struct w32_id
*w32_idlist
;
3110 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3112 struct w32_id
*tail
, *found
;
3114 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3116 if (equal_sid ((PSID
)tail
->sid
, sid
))
3125 strcpy (name
, found
->name
);
3133 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3136 struct w32_id
*new_entry
;
3138 /* We don't want to leave behind stale cache from when Emacs was
3142 sid_len
= get_length_sid (sid
);
3143 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3146 new_entry
->rid
= id
;
3147 strcpy (new_entry
->name
, name
);
3148 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3149 new_entry
->next
= w32_idlist
;
3150 w32_idlist
= new_entry
;
3159 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3160 unsigned *id
, char *nm
, int what
)
3163 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3165 SID_NAME_USE ignore
;
3167 DWORD name_len
= sizeof (name
);
3169 DWORD domain_len
= sizeof(domain
);
3175 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3176 else if (what
== GID
)
3177 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3181 if (!result
|| !is_valid_sid (sid
))
3183 else if (!w32_cached_id (sid
, id
, nm
))
3185 /* If FNAME is a UNC, we need to lookup account on the
3186 specified machine. */
3187 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3188 && fname
[2] != '\0')
3193 for (s
= fname
+ 2, p
= machine
;
3194 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3200 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3201 domain
, &domain_len
, &ignore
)
3202 || name_len
> UNLEN
+1)
3206 *id
= get_rid (sid
);
3208 w32_add_to_cache (sid
, *id
, name
);
3215 get_file_owner_and_group (
3216 PSECURITY_DESCRIPTOR psd
,
3220 int dflt_usr
= 0, dflt_grp
= 0;
3229 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3231 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3234 /* Consider files to belong to current user/group, if we cannot get
3235 more accurate information. */
3238 st
->st_uid
= dflt_passwd
.pw_uid
;
3239 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3243 st
->st_gid
= dflt_passwd
.pw_gid
;
3244 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3248 /* Return non-zero if NAME is a potentially slow filesystem. */
3250 is_slow_fs (const char *name
)
3255 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3256 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3257 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3258 devtype
= GetDriveType (NULL
); /* use root of current drive */
3261 /* GetDriveType needs the root directory of the drive. */
3262 strncpy (drive_root
, name
, 2);
3263 drive_root
[2] = '\\';
3264 drive_root
[3] = '\0';
3265 devtype
= GetDriveType (drive_root
);
3267 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3270 /* MSVC stat function can't cope with UNC names and has other bugs, so
3271 replace it with our own. This also allows us to calculate consistent
3272 inode values without hacks in the main Emacs code. */
3274 stat (const char * path
, struct stat
* buf
)
3279 WIN32_FIND_DATA wfd
;
3281 unsigned __int64 fake_inode
;
3284 int rootdir
= FALSE
;
3285 PSECURITY_DESCRIPTOR psd
= NULL
;
3287 if (path
== NULL
|| buf
== NULL
)
3293 name
= (char *) map_w32_filename (path
, &path
);
3294 /* Must be valid filename, no wild cards or other invalid
3295 characters. We use _mbspbrk to support multibyte strings that
3296 might look to strpbrk as if they included literal *, ?, and other
3297 characters mentioned below that are disallowed by Windows
3299 if (_mbspbrk (name
, "*?|<>\""))
3305 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3306 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3307 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3312 /* Remove trailing directory separator, unless name is the root
3313 directory of a drive or UNC volume in which case ensure there
3314 is a trailing separator. */
3315 len
= strlen (name
);
3316 rootdir
= (path
>= name
+ len
- 1
3317 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3318 name
= strcpy (alloca (len
+ 2), name
);
3320 if (is_unc_volume (name
))
3322 DWORD attrs
= unc_volume_file_attributes (name
);
3327 memset (&wfd
, 0, sizeof (wfd
));
3328 wfd
.dwFileAttributes
= attrs
;
3329 wfd
.ftCreationTime
= utc_base_ft
;
3330 wfd
.ftLastAccessTime
= utc_base_ft
;
3331 wfd
.ftLastWriteTime
= utc_base_ft
;
3332 strcpy (wfd
.cFileName
, name
);
3336 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3337 strcat (name
, "\\");
3338 if (GetDriveType (name
) < 2)
3343 memset (&wfd
, 0, sizeof (wfd
));
3344 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3345 wfd
.ftCreationTime
= utc_base_ft
;
3346 wfd
.ftLastAccessTime
= utc_base_ft
;
3347 wfd
.ftLastWriteTime
= utc_base_ft
;
3348 strcpy (wfd
.cFileName
, name
);
3352 if (IS_DIRECTORY_SEP (name
[len
-1]))
3355 /* (This is hacky, but helps when doing file completions on
3356 network drives.) Optimize by using information available from
3357 active readdir if possible. */
3358 len
= strlen (dir_pathname
);
3359 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3361 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3362 && strnicmp (name
, dir_pathname
, len
) == 0
3363 && IS_DIRECTORY_SEP (name
[len
])
3364 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3366 /* This was the last entry returned by readdir. */
3367 wfd
= dir_find_data
;
3371 logon_network_drive (name
);
3373 fh
= FindFirstFile (name
, &wfd
);
3374 if (fh
== INVALID_HANDLE_VALUE
)
3383 if (!(NILP (Vw32_get_true_file_attributes
)
3384 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3385 /* No access rights required to get info. */
3386 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3387 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3388 != INVALID_HANDLE_VALUE
)
3390 /* This is more accurate in terms of gettting the correct number
3391 of links, but is quite slow (it is noticeable when Emacs is
3392 making a list of file name completions). */
3393 BY_HANDLE_FILE_INFORMATION info
;
3395 if (GetFileInformationByHandle (fh
, &info
))
3397 buf
->st_nlink
= info
.nNumberOfLinks
;
3398 /* Might as well use file index to fake inode values, but this
3399 is not guaranteed to be unique unless we keep a handle open
3400 all the time (even then there are situations where it is
3401 not unique). Reputedly, there are at most 48 bits of info
3402 (on NTFS, presumably less on FAT). */
3403 fake_inode
= info
.nFileIndexHigh
;
3405 fake_inode
+= info
.nFileIndexLow
;
3413 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3415 buf
->st_mode
= S_IFDIR
;
3419 switch (GetFileType (fh
))
3421 case FILE_TYPE_DISK
:
3422 buf
->st_mode
= S_IFREG
;
3424 case FILE_TYPE_PIPE
:
3425 buf
->st_mode
= S_IFIFO
;
3427 case FILE_TYPE_CHAR
:
3428 case FILE_TYPE_UNKNOWN
:
3430 buf
->st_mode
= S_IFCHR
;
3434 psd
= get_file_security_desc (name
);
3435 get_file_owner_and_group (psd
, name
, buf
);
3439 /* Don't bother to make this information more accurate. */
3440 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3445 get_file_owner_and_group (NULL
, name
, buf
);
3450 /* Not sure if there is any point in this. */
3451 if (!NILP (Vw32_generate_fake_inodes
))
3452 fake_inode
= generate_inode_val (name
);
3453 else if (fake_inode
== 0)
3455 /* For want of something better, try to make everything unique. */
3456 static DWORD gen_num
= 0;
3457 fake_inode
= ++gen_num
;
3461 /* MSVC defines _ino_t to be short; other libc's might not. */
3462 if (sizeof (buf
->st_ino
) == 2)
3463 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3465 buf
->st_ino
= fake_inode
;
3467 /* volume_info is set indirectly by map_w32_filename */
3468 buf
->st_dev
= volume_info
.serialnum
;
3469 buf
->st_rdev
= volume_info
.serialnum
;
3472 buf
->st_size
= wfd
.nFileSizeHigh
;
3473 buf
->st_size
<<= 32;
3474 buf
->st_size
+= wfd
.nFileSizeLow
;
3476 /* Convert timestamps to Unix format. */
3477 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3478 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3479 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3480 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3481 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3483 /* determine rwx permissions */
3484 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3485 permission
= S_IREAD
;
3487 permission
= S_IREAD
| S_IWRITE
;
3489 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3490 permission
|= S_IEXEC
;
3491 else if (is_exec (name
))
3492 permission
|= S_IEXEC
;
3494 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3499 /* Provide fstat and utime as well as stat for consistent handling of
3502 fstat (int desc
, struct stat
* buf
)
3504 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3505 BY_HANDLE_FILE_INFORMATION info
;
3506 unsigned __int64 fake_inode
;
3509 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3511 case FILE_TYPE_DISK
:
3512 buf
->st_mode
= S_IFREG
;
3513 if (!GetFileInformationByHandle (fh
, &info
))
3519 case FILE_TYPE_PIPE
:
3520 buf
->st_mode
= S_IFIFO
;
3522 case FILE_TYPE_CHAR
:
3523 case FILE_TYPE_UNKNOWN
:
3525 buf
->st_mode
= S_IFCHR
;
3527 memset (&info
, 0, sizeof (info
));
3528 info
.dwFileAttributes
= 0;
3529 info
.ftCreationTime
= utc_base_ft
;
3530 info
.ftLastAccessTime
= utc_base_ft
;
3531 info
.ftLastWriteTime
= utc_base_ft
;
3534 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3535 buf
->st_mode
= S_IFDIR
;
3537 buf
->st_nlink
= info
.nNumberOfLinks
;
3538 /* Might as well use file index to fake inode values, but this
3539 is not guaranteed to be unique unless we keep a handle open
3540 all the time (even then there are situations where it is
3541 not unique). Reputedly, there are at most 48 bits of info
3542 (on NTFS, presumably less on FAT). */
3543 fake_inode
= info
.nFileIndexHigh
;
3545 fake_inode
+= info
.nFileIndexLow
;
3547 /* MSVC defines _ino_t to be short; other libc's might not. */
3548 if (sizeof (buf
->st_ino
) == 2)
3549 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3551 buf
->st_ino
= fake_inode
;
3553 /* Consider files to belong to current user.
3554 FIXME: this should use GetSecurityInfo API, but it is only
3555 available for _WIN32_WINNT >= 0x501. */
3556 buf
->st_uid
= dflt_passwd
.pw_uid
;
3557 buf
->st_gid
= dflt_passwd
.pw_gid
;
3558 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3559 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3561 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3562 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3564 buf
->st_size
= info
.nFileSizeHigh
;
3565 buf
->st_size
<<= 32;
3566 buf
->st_size
+= info
.nFileSizeLow
;
3568 /* Convert timestamps to Unix format. */
3569 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3570 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3571 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3572 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3573 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3575 /* determine rwx permissions */
3576 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3577 permission
= S_IREAD
;
3579 permission
= S_IREAD
| S_IWRITE
;
3581 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3582 permission
|= S_IEXEC
;
3585 #if 0 /* no way of knowing the filename */
3586 char * p
= strrchr (name
, '.');
3588 (xstrcasecmp (p
, ".exe") == 0 ||
3589 xstrcasecmp (p
, ".com") == 0 ||
3590 xstrcasecmp (p
, ".bat") == 0 ||
3591 xstrcasecmp (p
, ".cmd") == 0))
3592 permission
|= S_IEXEC
;
3596 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3602 utime (const char *name
, struct utimbuf
*times
)
3604 struct utimbuf deftime
;
3611 deftime
.modtime
= deftime
.actime
= time (NULL
);
3615 /* Need write access to set times. */
3616 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3617 0, OPEN_EXISTING
, 0, NULL
);
3620 convert_from_time_t (times
->actime
, &atime
);
3621 convert_from_time_t (times
->modtime
, &mtime
);
3622 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3639 /* Support for browsing other processes and their attributes. See
3640 process.c for the Lisp bindings. */
3642 /* Helper wrapper functions. */
3644 HANDLE WINAPI
create_toolhelp32_snapshot(
3648 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3650 if (g_b_init_create_toolhelp32_snapshot
== 0)
3652 g_b_init_create_toolhelp32_snapshot
= 1;
3653 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3654 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3655 "CreateToolhelp32Snapshot");
3657 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3659 return INVALID_HANDLE_VALUE
;
3661 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3664 BOOL WINAPI
process32_first(
3666 LPPROCESSENTRY32 lppe
)
3668 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3670 if (g_b_init_process32_first
== 0)
3672 g_b_init_process32_first
= 1;
3673 s_pfn_Process32_First
= (Process32First_Proc
)
3674 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3677 if (s_pfn_Process32_First
== NULL
)
3681 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3684 BOOL WINAPI
process32_next(
3686 LPPROCESSENTRY32 lppe
)
3688 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3690 if (g_b_init_process32_next
== 0)
3692 g_b_init_process32_next
= 1;
3693 s_pfn_Process32_Next
= (Process32Next_Proc
)
3694 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3697 if (s_pfn_Process32_Next
== NULL
)
3701 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3704 BOOL WINAPI
open_thread_token (
3705 HANDLE ThreadHandle
,
3706 DWORD DesiredAccess
,
3708 PHANDLE TokenHandle
)
3710 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3711 HMODULE hm_advapi32
= NULL
;
3712 if (is_windows_9x () == TRUE
)
3714 SetLastError (ERROR_NOT_SUPPORTED
);
3717 if (g_b_init_open_thread_token
== 0)
3719 g_b_init_open_thread_token
= 1;
3720 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3721 s_pfn_Open_Thread_Token
=
3722 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3724 if (s_pfn_Open_Thread_Token
== NULL
)
3726 SetLastError (ERROR_NOT_SUPPORTED
);
3730 s_pfn_Open_Thread_Token (
3738 BOOL WINAPI
impersonate_self (
3739 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3741 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3742 HMODULE hm_advapi32
= NULL
;
3743 if (is_windows_9x () == TRUE
)
3747 if (g_b_init_impersonate_self
== 0)
3749 g_b_init_impersonate_self
= 1;
3750 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3751 s_pfn_Impersonate_Self
=
3752 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3754 if (s_pfn_Impersonate_Self
== NULL
)
3758 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3761 BOOL WINAPI
revert_to_self (void)
3763 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3764 HMODULE hm_advapi32
= NULL
;
3765 if (is_windows_9x () == TRUE
)
3769 if (g_b_init_revert_to_self
== 0)
3771 g_b_init_revert_to_self
= 1;
3772 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3773 s_pfn_Revert_To_Self
=
3774 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3776 if (s_pfn_Revert_To_Self
== NULL
)
3780 return s_pfn_Revert_To_Self ();
3783 BOOL WINAPI
get_process_memory_info (
3785 PPROCESS_MEMORY_COUNTERS mem_counters
,
3788 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3789 HMODULE hm_psapi
= NULL
;
3790 if (is_windows_9x () == TRUE
)
3794 if (g_b_init_get_process_memory_info
== 0)
3796 g_b_init_get_process_memory_info
= 1;
3797 hm_psapi
= LoadLibrary ("Psapi.dll");
3799 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3800 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3802 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3806 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3809 BOOL WINAPI
get_process_working_set_size (
3814 static GetProcessWorkingSetSize_Proc
3815 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3817 if (is_windows_9x () == TRUE
)
3821 if (g_b_init_get_process_working_set_size
== 0)
3823 g_b_init_get_process_working_set_size
= 1;
3824 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3825 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3826 "GetProcessWorkingSetSize");
3828 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3832 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3835 BOOL WINAPI
global_memory_status (
3838 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3840 if (is_windows_9x () == TRUE
)
3844 if (g_b_init_global_memory_status
== 0)
3846 g_b_init_global_memory_status
= 1;
3847 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3848 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3849 "GlobalMemoryStatus");
3851 if (s_pfn_Global_Memory_Status
== NULL
)
3855 return s_pfn_Global_Memory_Status (buf
);
3858 BOOL WINAPI
global_memory_status_ex (
3859 MEMORY_STATUS_EX
*buf
)
3861 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3863 if (is_windows_9x () == TRUE
)
3867 if (g_b_init_global_memory_status_ex
== 0)
3869 g_b_init_global_memory_status_ex
= 1;
3870 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3871 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3872 "GlobalMemoryStatusEx");
3874 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3878 return s_pfn_Global_Memory_Status_Ex (buf
);
3882 list_system_processes ()
3884 struct gcpro gcpro1
;
3885 Lisp_Object proclist
= Qnil
;
3888 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3890 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3892 PROCESSENTRY32 proc_entry
;
3898 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3899 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3900 res
= process32_next (h_snapshot
, &proc_entry
))
3902 proc_id
= proc_entry
.th32ProcessID
;
3903 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3906 CloseHandle (h_snapshot
);
3908 proclist
= Fnreverse (proclist
);
3915 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3917 TOKEN_PRIVILEGES priv
;
3918 DWORD priv_size
= sizeof (priv
);
3919 DWORD opriv_size
= sizeof (*old_priv
);
3920 HANDLE h_token
= NULL
;
3921 HANDLE h_thread
= GetCurrentThread ();
3925 res
= open_thread_token (h_thread
,
3926 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3928 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3930 if (impersonate_self (SecurityImpersonation
))
3931 res
= open_thread_token (h_thread
,
3932 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3937 priv
.PrivilegeCount
= 1;
3938 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3939 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3940 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3941 old_priv
, &opriv_size
)
3942 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3946 CloseHandle (h_token
);
3952 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3954 DWORD priv_size
= sizeof (*priv
);
3955 HANDLE h_token
= NULL
;
3958 if (open_thread_token (GetCurrentThread (),
3959 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3962 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3963 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3967 CloseHandle (h_token
);
3973 ltime (time_sec
, time_usec
)
3974 long time_sec
, time_usec
;
3976 return list3 (make_number ((time_sec
>> 16) & 0xffff),
3977 make_number (time_sec
& 0xffff),
3978 make_number (time_usec
));
3981 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
3984 process_times (h_proc
, ctime
, etime
, stime
, utime
, ttime
, pcpu
)
3986 Lisp_Object
*ctime
, *etime
, *stime
, *utime
, *ttime
;
3989 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
3990 ULONGLONG tem1
, tem2
, tem3
, tem
;
3993 || !get_process_times_fn
3994 || !(*get_process_times_fn
)(h_proc
, &ft_creation
, &ft_exit
,
3995 &ft_kernel
, &ft_user
))
3998 GetSystemTimeAsFileTime (&ft_current
);
4000 FILETIME_TO_U64 (tem1
, ft_kernel
);
4002 *stime
= U64_TO_LISP_TIME (tem1
);
4004 FILETIME_TO_U64 (tem2
, ft_user
);
4006 *utime
= U64_TO_LISP_TIME (tem2
);
4009 *ttime
= U64_TO_LISP_TIME (tem3
);
4011 FILETIME_TO_U64 (tem
, ft_creation
);
4012 /* Process no 4 (System) returns zero creation time. */
4014 tem
= (tem
- utc_base
) / 10L;
4015 *ctime
= U64_TO_LISP_TIME (tem
);
4019 FILETIME_TO_U64 (tem3
, ft_current
);
4020 tem
= (tem3
- utc_base
) / 10L - tem
;
4022 *etime
= U64_TO_LISP_TIME (tem
);
4026 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4037 system_process_attributes (pid
)
4040 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4041 Lisp_Object attrs
= Qnil
;
4042 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4043 HANDLE h_snapshot
, h_proc
;
4046 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4047 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4048 DWORD glength
= sizeof (gname
);
4049 HANDLE token
= NULL
;
4050 SID_NAME_USE user_type
;
4051 unsigned char *buf
= NULL
;
4053 TOKEN_USER user_token
;
4054 TOKEN_PRIMARY_GROUP group_token
;
4058 PROCESS_MEMORY_COUNTERS mem
;
4059 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4060 DWORD minrss
, maxrss
;
4062 MEMORY_STATUS_EX memstex
;
4063 double totphys
= 0.0;
4064 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4066 BOOL result
= FALSE
;
4068 CHECK_NUMBER_OR_FLOAT (pid
);
4069 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4071 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4073 GCPRO3 (attrs
, decoded_cmd
, tem
);
4075 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4080 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4081 for (res
= process32_first (h_snapshot
, &pe
); res
;
4082 res
= process32_next (h_snapshot
, &pe
))
4084 if (proc_id
== pe
.th32ProcessID
)
4087 decoded_cmd
= build_string ("Idle");
4090 /* Decode the command name from locale-specific
4092 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4093 strlen (pe
.szExeFile
));
4095 code_convert_string_norecord (cmd_str
,
4096 Vlocale_coding_system
, 0);
4098 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4099 attrs
= Fcons (Fcons (Qppid
,
4100 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4102 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4104 attrs
= Fcons (Fcons (Qthcount
,
4105 make_fixnum_or_float (pe
.cntThreads
)),
4112 CloseHandle (h_snapshot
);
4121 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4123 /* If we were denied a handle to the process, try again after
4124 enabling the SeDebugPrivilege in our process. */
4127 TOKEN_PRIVILEGES priv_current
;
4129 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4131 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4133 restore_privilege (&priv_current
);
4139 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4142 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4143 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4145 buf
= xmalloc (blen
);
4146 result
= get_token_information (token
, TokenUser
,
4147 (LPVOID
)buf
, blen
, &needed
);
4150 memcpy (&user_token
, buf
, sizeof (user_token
));
4151 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4153 euid
= get_rid (user_token
.User
.Sid
);
4154 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4159 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4162 strcpy (uname
, "unknown");
4166 ulength
= strlen (uname
);
4172 /* Determine a reasonable euid and gid values. */
4173 if (xstrcasecmp ("administrator", uname
) == 0)
4175 euid
= 500; /* well-known Administrator uid */
4176 egid
= 513; /* well-known None gid */
4180 /* Get group id and name. */
4181 result
= get_token_information (token
, TokenPrimaryGroup
,
4182 (LPVOID
)buf
, blen
, &needed
);
4183 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4185 buf
= xrealloc (buf
, blen
= needed
);
4186 result
= get_token_information (token
, TokenPrimaryGroup
,
4187 (LPVOID
)buf
, blen
, &needed
);
4191 memcpy (&group_token
, buf
, sizeof (group_token
));
4192 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4194 egid
= get_rid (group_token
.PrimaryGroup
);
4195 dlength
= sizeof (domain
);
4197 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4198 gname
, &glength
, NULL
, &dlength
,
4201 w32_add_to_cache (group_token
.PrimaryGroup
,
4205 strcpy (gname
, "None");
4209 glength
= strlen (gname
);
4217 if (!is_windows_9x ())
4219 /* We couldn't open the process token, presumably because of
4220 insufficient access rights. Assume this process is run
4222 strcpy (uname
, "SYSTEM");
4223 strcpy (gname
, "None");
4224 euid
= 18; /* SYSTEM */
4225 egid
= 513; /* None */
4226 glength
= strlen (gname
);
4227 ulength
= strlen (uname
);
4229 /* If we are running under Windows 9X, where security calls are
4230 not supported, we assume all processes are run by the current
4232 else if (GetUserName (uname
, &ulength
))
4234 if (xstrcasecmp ("administrator", uname
) == 0)
4239 strcpy (gname
, "None");
4240 glength
= strlen (gname
);
4241 ulength
= strlen (uname
);
4247 strcpy (uname
, "administrator");
4248 ulength
= strlen (uname
);
4249 strcpy (gname
, "None");
4250 glength
= strlen (gname
);
4253 CloseHandle (token
);
4256 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4257 tem
= make_unibyte_string (uname
, ulength
);
4258 attrs
= Fcons (Fcons (Quser
,
4259 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4261 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4262 tem
= make_unibyte_string (gname
, glength
);
4263 attrs
= Fcons (Fcons (Qgroup
,
4264 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4267 if (global_memory_status_ex (&memstex
))
4268 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4269 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4271 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4272 double, so we need to do this for it... */
4274 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4275 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4276 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4278 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4280 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4281 else if (global_memory_status (&memst
))
4282 totphys
= memst
.dwTotalPhys
/ 1024.0;
4285 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4288 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4290 attrs
= Fcons (Fcons (Qmajflt
,
4291 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4293 attrs
= Fcons (Fcons (Qvsize
,
4294 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4296 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4298 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4301 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4303 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4305 attrs
= Fcons (Fcons (Qmajflt
,
4306 make_fixnum_or_float (mem
.PageFaultCount
)),
4308 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4310 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4313 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4315 DWORD rss
= maxrss
/ 1024;
4317 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4319 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4322 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4324 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4325 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4326 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4327 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4328 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4329 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4332 /* FIXME: Retrieve command line by walking the PEB of the process. */
4335 CloseHandle (h_proc
);
4343 /* Wrappers for winsock functions to map between our file descriptors
4344 and winsock's handles; also set h_errno for convenience.
4346 To allow Emacs to run on systems which don't have winsock support
4347 installed, we dynamically link to winsock on startup if present, and
4348 otherwise provide the minimum necessary functionality
4349 (eg. gethostname). */
4351 /* function pointers for relevant socket functions */
4352 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4353 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4354 int (PASCAL
*pfn_WSAGetLastError
) (void);
4355 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4356 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4357 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4358 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4359 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4360 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4361 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4362 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4363 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4364 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4365 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4366 int (PASCAL
*pfn_WSACleanup
) (void);
4368 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4369 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4370 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4371 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4372 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4373 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4374 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4375 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4376 const char * optval
, int optlen
);
4377 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4378 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4380 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4381 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4382 struct sockaddr
* from
, int * fromlen
);
4383 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4384 const struct sockaddr
* to
, int tolen
);
4386 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4387 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4388 #ifndef HANDLE_FLAG_INHERIT
4389 #define HANDLE_FLAG_INHERIT 1
4393 static int winsock_inuse
;
4398 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4400 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4401 after WSAStartup returns successfully, but it seems reasonable
4402 to allow unloading winsock anyway in that case. */
4403 if (pfn_WSACleanup () == 0 ||
4404 pfn_WSAGetLastError () == WSAENETDOWN
)
4406 if (FreeLibrary (winsock_lib
))
4415 init_winsock (int load_now
)
4417 WSADATA winsockData
;
4419 if (winsock_lib
!= NULL
)
4422 pfn_SetHandleInformation
= NULL
;
4423 pfn_SetHandleInformation
4424 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4425 "SetHandleInformation");
4427 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4429 if (winsock_lib
!= NULL
)
4431 /* dynamically link to socket functions */
4433 #define LOAD_PROC(fn) \
4434 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4437 LOAD_PROC( WSAStartup
);
4438 LOAD_PROC( WSASetLastError
);
4439 LOAD_PROC( WSAGetLastError
);
4440 LOAD_PROC( WSAEventSelect
);
4441 LOAD_PROC( WSACreateEvent
);
4442 LOAD_PROC( WSACloseEvent
);
4443 LOAD_PROC( socket
);
4445 LOAD_PROC( connect
);
4446 LOAD_PROC( ioctlsocket
);
4449 LOAD_PROC( closesocket
);
4450 LOAD_PROC( shutdown
);
4453 LOAD_PROC( inet_addr
);
4454 LOAD_PROC( gethostname
);
4455 LOAD_PROC( gethostbyname
);
4456 LOAD_PROC( getservbyname
);
4457 LOAD_PROC( getpeername
);
4458 LOAD_PROC( WSACleanup
);
4459 LOAD_PROC( setsockopt
);
4460 LOAD_PROC( listen
);
4461 LOAD_PROC( getsockname
);
4462 LOAD_PROC( accept
);
4463 LOAD_PROC( recvfrom
);
4464 LOAD_PROC( sendto
);
4467 /* specify version 1.1 of winsock */
4468 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4470 if (winsockData
.wVersion
!= 0x101)
4475 /* Report that winsock exists and is usable, but leave
4476 socket functions disabled. I am assuming that calling
4477 WSAStartup does not require any network interaction,
4478 and in particular does not cause or require a dial-up
4479 connection to be established. */
4482 FreeLibrary (winsock_lib
);
4490 FreeLibrary (winsock_lib
);
4500 /* function to set h_errno for compatibility; map winsock error codes to
4501 normal system codes where they overlap (non-overlapping definitions
4502 are already in <sys/socket.h> */
4506 if (winsock_lib
== NULL
)
4509 h_errno
= pfn_WSAGetLastError ();
4513 case WSAEACCES
: h_errno
= EACCES
; break;
4514 case WSAEBADF
: h_errno
= EBADF
; break;
4515 case WSAEFAULT
: h_errno
= EFAULT
; break;
4516 case WSAEINTR
: h_errno
= EINTR
; break;
4517 case WSAEINVAL
: h_errno
= EINVAL
; break;
4518 case WSAEMFILE
: h_errno
= EMFILE
; break;
4519 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4520 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4528 if (h_errno
== 0 && winsock_lib
!= NULL
)
4529 pfn_WSASetLastError (0);
4532 /* Extend strerror to handle the winsock-specific error codes. */
4536 } _wsa_errlist
[] = {
4537 WSAEINTR
, "Interrupted function call",
4538 WSAEBADF
, "Bad file descriptor",
4539 WSAEACCES
, "Permission denied",
4540 WSAEFAULT
, "Bad address",
4541 WSAEINVAL
, "Invalid argument",
4542 WSAEMFILE
, "Too many open files",
4544 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
4545 WSAEINPROGRESS
, "Operation now in progress",
4546 WSAEALREADY
, "Operation already in progress",
4547 WSAENOTSOCK
, "Socket operation on non-socket",
4548 WSAEDESTADDRREQ
, "Destination address required",
4549 WSAEMSGSIZE
, "Message too long",
4550 WSAEPROTOTYPE
, "Protocol wrong type for socket",
4551 WSAENOPROTOOPT
, "Bad protocol option",
4552 WSAEPROTONOSUPPORT
, "Protocol not supported",
4553 WSAESOCKTNOSUPPORT
, "Socket type not supported",
4554 WSAEOPNOTSUPP
, "Operation not supported",
4555 WSAEPFNOSUPPORT
, "Protocol family not supported",
4556 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
4557 WSAEADDRINUSE
, "Address already in use",
4558 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
4559 WSAENETDOWN
, "Network is down",
4560 WSAENETUNREACH
, "Network is unreachable",
4561 WSAENETRESET
, "Network dropped connection on reset",
4562 WSAECONNABORTED
, "Software caused connection abort",
4563 WSAECONNRESET
, "Connection reset by peer",
4564 WSAENOBUFS
, "No buffer space available",
4565 WSAEISCONN
, "Socket is already connected",
4566 WSAENOTCONN
, "Socket is not connected",
4567 WSAESHUTDOWN
, "Cannot send after socket shutdown",
4568 WSAETOOMANYREFS
, "Too many references", /* not sure */
4569 WSAETIMEDOUT
, "Connection timed out",
4570 WSAECONNREFUSED
, "Connection refused",
4571 WSAELOOP
, "Network loop", /* not sure */
4572 WSAENAMETOOLONG
, "Name is too long",
4573 WSAEHOSTDOWN
, "Host is down",
4574 WSAEHOSTUNREACH
, "No route to host",
4575 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
4576 WSAEPROCLIM
, "Too many processes",
4577 WSAEUSERS
, "Too many users", /* not sure */
4578 WSAEDQUOT
, "Double quote in host name", /* really not sure */
4579 WSAESTALE
, "Data is stale", /* not sure */
4580 WSAEREMOTE
, "Remote error", /* not sure */
4582 WSASYSNOTREADY
, "Network subsystem is unavailable",
4583 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
4584 WSANOTINITIALISED
, "Winsock not initialized successfully",
4585 WSAEDISCON
, "Graceful shutdown in progress",
4587 WSAENOMORE
, "No more operations allowed", /* not sure */
4588 WSAECANCELLED
, "Operation cancelled", /* not sure */
4589 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
4590 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
4591 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
4592 WSASYSCALLFAILURE
, "System call failure",
4593 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
4594 WSATYPE_NOT_FOUND
, "Class type not found",
4595 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
4596 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
4597 WSAEREFUSED
, "Operation refused", /* not sure */
4600 WSAHOST_NOT_FOUND
, "Host not found",
4601 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
4602 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
4603 WSANO_DATA
, "Valid name, no data record of requested type",
4609 sys_strerror(int error_no
)
4612 static char unknown_msg
[40];
4614 if (error_no
>= 0 && error_no
< sys_nerr
)
4615 return sys_errlist
[error_no
];
4617 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4618 if (_wsa_errlist
[i
].errnum
== error_no
)
4619 return _wsa_errlist
[i
].msg
;
4621 sprintf(unknown_msg
, "Unidentified error: %d", error_no
);
4625 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4626 but I believe the method of keeping the socket handle separate (and
4627 insuring it is not inheritable) is the correct one. */
4629 //#define SOCK_REPLACE_HANDLE
4631 #ifdef SOCK_REPLACE_HANDLE
4632 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
4634 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4637 int socket_to_fd (SOCKET s
);
4640 sys_socket(int af
, int type
, int protocol
)
4644 if (winsock_lib
== NULL
)
4647 return INVALID_SOCKET
;
4652 /* call the real socket function */
4653 s
= pfn_socket (af
, type
, protocol
);
4655 if (s
!= INVALID_SOCKET
)
4656 return socket_to_fd (s
);
4662 /* Convert a SOCKET to a file descriptor. */
4664 socket_to_fd (SOCKET s
)
4669 /* Although under NT 3.5 _open_osfhandle will accept a socket
4670 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4671 that does not work under NT 3.1. However, we can get the same
4672 effect by using a backdoor function to replace an existing
4673 descriptor handle with the one we want. */
4675 /* allocate a file descriptor (with appropriate flags) */
4676 fd
= _open ("NUL:", _O_RDWR
);
4679 #ifdef SOCK_REPLACE_HANDLE
4680 /* now replace handle to NUL with our socket handle */
4681 CloseHandle ((HANDLE
) _get_osfhandle (fd
));
4683 _set_osfhnd (fd
, s
);
4684 /* setmode (fd, _O_BINARY); */
4686 /* Make a non-inheritable copy of the socket handle. Note
4687 that it is possible that sockets aren't actually kernel
4688 handles, which appears to be the case on Windows 9x when
4689 the MS Proxy winsock client is installed. */
4691 /* Apparently there is a bug in NT 3.51 with some service
4692 packs, which prevents using DuplicateHandle to make a
4693 socket handle non-inheritable (causes WSACleanup to
4694 hang). The work-around is to use SetHandleInformation
4695 instead if it is available and implemented. */
4696 if (pfn_SetHandleInformation
)
4698 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4702 HANDLE parent
= GetCurrentProcess ();
4703 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4705 if (DuplicateHandle (parent
,
4711 DUPLICATE_SAME_ACCESS
))
4713 /* It is possible that DuplicateHandle succeeds even
4714 though the socket wasn't really a kernel handle,
4715 because a real handle has the same value. So
4716 test whether the new handle really is a socket. */
4717 long nonblocking
= 0;
4718 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4720 pfn_closesocket (s
);
4725 CloseHandle (new_s
);
4730 fd_info
[fd
].hnd
= (HANDLE
) s
;
4733 /* set our own internal flags */
4734 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4740 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4742 /* attach child_process to fd_info */
4743 if (fd_info
[ fd
].cp
!= NULL
)
4745 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4749 fd_info
[ fd
].cp
= cp
;
4752 winsock_inuse
++; /* count open sockets */
4759 pfn_closesocket (s
);
4766 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4768 if (winsock_lib
== NULL
)
4771 return SOCKET_ERROR
;
4775 if (fd_info
[s
].flags
& FILE_SOCKET
)
4777 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4778 if (rc
== SOCKET_ERROR
)
4783 return SOCKET_ERROR
;
4788 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4790 if (winsock_lib
== NULL
)
4793 return SOCKET_ERROR
;
4797 if (fd_info
[s
].flags
& FILE_SOCKET
)
4799 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4800 if (rc
== SOCKET_ERROR
)
4805 return SOCKET_ERROR
;
4809 sys_htons (u_short hostshort
)
4811 return (winsock_lib
!= NULL
) ?
4812 pfn_htons (hostshort
) : hostshort
;
4816 sys_ntohs (u_short netshort
)
4818 return (winsock_lib
!= NULL
) ?
4819 pfn_ntohs (netshort
) : netshort
;
4823 sys_inet_addr (const char * cp
)
4825 return (winsock_lib
!= NULL
) ?
4826 pfn_inet_addr (cp
) : INADDR_NONE
;
4830 sys_gethostname (char * name
, int namelen
)
4832 if (winsock_lib
!= NULL
)
4833 return pfn_gethostname (name
, namelen
);
4835 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4836 return !GetComputerName (name
, (DWORD
*)&namelen
);
4839 return SOCKET_ERROR
;
4843 sys_gethostbyname(const char * name
)
4845 struct hostent
* host
;
4847 if (winsock_lib
== NULL
)
4854 host
= pfn_gethostbyname (name
);
4861 sys_getservbyname(const char * name
, const char * proto
)
4863 struct servent
* serv
;
4865 if (winsock_lib
== NULL
)
4872 serv
= pfn_getservbyname (name
, proto
);
4879 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4881 if (winsock_lib
== NULL
)
4884 return SOCKET_ERROR
;
4888 if (fd_info
[s
].flags
& FILE_SOCKET
)
4890 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4891 if (rc
== SOCKET_ERROR
)
4896 return SOCKET_ERROR
;
4901 sys_shutdown (int s
, int how
)
4903 if (winsock_lib
== NULL
)
4906 return SOCKET_ERROR
;
4910 if (fd_info
[s
].flags
& FILE_SOCKET
)
4912 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4913 if (rc
== SOCKET_ERROR
)
4918 return SOCKET_ERROR
;
4922 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4924 if (winsock_lib
== NULL
)
4927 return SOCKET_ERROR
;
4931 if (fd_info
[s
].flags
& FILE_SOCKET
)
4933 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4934 (const char *)optval
, optlen
);
4935 if (rc
== SOCKET_ERROR
)
4940 return SOCKET_ERROR
;
4944 sys_listen (int s
, int backlog
)
4946 if (winsock_lib
== NULL
)
4949 return SOCKET_ERROR
;
4953 if (fd_info
[s
].flags
& FILE_SOCKET
)
4955 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4956 if (rc
== SOCKET_ERROR
)
4959 fd_info
[s
].flags
|= FILE_LISTEN
;
4963 return SOCKET_ERROR
;
4967 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4969 if (winsock_lib
== NULL
)
4972 return SOCKET_ERROR
;
4976 if (fd_info
[s
].flags
& FILE_SOCKET
)
4978 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4979 if (rc
== SOCKET_ERROR
)
4984 return SOCKET_ERROR
;
4988 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
4990 if (winsock_lib
== NULL
)
4997 if (fd_info
[s
].flags
& FILE_LISTEN
)
4999 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5001 if (t
== INVALID_SOCKET
)
5004 fd
= socket_to_fd (t
);
5006 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5007 ResetEvent (fd_info
[s
].cp
->char_avail
);
5015 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5016 struct sockaddr
* from
, int * fromlen
)
5018 if (winsock_lib
== NULL
)
5021 return SOCKET_ERROR
;
5025 if (fd_info
[s
].flags
& FILE_SOCKET
)
5027 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5028 if (rc
== SOCKET_ERROR
)
5033 return SOCKET_ERROR
;
5037 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5038 const struct sockaddr
* to
, int tolen
)
5040 if (winsock_lib
== NULL
)
5043 return SOCKET_ERROR
;
5047 if (fd_info
[s
].flags
& FILE_SOCKET
)
5049 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5050 if (rc
== SOCKET_ERROR
)
5055 return SOCKET_ERROR
;
5058 /* Windows does not have an fcntl function. Provide an implementation
5059 solely for making sockets non-blocking. */
5061 fcntl (int s
, int cmd
, int options
)
5063 if (winsock_lib
== NULL
)
5070 if (fd_info
[s
].flags
& FILE_SOCKET
)
5072 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5074 unsigned long nblock
= 1;
5075 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5076 if (rc
== SOCKET_ERROR
)
5078 /* Keep track of the fact that we set this to non-blocking. */
5079 fd_info
[s
].flags
|= FILE_NDELAY
;
5085 return SOCKET_ERROR
;
5089 return SOCKET_ERROR
;
5092 #endif /* HAVE_SOCKETS */
5095 /* Shadow main io functions: we need to handle pipes and sockets more
5096 intelligently, and implement non-blocking mode as well. */
5109 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5111 child_process
* cp
= fd_info
[fd
].cp
;
5113 fd_info
[fd
].cp
= NULL
;
5115 if (CHILD_ACTIVE (cp
))
5117 /* if last descriptor to active child_process then cleanup */
5119 for (i
= 0; i
< MAXDESC
; i
++)
5123 if (fd_info
[i
].cp
== cp
)
5129 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5131 #ifndef SOCK_REPLACE_HANDLE
5132 if (winsock_lib
== NULL
) abort ();
5134 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5135 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5137 winsock_inuse
--; /* count open sockets */
5145 /* Note that sockets do not need special treatment here (at least on
5146 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5147 closesocket is equivalent to CloseHandle, which is to be expected
5148 because socket handles are fully fledged kernel handles. */
5151 if (rc
== 0 && fd
< MAXDESC
)
5152 fd_info
[fd
].flags
= 0;
5163 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5165 /* duplicate our internal info as well */
5166 fd_info
[new_fd
] = fd_info
[fd
];
5173 sys_dup2 (int src
, int dst
)
5177 if (dst
< 0 || dst
>= MAXDESC
)
5183 /* make sure we close the destination first if it's a pipe or socket */
5184 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5187 rc
= _dup2 (src
, dst
);
5190 /* duplicate our internal info as well */
5191 fd_info
[dst
] = fd_info
[src
];
5196 /* Unix pipe() has only one arg */
5198 sys_pipe (int * phandles
)
5203 /* make pipe handles non-inheritable; when we spawn a child, we
5204 replace the relevant handle with an inheritable one. Also put
5205 pipes into binary mode; we will do text mode translation ourselves
5207 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5211 /* Protect against overflow, since Windows can open more handles than
5212 our fd_info array has room for. */
5213 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5215 _close (phandles
[0]);
5216 _close (phandles
[1]);
5221 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5222 fd_info
[phandles
[0]].flags
= flags
;
5224 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5225 fd_info
[phandles
[1]].flags
= flags
;
5233 extern int w32_pipe_read_delay
;
5235 /* Function to do blocking read of one byte, needed to implement
5236 select. It is only allowed on sockets and pipes. */
5238 _sys_read_ahead (int fd
)
5243 if (fd
< 0 || fd
>= MAXDESC
)
5244 return STATUS_READ_ERROR
;
5246 cp
= fd_info
[fd
].cp
;
5248 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5249 return STATUS_READ_ERROR
;
5251 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5252 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5254 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5258 cp
->status
= STATUS_READ_IN_PROGRESS
;
5260 if (fd_info
[fd
].flags
& FILE_PIPE
)
5262 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5264 /* Give subprocess time to buffer some more output for us before
5265 reporting that input is available; we need this because Windows 95
5266 connects DOS programs to pipes by making the pipe appear to be
5267 the normal console stdout - as a result most DOS programs will
5268 write to stdout without buffering, ie. one character at a
5269 time. Even some W32 programs do this - "dir" in a command
5270 shell on NT is very slow if we don't do this. */
5273 int wait
= w32_pipe_read_delay
;
5279 /* Yield remainder of our time slice, effectively giving a
5280 temporary priority boost to the child process. */
5284 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5286 HANDLE hnd
= fd_info
[fd
].hnd
;
5287 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5290 /* Configure timeouts for blocking read. */
5291 if (!GetCommTimeouts (hnd
, &ct
))
5292 return STATUS_READ_ERROR
;
5293 ct
.ReadIntervalTimeout
= 0;
5294 ct
.ReadTotalTimeoutMultiplier
= 0;
5295 ct
.ReadTotalTimeoutConstant
= 0;
5296 if (!SetCommTimeouts (hnd
, &ct
))
5297 return STATUS_READ_ERROR
;
5299 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5301 if (GetLastError () != ERROR_IO_PENDING
)
5302 return STATUS_READ_ERROR
;
5303 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5304 return STATUS_READ_ERROR
;
5308 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5310 unsigned long nblock
= 0;
5311 /* We always want this to block, so temporarily disable NDELAY. */
5312 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5313 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5315 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5317 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5320 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5325 if (rc
== sizeof (char))
5326 cp
->status
= STATUS_READ_SUCCEEDED
;
5328 cp
->status
= STATUS_READ_FAILED
;
5334 _sys_wait_accept (int fd
)
5340 if (fd
< 0 || fd
>= MAXDESC
)
5341 return STATUS_READ_ERROR
;
5343 cp
= fd_info
[fd
].cp
;
5345 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5346 return STATUS_READ_ERROR
;
5348 cp
->status
= STATUS_READ_FAILED
;
5350 hEv
= pfn_WSACreateEvent ();
5351 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5352 if (rc
!= SOCKET_ERROR
)
5354 rc
= WaitForSingleObject (hEv
, INFINITE
);
5355 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5356 if (rc
== WAIT_OBJECT_0
)
5357 cp
->status
= STATUS_READ_SUCCEEDED
;
5359 pfn_WSACloseEvent (hEv
);
5365 sys_read (int fd
, char * buffer
, unsigned int count
)
5370 char * orig_buffer
= buffer
;
5378 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5380 child_process
*cp
= fd_info
[fd
].cp
;
5382 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5390 /* re-read CR carried over from last read */
5391 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5393 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5397 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5400 /* presence of a child_process structure means we are operating in
5401 non-blocking mode - otherwise we just call _read directly.
5402 Note that the child_process structure might be missing because
5403 reap_subprocess has been called; in this case the pipe is
5404 already broken, so calling _read on it is okay. */
5407 int current_status
= cp
->status
;
5409 switch (current_status
)
5411 case STATUS_READ_FAILED
:
5412 case STATUS_READ_ERROR
:
5413 /* report normal EOF if nothing in buffer */
5415 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5418 case STATUS_READ_READY
:
5419 case STATUS_READ_IN_PROGRESS
:
5420 DebPrint (("sys_read called when read is in progress\n"));
5421 errno
= EWOULDBLOCK
;
5424 case STATUS_READ_SUCCEEDED
:
5425 /* consume read-ahead char */
5426 *buffer
++ = cp
->chr
;
5429 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5430 ResetEvent (cp
->char_avail
);
5432 case STATUS_READ_ACKNOWLEDGED
:
5436 DebPrint (("sys_read: bad status %d\n", current_status
));
5441 if (fd_info
[fd
].flags
& FILE_PIPE
)
5443 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5444 to_read
= min (waiting
, (DWORD
) count
);
5447 nchars
+= _read (fd
, buffer
, to_read
);
5449 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5451 HANDLE hnd
= fd_info
[fd
].hnd
;
5452 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5459 /* Configure timeouts for non-blocking read. */
5460 if (!GetCommTimeouts (hnd
, &ct
))
5465 ct
.ReadIntervalTimeout
= MAXDWORD
;
5466 ct
.ReadTotalTimeoutMultiplier
= 0;
5467 ct
.ReadTotalTimeoutConstant
= 0;
5468 if (!SetCommTimeouts (hnd
, &ct
))
5474 if (!ResetEvent (ovl
->hEvent
))
5479 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5481 if (GetLastError () != ERROR_IO_PENDING
)
5486 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5496 else /* FILE_SOCKET */
5498 if (winsock_lib
== NULL
) abort ();
5500 /* do the equivalent of a non-blocking read */
5501 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5502 if (waiting
== 0 && nchars
== 0)
5504 h_errno
= errno
= EWOULDBLOCK
;
5510 /* always use binary mode for sockets */
5511 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5512 if (res
== SOCKET_ERROR
)
5514 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
5515 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5526 int nread
= _read (fd
, buffer
, count
);
5529 else if (nchars
== 0)
5534 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5535 /* Perform text mode translation if required. */
5536 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5538 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5539 /* If buffer contains only CR, return that. To be absolutely
5540 sure we should attempt to read the next char, but in
5541 practice a CR to be followed by LF would not appear by
5542 itself in the buffer. */
5543 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5545 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5551 nchars
= _read (fd
, buffer
, count
);
5556 /* From w32xfns.c */
5557 extern HANDLE interrupt_handle
;
5559 /* For now, don't bother with a non-blocking mode */
5561 sys_write (int fd
, const void * buffer
, unsigned int count
)
5571 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5573 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5579 /* Perform text mode translation if required. */
5580 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5582 char * tmpbuf
= alloca (count
* 2);
5583 unsigned char * src
= (void *)buffer
;
5584 unsigned char * dst
= tmpbuf
;
5589 unsigned char *next
;
5590 /* copy next line or remaining bytes */
5591 next
= _memccpy (dst
, src
, '\n', nbytes
);
5594 /* copied one line ending with '\n' */
5595 int copied
= next
- dst
;
5598 /* insert '\r' before '\n' */
5605 /* copied remaining partial line -> now finished */
5612 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5614 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5615 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5616 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5619 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5621 if (GetLastError () != ERROR_IO_PENDING
)
5626 if (detect_input_pending ())
5627 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5630 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5631 if (active
== WAIT_OBJECT_0
)
5632 { /* User pressed C-g, cancel write, then leave. Don't bother
5633 cleaning up as we may only get stuck in buggy drivers. */
5634 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5639 if (active
== WAIT_OBJECT_0
+ 1
5640 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5649 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5651 unsigned long nblock
= 0;
5652 if (winsock_lib
== NULL
) abort ();
5654 /* TODO: implement select() properly so non-blocking I/O works. */
5655 /* For now, make sure the write blocks. */
5656 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5657 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5659 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5661 /* Set the socket back to non-blocking if it was before,
5662 for other operations that support it. */
5663 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5666 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5669 if (nchars
== SOCKET_ERROR
)
5671 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
5672 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5678 nchars
= _write (fd
, buffer
, count
);
5684 check_windows_init_file ()
5686 extern int noninteractive
, inhibit_window_system
;
5688 /* A common indication that Emacs is not installed properly is when
5689 it cannot find the Windows installation file. If this file does
5690 not exist in the expected place, tell the user. */
5692 if (!noninteractive
&& !inhibit_window_system
)
5694 extern Lisp_Object Vwindow_system
, Vload_path
, Qfile_exists_p
;
5695 Lisp_Object objs
[2];
5696 Lisp_Object full_load_path
;
5697 Lisp_Object init_file
;
5700 objs
[0] = Vload_path
;
5701 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5702 full_load_path
= Fappend (2, objs
);
5703 init_file
= build_string ("term/w32-win");
5704 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5707 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5708 char *init_file_name
= SDATA (init_file
);
5709 char *load_path
= SDATA (load_path_print
);
5710 char *buffer
= alloca (1024
5711 + strlen (init_file_name
)
5712 + strlen (load_path
));
5715 "The Emacs Windows initialization file \"%s.el\" "
5716 "could not be found in your Emacs installation. "
5717 "Emacs checked the following directories for this file:\n"
5719 "When Emacs cannot find this file, it usually means that it "
5720 "was not installed properly, or its distribution file was "
5721 "not unpacked properly.\nSee the README.W32 file in the "
5722 "top-level Emacs directory for more information.",
5723 init_file_name
, load_path
);
5726 "Emacs Abort Dialog",
5727 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5728 /* Use the low-level Emacs abort. */
5743 /* shutdown the socket interface if necessary */
5754 /* Initialise the socket interface now if available and requested by
5755 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5756 delayed until open-network-stream is called (w32-has-winsock can
5757 also be used to dynamically load or reload winsock).
5759 Conveniently, init_environment is called before us, so
5760 PRELOAD_WINSOCK can be set in the registry. */
5762 /* Always initialize this correctly. */
5765 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5766 init_winsock (TRUE
);
5769 /* Initial preparation for subprocess support: replace our standard
5770 handles with non-inheritable versions. */
5773 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5774 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5775 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5777 parent
= GetCurrentProcess ();
5779 /* ignore errors when duplicating and closing; typically the
5780 handles will be invalid when running as a gui program. */
5781 DuplicateHandle (parent
,
5782 GetStdHandle (STD_INPUT_HANDLE
),
5787 DUPLICATE_SAME_ACCESS
);
5789 DuplicateHandle (parent
,
5790 GetStdHandle (STD_OUTPUT_HANDLE
),
5795 DUPLICATE_SAME_ACCESS
);
5797 DuplicateHandle (parent
,
5798 GetStdHandle (STD_ERROR_HANDLE
),
5803 DUPLICATE_SAME_ACCESS
);
5809 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5810 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5812 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5815 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5816 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5818 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5821 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5822 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5824 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5828 /* unfortunately, atexit depends on implementation of malloc */
5829 /* atexit (term_ntproc); */
5830 signal (SIGABRT
, term_ntproc
);
5832 /* determine which drives are fixed, for GetCachedVolumeInformation */
5834 /* GetDriveType must have trailing backslash. */
5835 char drive
[] = "A:\\";
5837 /* Loop over all possible drive letters */
5838 while (*drive
<= 'Z')
5840 /* Record if this drive letter refers to a fixed drive. */
5841 fixed_drives
[DRIVE_INDEX (*drive
)] =
5842 (GetDriveType (drive
) == DRIVE_FIXED
);
5847 /* Reset the volume info cache. */
5848 volume_cache
= NULL
;
5851 /* Check to see if Emacs has been installed correctly. */
5852 check_windows_init_file ();
5856 shutdown_handler ensures that buffers' autosave files are
5857 up to date when the user logs off, or the system shuts down.
5859 BOOL WINAPI
shutdown_handler(DWORD type
)
5861 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5862 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5863 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5864 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5866 /* Shut down cleanly, making sure autosave files are up to date. */
5867 shut_down_emacs (0, 0, Qnil
);
5870 /* Allow other handlers to handle this signal. */
5875 globals_of_w32 is used to initialize those global variables that
5876 must always be initialized on startup even when the global variable
5877 initialized is non zero (see the function main in emacs.c).
5882 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5884 get_process_times_fn
= (GetProcessTimes_Proc
)
5885 GetProcAddress (kernel32
, "GetProcessTimes");
5887 g_b_init_is_windows_9x
= 0;
5888 g_b_init_open_process_token
= 0;
5889 g_b_init_get_token_information
= 0;
5890 g_b_init_lookup_account_sid
= 0;
5891 g_b_init_get_sid_identifier_authority
= 0;
5892 g_b_init_get_sid_sub_authority
= 0;
5893 g_b_init_get_sid_sub_authority_count
= 0;
5894 g_b_init_get_file_security
= 0;
5895 g_b_init_get_security_descriptor_owner
= 0;
5896 g_b_init_get_security_descriptor_group
= 0;
5897 g_b_init_is_valid_sid
= 0;
5898 g_b_init_create_toolhelp32_snapshot
= 0;
5899 g_b_init_process32_first
= 0;
5900 g_b_init_process32_next
= 0;
5901 g_b_init_open_thread_token
= 0;
5902 g_b_init_impersonate_self
= 0;
5903 g_b_init_revert_to_self
= 0;
5904 g_b_init_get_process_memory_info
= 0;
5905 g_b_init_get_process_working_set_size
= 0;
5906 g_b_init_global_memory_status
= 0;
5907 g_b_init_global_memory_status_ex
= 0;
5908 g_b_init_equal_sid
= 0;
5909 g_b_init_copy_sid
= 0;
5910 g_b_init_get_length_sid
= 0;
5911 g_b_init_get_native_system_info
= 0;
5912 g_b_init_get_system_times
= 0;
5913 num_of_processors
= 0;
5914 /* The following sets a handler for shutdown notifications for
5915 console apps. This actually applies to Emacs in both console and
5916 GUI modes, since we had to fool windows into thinking emacs is a
5917 console application to get console mode to work. */
5918 SetConsoleCtrlHandler(shutdown_handler
, TRUE
);
5920 /* "None" is the default group name on standalone workstations. */
5921 strcpy (dflt_group_name
, "None");
5924 /* For make-serial-process */
5925 int serial_open (char *port
)
5931 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5932 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5933 if (hnd
== INVALID_HANDLE_VALUE
)
5934 error ("Could not open %s", port
);
5935 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5937 error ("Could not open %s", port
);
5941 error ("Could not create child process");
5943 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5944 fd_info
[ fd
].hnd
= hnd
;
5945 fd_info
[ fd
].flags
|=
5946 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5947 if (fd_info
[ fd
].cp
!= NULL
)
5949 error ("fd_info[fd = %d] is already in use", fd
);
5951 fd_info
[ fd
].cp
= cp
;
5952 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5953 if (cp
->ovl_read
.hEvent
== NULL
)
5954 error ("Could not create read event");
5955 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5956 if (cp
->ovl_write
.hEvent
== NULL
)
5957 error ("Could not create write event");
5962 /* For serial-process-configure */
5964 serial_configure (struct Lisp_Process
*p
,
5965 Lisp_Object contact
)
5967 Lisp_Object childp2
= Qnil
;
5968 Lisp_Object tem
= Qnil
;
5972 char summary
[4] = "???"; /* This usually becomes "8N1". */
5974 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
5975 error ("Not a serial process");
5976 hnd
= fd_info
[ p
->outfd
].hnd
;
5978 childp2
= Fcopy_sequence (p
->childp
);
5980 /* Initialize timeouts for blocking read and blocking write. */
5981 if (!GetCommTimeouts (hnd
, &ct
))
5982 error ("GetCommTimeouts() failed");
5983 ct
.ReadIntervalTimeout
= 0;
5984 ct
.ReadTotalTimeoutMultiplier
= 0;
5985 ct
.ReadTotalTimeoutConstant
= 0;
5986 ct
.WriteTotalTimeoutMultiplier
= 0;
5987 ct
.WriteTotalTimeoutConstant
= 0;
5988 if (!SetCommTimeouts (hnd
, &ct
))
5989 error ("SetCommTimeouts() failed");
5990 /* Read port attributes and prepare default configuration. */
5991 memset (&dcb
, 0, sizeof (dcb
));
5992 dcb
.DCBlength
= sizeof (DCB
);
5993 if (!GetCommState (hnd
, &dcb
))
5994 error ("GetCommState() failed");
5997 dcb
.fAbortOnError
= FALSE
;
5998 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6003 /* Configure speed. */
6004 if (!NILP (Fplist_member (contact
, QCspeed
)))
6005 tem
= Fplist_get (contact
, QCspeed
);
6007 tem
= Fplist_get (p
->childp
, QCspeed
);
6009 dcb
.BaudRate
= XINT (tem
);
6010 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6012 /* Configure bytesize. */
6013 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6014 tem
= Fplist_get (contact
, QCbytesize
);
6016 tem
= Fplist_get (p
->childp
, QCbytesize
);
6018 tem
= make_number (8);
6020 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6021 error (":bytesize must be nil (8), 7, or 8");
6022 dcb
.ByteSize
= XINT (tem
);
6023 summary
[0] = XINT (tem
) + '0';
6024 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6026 /* Configure parity. */
6027 if (!NILP (Fplist_member (contact
, QCparity
)))
6028 tem
= Fplist_get (contact
, QCparity
);
6030 tem
= Fplist_get (p
->childp
, QCparity
);
6031 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6032 error (":parity must be nil (no parity), `even', or `odd'");
6033 dcb
.fParity
= FALSE
;
6034 dcb
.Parity
= NOPARITY
;
6035 dcb
.fErrorChar
= FALSE
;
6040 else if (EQ (tem
, Qeven
))
6044 dcb
.Parity
= EVENPARITY
;
6045 dcb
.fErrorChar
= TRUE
;
6047 else if (EQ (tem
, Qodd
))
6051 dcb
.Parity
= ODDPARITY
;
6052 dcb
.fErrorChar
= TRUE
;
6054 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6056 /* Configure stopbits. */
6057 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6058 tem
= Fplist_get (contact
, QCstopbits
);
6060 tem
= Fplist_get (p
->childp
, QCstopbits
);
6062 tem
= make_number (1);
6064 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6065 error (":stopbits must be nil (1 stopbit), 1, or 2");
6066 summary
[2] = XINT (tem
) + '0';
6067 if (XINT (tem
) == 1)
6068 dcb
.StopBits
= ONESTOPBIT
;
6069 else if (XINT (tem
) == 2)
6070 dcb
.StopBits
= TWOSTOPBITS
;
6071 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6073 /* Configure flowcontrol. */
6074 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6075 tem
= Fplist_get (contact
, QCflowcontrol
);
6077 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6078 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6079 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6080 dcb
.fOutxCtsFlow
= FALSE
;
6081 dcb
.fOutxDsrFlow
= FALSE
;
6082 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6083 dcb
.fDsrSensitivity
= FALSE
;
6084 dcb
.fTXContinueOnXoff
= FALSE
;
6087 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6088 dcb
.XonChar
= 17; /* Control-Q */
6089 dcb
.XoffChar
= 19; /* Control-S */
6092 /* Already configured. */
6094 else if (EQ (tem
, Qhw
))
6096 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6097 dcb
.fOutxCtsFlow
= TRUE
;
6099 else if (EQ (tem
, Qsw
))
6104 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6106 /* Activate configuration. */
6107 if (!SetCommState (hnd
, &dcb
))
6108 error ("SetCommState() failed");
6110 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6111 p
->childp
= childp2
;
6116 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
6117 (do not change this comment) */