1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
23 #include <stddef.h> /* for offsetof */
26 #include <float.h> /* for DBL_EPSILON */
34 #include <sys/utime.h>
35 #include <mbstring.h> /* for _mbspbrk */
39 /* must include CRT headers *before* config.h */
74 #define _ANONYMOUS_UNION
75 #define _ANONYMOUS_STRUCT
78 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
79 use a different name to avoid compilation problems. */
80 typedef struct _MEMORY_STATUS_EX
{
83 DWORDLONG ullTotalPhys
;
84 DWORDLONG ullAvailPhys
;
85 DWORDLONG ullTotalPageFile
;
86 DWORDLONG ullAvailPageFile
;
87 DWORDLONG ullTotalVirtual
;
88 DWORDLONG ullAvailVirtual
;
89 DWORDLONG ullAvailExtendedVirtual
;
90 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
98 #if !defined(__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
99 /* This either is not in psapi.h or guarded by higher value of
100 _WIN32_WINNT than what we use. w32api suplied with MinGW 3.15
101 defines it in psapi.h */
102 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
104 DWORD PageFaultCount
;
105 DWORD PeakWorkingSetSize
;
106 DWORD WorkingSetSize
;
107 DWORD QuotaPeakPagedPoolUsage
;
108 DWORD QuotaPagedPoolUsage
;
109 DWORD QuotaPeakNonPagedPoolUsage
;
110 DWORD QuotaNonPagedPoolUsage
;
112 DWORD PeakPagefileUsage
;
114 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
117 /* TCP connection support. */
118 #include <sys/socket.h>
141 #include "dispextern.h" /* for xstrcasecmp */
142 #include "coding.h" /* for Vlocale_coding_system */
144 /* For serial_configure and serial_open. */
147 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
148 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
150 void globals_of_w32 (void);
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 (void)
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
);
836 /* Emulate getloadavg. */
845 /* Number of processors on this machine. */
846 static unsigned num_of_processors
;
848 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
849 static struct load_sample samples
[16*60];
850 static int first_idx
= -1, last_idx
= -1;
851 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
856 int next_idx
= from
+ 1;
858 if (next_idx
>= max_idx
)
867 int prev_idx
= from
- 1;
870 prev_idx
= max_idx
- 1;
876 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
879 FILETIME ft_idle
, ft_user
, ft_kernel
;
881 /* Initialize the number of processors on this machine. */
882 if (num_of_processors
<= 0)
884 get_native_system_info (&sysinfo
);
885 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
886 if (num_of_processors
<= 0)
888 GetSystemInfo (&sysinfo
);
889 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
891 if (num_of_processors
<= 0)
892 num_of_processors
= 1;
895 /* TODO: Take into account threads that are ready to run, by
896 sampling the "\System\Processor Queue Length" performance
897 counter. The code below accounts only for threads that are
900 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
902 ULARGE_INTEGER uidle
, ukernel
, uuser
;
904 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
905 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
906 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
907 *idle
= uidle
.QuadPart
;
908 *kernel
= ukernel
.QuadPart
;
909 *user
= uuser
.QuadPart
;
919 /* Produce the load average for a given time interval, using the
920 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
921 1-minute, 5-minute, or 15-minute average, respectively. */
925 double retval
= -1.0;
928 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
929 time_t now
= samples
[last_idx
].sample_time
;
931 if (first_idx
!= last_idx
)
933 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
935 tdiff
= difftime (now
, samples
[idx
].sample_time
);
936 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
939 samples
[last_idx
].kernel
+ samples
[last_idx
].user
940 - (samples
[idx
].kernel
+ samples
[idx
].user
);
941 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
943 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
946 if (idx
== first_idx
)
955 getloadavg (double loadavg
[], int nelem
)
958 ULONGLONG idle
, kernel
, user
;
959 time_t now
= time (NULL
);
961 /* Store another sample. We ignore samples that are less than 1 sec
963 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
965 sample_system_load (&idle
, &kernel
, &user
);
966 last_idx
= buf_next (last_idx
);
967 samples
[last_idx
].sample_time
= now
;
968 samples
[last_idx
].idle
= idle
;
969 samples
[last_idx
].kernel
= kernel
;
970 samples
[last_idx
].user
= user
;
971 /* If the buffer has more that 15 min worth of samples, discard
974 first_idx
= last_idx
;
975 while (first_idx
!= last_idx
976 && (difftime (now
, samples
[first_idx
].sample_time
)
977 >= 15.0*60 + 2*DBL_EPSILON
*now
))
978 first_idx
= buf_next (first_idx
);
981 for (elem
= 0; elem
< nelem
; elem
++)
983 double avg
= getavg (elem
);
993 /* Emulate getpwuid, getpwnam and others. */
995 #define PASSWD_FIELD_SIZE 256
997 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
998 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
999 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1000 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
1001 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
1003 static struct passwd dflt_passwd
=
1015 static char dflt_group_name
[GNLEN
+1];
1017 static struct group dflt_group
=
1019 /* When group information is not available, we return this as the
1020 group for all files. */
1028 return dflt_passwd
.pw_uid
;
1034 /* I could imagine arguing for checking to see whether the user is
1035 in the Administrators group and returning a UID of 0 for that
1036 case, but I don't know how wise that would be in the long run. */
1043 return dflt_passwd
.pw_gid
;
1053 getpwuid (unsigned uid
)
1055 if (uid
== dflt_passwd
.pw_uid
)
1056 return &dflt_passwd
;
1061 getgrgid (gid_t gid
)
1067 getpwnam (char *name
)
1071 pw
= getpwuid (getuid ());
1075 if (xstrcasecmp (name
, pw
->pw_name
))
1082 init_user_info (void)
1084 /* Find the user's real name by opening the process token and
1085 looking up the name associated with the user-sid in that token.
1087 Use the relative portion of the identifier authority value from
1088 the user-sid as the user id value (same for group id using the
1089 primary group sid from the process token). */
1091 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1092 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1093 DWORD glength
= sizeof (gname
);
1094 HANDLE token
= NULL
;
1095 SID_NAME_USE user_type
;
1096 unsigned char *buf
= NULL
;
1098 TOKEN_USER user_token
;
1099 TOKEN_PRIMARY_GROUP group_token
;
1102 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1105 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1106 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1108 buf
= xmalloc (blen
);
1109 result
= get_token_information (token
, TokenUser
,
1110 (LPVOID
)buf
, blen
, &needed
);
1113 memcpy (&user_token
, buf
, sizeof (user_token
));
1114 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1116 domain
, &dlength
, &user_type
);
1124 strcpy (dflt_passwd
.pw_name
, uname
);
1125 /* Determine a reasonable uid value. */
1126 if (xstrcasecmp ("administrator", uname
) == 0)
1128 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1129 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1133 /* Use the last sub-authority value of the RID, the relative
1134 portion of the SID, as user/group ID. */
1135 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1137 /* Get group id and name. */
1138 result
= get_token_information (token
, TokenPrimaryGroup
,
1139 (LPVOID
)buf
, blen
, &needed
);
1140 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1142 buf
= xrealloc (buf
, blen
= needed
);
1143 result
= get_token_information (token
, TokenPrimaryGroup
,
1144 (LPVOID
)buf
, blen
, &needed
);
1148 memcpy (&group_token
, buf
, sizeof (group_token
));
1149 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1150 dlength
= sizeof (domain
);
1151 /* If we can get at the real Primary Group name, use that.
1152 Otherwise, the default group name was already set to
1153 "None" in globals_of_w32. */
1154 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1155 gname
, &glength
, NULL
, &dlength
,
1157 strcpy (dflt_group_name
, gname
);
1160 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1163 /* If security calls are not supported (presumably because we
1164 are running under Windows 9X), fallback to this: */
1165 else if (GetUserName (uname
, &ulength
))
1167 strcpy (dflt_passwd
.pw_name
, uname
);
1168 if (xstrcasecmp ("administrator", uname
) == 0)
1169 dflt_passwd
.pw_uid
= 0;
1171 dflt_passwd
.pw_uid
= 123;
1172 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1176 strcpy (dflt_passwd
.pw_name
, "unknown");
1177 dflt_passwd
.pw_uid
= 123;
1178 dflt_passwd
.pw_gid
= 123;
1180 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1182 /* Ensure HOME and SHELL are defined. */
1183 if (getenv ("HOME") == NULL
)
1185 if (getenv ("SHELL") == NULL
)
1188 /* Set dir and shell from environment variables. */
1189 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1190 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1194 CloseHandle (token
);
1200 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1201 return ((rand () << 15) | rand ());
1211 /* Normalize filename by converting all path separators to
1212 the specified separator. Also conditionally convert upper
1213 case path name components to lower case. */
1216 normalize_filename (register char *fp
, char path_sep
)
1221 /* Always lower-case drive letters a-z, even if the filesystem
1222 preserves case in filenames.
1223 This is so filenames can be compared by string comparison
1224 functions that are case-sensitive. Even case-preserving filesystems
1225 do not distinguish case in drive letters. */
1226 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1232 if (NILP (Vw32_downcase_file_names
))
1236 if (*fp
== '/' || *fp
== '\\')
1243 sep
= path_sep
; /* convert to this path separator */
1244 elem
= fp
; /* start of current path element */
1247 if (*fp
>= 'a' && *fp
<= 'z')
1248 elem
= 0; /* don't convert this element */
1250 if (*fp
== 0 || *fp
== ':')
1252 sep
= *fp
; /* restore current separator (or 0) */
1253 *fp
= '/'; /* after conversion of this element */
1256 if (*fp
== '/' || *fp
== '\\')
1258 if (elem
&& elem
!= fp
)
1260 *fp
= 0; /* temporary end of string */
1261 _strlwr (elem
); /* while we convert to lower case */
1263 *fp
= sep
; /* convert (or restore) path separator */
1264 elem
= fp
+ 1; /* next element starts after separator */
1270 /* Destructively turn backslashes into slashes. */
1272 dostounix_filename (register char *p
)
1274 normalize_filename (p
, '/');
1277 /* Destructively turn slashes into backslashes. */
1279 unixtodos_filename (register char *p
)
1281 normalize_filename (p
, '\\');
1284 /* Remove all CR's that are followed by a LF.
1285 (From msdos.c...probably should figure out a way to share it,
1286 although this code isn't going to ever change.) */
1288 crlf_to_lf (register int n
, register unsigned char *buf
)
1290 unsigned char *np
= buf
;
1291 unsigned char *startp
= buf
;
1292 unsigned char *endp
= buf
+ n
;
1296 while (buf
< endp
- 1)
1300 if (*(++buf
) != 0x0a)
1311 /* Parse the root part of file name, if present. Return length and
1312 optionally store pointer to char after root. */
1314 parse_root (char * name
, char ** pPath
)
1316 char * start
= name
;
1321 /* find the root name of the volume if given */
1322 if (isalpha (name
[0]) && name
[1] == ':')
1324 /* skip past drive specifier */
1326 if (IS_DIRECTORY_SEP (name
[0]))
1329 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1335 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1340 if (IS_DIRECTORY_SEP (name
[0]))
1347 return name
- start
;
1350 /* Get long base name for name; name is assumed to be absolute. */
1352 get_long_basename (char * name
, char * buf
, int size
)
1354 WIN32_FIND_DATA find_data
;
1358 /* must be valid filename, no wild cards or other invalid characters */
1359 if (_mbspbrk (name
, "*?|<>\""))
1362 dir_handle
= FindFirstFile (name
, &find_data
);
1363 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1365 if ((len
= strlen (find_data
.cFileName
)) < size
)
1366 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1369 FindClose (dir_handle
);
1374 /* Get long name for file, if possible (assumed to be absolute). */
1376 w32_get_long_filename (char * name
, char * buf
, int size
)
1381 char full
[ MAX_PATH
];
1384 len
= strlen (name
);
1385 if (len
>= MAX_PATH
)
1388 /* Use local copy for destructive modification. */
1389 memcpy (full
, name
, len
+1);
1390 unixtodos_filename (full
);
1392 /* Copy root part verbatim. */
1393 len
= parse_root (full
, &p
);
1394 memcpy (o
, full
, len
);
1399 while (p
!= NULL
&& *p
)
1402 p
= strchr (q
, '\\');
1404 len
= get_long_basename (full
, o
, size
);
1427 is_unc_volume (const char *filename
)
1429 const char *ptr
= filename
;
1431 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1434 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1440 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1443 sigsetmask (int signal_mask
)
1461 sigunblock (int sig
)
1467 sigemptyset (sigset_t
*set
)
1473 sigaddset (sigset_t
*set
, int signo
)
1479 sigfillset (sigset_t
*set
)
1485 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1491 setpgrp (int pid
, int gid
)
1502 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1505 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1508 HKEY hrootkey
= NULL
;
1511 /* Check both the current user and the local machine to see if
1512 we have any resources. */
1514 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1518 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1519 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1520 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1522 RegCloseKey (hrootkey
);
1528 RegCloseKey (hrootkey
);
1531 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1535 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1536 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1537 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1539 RegCloseKey (hrootkey
);
1545 RegCloseKey (hrootkey
);
1551 char *get_emacs_configuration (void);
1552 extern Lisp_Object Vsystem_configuration
;
1555 init_environment (char ** argv
)
1557 static const char * const tempdirs
[] = {
1558 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1563 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1565 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1566 temporary files and assume "/tmp" if $TMPDIR is unset, which
1567 will break on DOS/Windows. Refuse to work if we cannot find
1568 a directory, not even "c:/", usable for that purpose. */
1569 for (i
= 0; i
< imax
; i
++)
1571 const char *tmp
= tempdirs
[i
];
1574 tmp
= getenv (tmp
+ 1);
1575 /* Note that `access' can lie to us if the directory resides on a
1576 read-only filesystem, like CD-ROM or a write-protected floppy.
1577 The only way to be really sure is to actually create a file and
1578 see if it succeeds. But I think that's too much to ask. */
1579 if (tmp
&& _access (tmp
, D_OK
) == 0)
1581 char * var
= alloca (strlen (tmp
) + 8);
1582 sprintf (var
, "TMPDIR=%s", tmp
);
1583 _putenv (strdup (var
));
1590 Fcons (build_string ("no usable temporary directories found!!"),
1592 "While setting TMPDIR: ");
1594 /* Check for environment variables and use registry settings if they
1595 don't exist. Fallback on default values where applicable. */
1600 char locale_name
[32];
1601 struct stat ignored
;
1602 char default_home
[MAX_PATH
];
1604 static const struct env_entry
1611 {"PRELOAD_WINSOCK", NULL
},
1612 {"emacs_dir", "C:/emacs"},
1613 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1614 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1615 {"EMACSDATA", "%emacs_dir%/etc"},
1616 {"EMACSPATH", "%emacs_dir%/bin"},
1617 /* We no longer set INFOPATH because Info-default-directory-list
1619 /* {"INFOPATH", "%emacs_dir%/info"}, */
1620 {"EMACSDOC", "%emacs_dir%/etc"},
1625 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1627 /* We need to copy dflt_envvars[] and work on the copy because we
1628 don't want the dumped Emacs to inherit the values of
1629 environment variables we saw during dumping (which could be on
1630 a different system). The defaults above must be left intact. */
1631 struct env_entry env_vars
[N_ENV_VARS
];
1633 for (i
= 0; i
< N_ENV_VARS
; i
++)
1634 env_vars
[i
] = dflt_envvars
[i
];
1636 /* For backwards compatibility, check if a .emacs file exists in C:/
1637 If not, then we can try to default to the appdata directory under the
1638 user's profile, which is more likely to be writable. */
1639 if (stat ("C:/.emacs", &ignored
) < 0)
1641 HRESULT profile_result
;
1642 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1643 of Windows 95 and NT4 that have not been updated to include
1645 ShGetFolderPath_fn get_folder_path
;
1646 get_folder_path
= (ShGetFolderPath_fn
)
1647 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1649 if (get_folder_path
!= NULL
)
1651 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1654 /* If we can't get the appdata dir, revert to old behavior. */
1655 if (profile_result
== S_OK
)
1656 env_vars
[0].def_value
= default_home
;
1660 /* Get default locale info and use it for LANG. */
1661 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1662 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1663 locale_name
, sizeof (locale_name
)))
1665 for (i
= 0; i
< N_ENV_VARS
; i
++)
1667 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1669 env_vars
[i
].def_value
= locale_name
;
1675 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1677 /* Treat emacs_dir specially: set it unconditionally based on our
1678 location, if it appears that we are running from the bin subdir
1679 of a standard installation. */
1682 char modname
[MAX_PATH
];
1684 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1686 if ((p
= strrchr (modname
, '\\')) == NULL
)
1690 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1692 char buf
[SET_ENV_BUF_SIZE
];
1695 for (p
= modname
; *p
; p
++)
1696 if (*p
== '\\') *p
= '/';
1698 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1699 _putenv (strdup (buf
));
1701 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1703 /* FIXME: should use substring of get_emacs_configuration ().
1704 But I don't think the Windows build supports alpha, mips etc
1705 anymore, so have taken the easy option for now. */
1706 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1709 p
= strrchr (modname
, '\\');
1713 p
= strrchr (modname
, '\\');
1714 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1716 char buf
[SET_ENV_BUF_SIZE
];
1719 for (p
= modname
; *p
; p
++)
1720 if (*p
== '\\') *p
= '/';
1722 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1723 _putenv (strdup (buf
));
1729 for (i
= 0; i
< N_ENV_VARS
; i
++)
1731 if (!getenv (env_vars
[i
].name
))
1735 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1736 /* Also ignore empty environment variables. */
1740 lpval
= env_vars
[i
].def_value
;
1741 dwType
= REG_EXPAND_SZ
;
1747 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1749 if (dwType
== REG_EXPAND_SZ
)
1750 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1751 else if (dwType
== REG_SZ
)
1752 strcpy (buf1
, lpval
);
1753 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1755 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1757 _putenv (strdup (buf2
));
1767 /* Rebuild system configuration to reflect invoking system. */
1768 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1770 /* Another special case: on NT, the PATH variable is actually named
1771 "Path" although cmd.exe (perhaps NT itself) arranges for
1772 environment variable lookup and setting to be case insensitive.
1773 However, Emacs assumes a fully case sensitive environment, so we
1774 need to change "Path" to "PATH" to match the expectations of
1775 various elisp packages. We do this by the sneaky method of
1776 modifying the string in the C runtime environ entry.
1778 The same applies to COMSPEC. */
1782 for (envp
= environ
; *envp
; envp
++)
1783 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1784 memcpy (*envp
, "PATH=", 5);
1785 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1786 memcpy (*envp
, "COMSPEC=", 8);
1789 /* Remember the initial working directory for getwd, then make the
1790 real wd be the location of emacs.exe to avoid conflicts when
1791 renaming or deleting directories. (We also don't call chdir when
1792 running subprocesses for the same reason.) */
1793 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1798 static char modname
[MAX_PATH
];
1800 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1802 if ((p
= strrchr (modname
, '\\')) == NULL
)
1806 SetCurrentDirectory (modname
);
1808 /* Ensure argv[0] has the full path to Emacs. */
1813 /* Determine if there is a middle mouse button, to allow parse_button
1814 to decide whether right mouse events should be mouse-2 or
1816 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1822 emacs_root_dir (void)
1824 static char root_dir
[FILENAME_MAX
];
1827 p
= getenv ("emacs_dir");
1830 strcpy (root_dir
, p
);
1831 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1832 dostounix_filename (root_dir
);
1836 /* We don't have scripts to automatically determine the system configuration
1837 for Emacs before it's compiled, and we don't want to have to make the
1838 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1842 get_emacs_configuration (void)
1844 char *arch
, *oem
, *os
;
1846 static char configuration_buffer
[32];
1848 /* Determine the processor type. */
1849 switch (get_processor_type ())
1852 #ifdef PROCESSOR_INTEL_386
1853 case PROCESSOR_INTEL_386
:
1854 case PROCESSOR_INTEL_486
:
1855 case PROCESSOR_INTEL_PENTIUM
:
1860 #ifdef PROCESSOR_MIPS_R2000
1861 case PROCESSOR_MIPS_R2000
:
1862 case PROCESSOR_MIPS_R3000
:
1863 case PROCESSOR_MIPS_R4000
:
1868 #ifdef PROCESSOR_ALPHA_21064
1869 case PROCESSOR_ALPHA_21064
:
1879 /* Use the OEM field to reflect the compiler/library combination. */
1881 #define COMPILER_NAME "msvc"
1884 #define COMPILER_NAME "mingw"
1886 #define COMPILER_NAME "unknown"
1889 oem
= COMPILER_NAME
;
1891 switch (osinfo_cache
.dwPlatformId
) {
1892 case VER_PLATFORM_WIN32_NT
:
1894 build_num
= osinfo_cache
.dwBuildNumber
;
1896 case VER_PLATFORM_WIN32_WINDOWS
:
1897 if (osinfo_cache
.dwMinorVersion
== 0) {
1902 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1904 case VER_PLATFORM_WIN32s
:
1905 /* Not supported, should not happen. */
1907 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1915 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1916 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1917 get_w32_major_version (), get_w32_minor_version (), build_num
);
1919 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1922 return configuration_buffer
;
1926 get_emacs_configuration_options (void)
1928 static char *options_buffer
;
1929 char cv
[32]; /* Enough for COMPILER_VERSION. */
1931 cv
, /* To be filled later. */
1935 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1936 with a starting space to save work here. */
1938 " --cflags", USER_CFLAGS
,
1941 " --ldflags", USER_LDFLAGS
,
1948 /* Work out the effective configure options for this build. */
1950 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1953 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1955 #define COMPILER_VERSION ""
1959 if (_snprintf (cv
, sizeof (cv
), COMPILER_VERSION
) < 0)
1960 return "Error: not enough space for compiler version";
1962 for (i
= 0; options
[i
]; i
++)
1963 size
+= strlen (options
[i
]);
1965 options_buffer
= xmalloc (size
+ 1);
1966 options_buffer
[0] = '\0';
1968 for (i
= 0; options
[i
]; i
++)
1969 strcat (options_buffer
, options
[i
]);
1971 return options_buffer
;
1975 #include <sys/timeb.h>
1977 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1979 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1984 tv
->tv_sec
= tb
.time
;
1985 tv
->tv_usec
= tb
.millitm
* 1000L;
1988 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1989 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1993 /* ------------------------------------------------------------------------- */
1994 /* IO support and wrapper functions for W32 API. */
1995 /* ------------------------------------------------------------------------- */
1997 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1998 on network directories, so we handle that case here.
1999 (Ulrich Leodolter, 1/11/95). */
2001 sys_ctime (const time_t *t
)
2003 char *str
= (char *) ctime (t
);
2004 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2007 /* Emulate sleep...we could have done this with a define, but that
2008 would necessitate including windows.h in the files that used it.
2009 This is much easier. */
2011 sys_sleep (int seconds
)
2013 Sleep (seconds
* 1000);
2016 /* Internal MSVC functions for low-level descriptor munging */
2017 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2018 extern int __cdecl
_free_osfhnd (int fd
);
2020 /* parallel array of private info on file handles */
2021 filedesc fd_info
[ MAXDESC
];
2023 typedef struct volume_info_data
{
2024 struct volume_info_data
* next
;
2026 /* time when info was obtained */
2029 /* actual volume info */
2038 /* Global referenced by various functions. */
2039 static volume_info_data volume_info
;
2041 /* Vector to indicate which drives are local and fixed (for which cached
2042 data never expires). */
2043 static BOOL fixed_drives
[26];
2045 /* Consider cached volume information to be stale if older than 10s,
2046 at least for non-local drives. Info for fixed drives is never stale. */
2047 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2048 #define VOLINFO_STILL_VALID( root_dir, info ) \
2049 ( ( isalpha (root_dir[0]) && \
2050 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2051 || GetTickCount () - info->timestamp < 10000 )
2053 /* Cache support functions. */
2055 /* Simple linked list with linear search is sufficient. */
2056 static volume_info_data
*volume_cache
= NULL
;
2058 static volume_info_data
*
2059 lookup_volume_info (char * root_dir
)
2061 volume_info_data
* info
;
2063 for (info
= volume_cache
; info
; info
= info
->next
)
2064 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2070 add_volume_info (char * root_dir
, volume_info_data
* info
)
2072 info
->root_dir
= xstrdup (root_dir
);
2073 info
->next
= volume_cache
;
2074 volume_cache
= info
;
2078 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2079 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2080 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2082 GetCachedVolumeInformation (char * root_dir
)
2084 volume_info_data
* info
;
2085 char default_root
[ MAX_PATH
];
2087 /* NULL for root_dir means use root from current directory. */
2088 if (root_dir
== NULL
)
2090 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2092 parse_root (default_root
, &root_dir
);
2094 root_dir
= default_root
;
2097 /* Local fixed drives can be cached permanently. Removable drives
2098 cannot be cached permanently, since the volume name and serial
2099 number (if nothing else) can change. Remote drives should be
2100 treated as if they are removable, since there is no sure way to
2101 tell whether they are or not. Also, the UNC association of drive
2102 letters mapped to remote volumes can be changed at any time (even
2103 by other processes) without notice.
2105 As a compromise, so we can benefit from caching info for remote
2106 volumes, we use a simple expiry mechanism to invalidate cache
2107 entries that are more than ten seconds old. */
2110 /* No point doing this, because WNetGetConnection is even slower than
2111 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2112 GetDriveType is about the only call of this type which does not
2113 involve network access, and so is extremely quick). */
2115 /* Map drive letter to UNC if remote. */
2116 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2118 char remote_name
[ 256 ];
2119 char drive
[3] = { root_dir
[0], ':' };
2121 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2123 /* do something */ ;
2127 info
= lookup_volume_info (root_dir
);
2129 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2137 /* Info is not cached, or is stale. */
2138 if (!GetVolumeInformation (root_dir
,
2139 name
, sizeof (name
),
2143 type
, sizeof (type
)))
2146 /* Cache the volume information for future use, overwriting existing
2147 entry if present. */
2150 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2151 add_volume_info (root_dir
, info
);
2159 info
->name
= xstrdup (name
);
2160 info
->serialnum
= serialnum
;
2161 info
->maxcomp
= maxcomp
;
2162 info
->flags
= flags
;
2163 info
->type
= xstrdup (type
);
2164 info
->timestamp
= GetTickCount ();
2170 /* Get information on the volume where name is held; set path pointer to
2171 start of pathname in name (past UNC header\volume header if present). */
2173 get_volume_info (const char * name
, const char ** pPath
)
2175 char temp
[MAX_PATH
];
2176 char *rootname
= NULL
; /* default to current volume */
2177 volume_info_data
* info
;
2182 /* find the root name of the volume if given */
2183 if (isalpha (name
[0]) && name
[1] == ':')
2191 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2198 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2211 info
= GetCachedVolumeInformation (rootname
);
2214 /* Set global referenced by other functions. */
2215 volume_info
= *info
;
2221 /* Determine if volume is FAT format (ie. only supports short 8.3
2222 names); also set path pointer to start of pathname in name. */
2224 is_fat_volume (const char * name
, const char ** pPath
)
2226 if (get_volume_info (name
, pPath
))
2227 return (volume_info
.maxcomp
== 12);
2231 /* Map filename to a valid 8.3 name if necessary. */
2233 map_w32_filename (const char * name
, const char ** pPath
)
2235 static char shortname
[MAX_PATH
];
2236 char * str
= shortname
;
2239 const char * save_name
= name
;
2241 if (strlen (name
) >= MAX_PATH
)
2243 /* Return a filename which will cause callers to fail. */
2244 strcpy (shortname
, "?");
2248 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2250 register int left
= 8; /* maximum number of chars in part */
2251 register int extn
= 0; /* extension added? */
2252 register int dots
= 2; /* maximum number of dots allowed */
2255 *str
++ = *name
++; /* skip past UNC header */
2257 while ((c
= *name
++))
2264 extn
= 0; /* reset extension flags */
2265 dots
= 2; /* max 2 dots */
2266 left
= 8; /* max length 8 for main part */
2270 extn
= 0; /* reset extension flags */
2271 dots
= 2; /* max 2 dots */
2272 left
= 8; /* max length 8 for main part */
2277 /* Convert path components of the form .xxx to _xxx,
2278 but leave . and .. as they are. This allows .emacs
2279 to be read as _emacs, for example. */
2283 IS_DIRECTORY_SEP (*name
))
2298 extn
= 1; /* we've got an extension */
2299 left
= 3; /* 3 chars in extension */
2303 /* any embedded dots after the first are converted to _ */
2308 case '#': /* don't lose these, they're important */
2310 str
[-1] = c
; /* replace last character of part */
2315 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2317 dots
= 0; /* started a path component */
2326 strcpy (shortname
, name
);
2327 unixtodos_filename (shortname
);
2331 *pPath
= shortname
+ (path
- save_name
);
2337 is_exec (const char * name
)
2339 char * p
= strrchr (name
, '.');
2342 && (xstrcasecmp (p
, ".exe") == 0 ||
2343 xstrcasecmp (p
, ".com") == 0 ||
2344 xstrcasecmp (p
, ".bat") == 0 ||
2345 xstrcasecmp (p
, ".cmd") == 0));
2348 /* Emulate the Unix directory procedures opendir, closedir,
2349 and readdir. We can't use the procedures supplied in sysdep.c,
2350 so we provide them here. */
2352 struct direct dir_static
; /* simulated directory contents */
2353 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2354 static int dir_is_fat
;
2355 static char dir_pathname
[MAXPATHLEN
+1];
2356 static WIN32_FIND_DATA dir_find_data
;
2358 /* Support shares on a network resource as subdirectories of a read-only
2360 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2361 HANDLE
open_unc_volume (const char *);
2362 char *read_unc_volume (HANDLE
, char *, int);
2363 void close_unc_volume (HANDLE
);
2366 opendir (char *filename
)
2370 /* Opening is done by FindFirstFile. However, a read is inherent to
2371 this operation, so we defer the open until read time. */
2373 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2375 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2378 if (is_unc_volume (filename
))
2380 wnet_enum_handle
= open_unc_volume (filename
);
2381 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2385 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2392 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2393 dir_pathname
[MAXPATHLEN
] = '\0';
2394 dir_is_fat
= is_fat_volume (filename
, NULL
);
2400 closedir (DIR *dirp
)
2402 /* If we have a find-handle open, close it. */
2403 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2405 FindClose (dir_find_handle
);
2406 dir_find_handle
= INVALID_HANDLE_VALUE
;
2408 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2410 close_unc_volume (wnet_enum_handle
);
2411 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2413 xfree ((char *) dirp
);
2419 int downcase
= !NILP (Vw32_downcase_file_names
);
2421 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2423 if (!read_unc_volume (wnet_enum_handle
,
2424 dir_find_data
.cFileName
,
2428 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2429 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2431 char filename
[MAXNAMLEN
+ 3];
2434 strcpy (filename
, dir_pathname
);
2435 ln
= strlen (filename
) - 1;
2436 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2437 strcat (filename
, "\\");
2438 strcat (filename
, "*");
2440 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2442 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2447 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2451 /* Emacs never uses this value, so don't bother making it match
2452 value returned by stat(). */
2453 dir_static
.d_ino
= 1;
2455 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2457 /* If the file name in cFileName[] includes `?' characters, it means
2458 the original file name used characters that cannot be represented
2459 by the current ANSI codepage. To avoid total lossage, retrieve
2460 the short 8+3 alias of the long file name. */
2461 if (_mbspbrk (dir_static
.d_name
, "?"))
2463 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2464 downcase
= 1; /* 8+3 aliases are returned in all caps */
2466 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2467 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2468 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2470 /* If the file name in cFileName[] includes `?' characters, it means
2471 the original file name used characters that cannot be represented
2472 by the current ANSI codepage. To avoid total lossage, retrieve
2473 the short 8+3 alias of the long file name. */
2474 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2476 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2477 /* 8+3 aliases are returned in all caps, which could break
2478 various alists that look at filenames' extensions. */
2482 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2483 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2485 _strlwr (dir_static
.d_name
);
2489 for (p
= dir_static
.d_name
; *p
; p
++)
2490 if (*p
>= 'a' && *p
<= 'z')
2493 _strlwr (dir_static
.d_name
);
2500 open_unc_volume (const char *path
)
2506 nr
.dwScope
= RESOURCE_GLOBALNET
;
2507 nr
.dwType
= RESOURCETYPE_DISK
;
2508 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2509 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2510 nr
.lpLocalName
= NULL
;
2511 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2512 nr
.lpComment
= NULL
;
2513 nr
.lpProvider
= NULL
;
2515 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2516 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2518 if (result
== NO_ERROR
)
2521 return INVALID_HANDLE_VALUE
;
2525 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2529 DWORD bufsize
= 512;
2534 buffer
= alloca (bufsize
);
2535 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2536 if (result
!= NO_ERROR
)
2539 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2540 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2542 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2545 strncpy (readbuf
, ptr
, size
);
2550 close_unc_volume (HANDLE henum
)
2552 if (henum
!= INVALID_HANDLE_VALUE
)
2553 WNetCloseEnum (henum
);
2557 unc_volume_file_attributes (const char *path
)
2562 henum
= open_unc_volume (path
);
2563 if (henum
== INVALID_HANDLE_VALUE
)
2566 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2568 close_unc_volume (henum
);
2573 /* Ensure a network connection is authenticated. */
2575 logon_network_drive (const char *path
)
2577 NETRESOURCE resource
;
2578 char share
[MAX_PATH
];
2583 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2584 drvtype
= DRIVE_REMOTE
;
2585 else if (path
[0] == '\0' || path
[1] != ':')
2586 drvtype
= GetDriveType (NULL
);
2593 drvtype
= GetDriveType (drive
);
2596 /* Only logon to networked drives. */
2597 if (drvtype
!= DRIVE_REMOTE
)
2601 strncpy (share
, path
, MAX_PATH
);
2602 /* Truncate to just server and share name. */
2603 for (i
= 2; i
< MAX_PATH
; i
++)
2605 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2612 resource
.dwType
= RESOURCETYPE_DISK
;
2613 resource
.lpLocalName
= NULL
;
2614 resource
.lpRemoteName
= share
;
2615 resource
.lpProvider
= NULL
;
2617 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2620 /* Shadow some MSVC runtime functions to map requests for long filenames
2621 to reasonable short names if necessary. This was originally added to
2622 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2626 sys_access (const char * path
, int mode
)
2630 /* MSVC implementation doesn't recognize D_OK. */
2631 path
= map_w32_filename (path
, NULL
);
2632 if (is_unc_volume (path
))
2634 attributes
= unc_volume_file_attributes (path
);
2635 if (attributes
== -1) {
2640 else if ((attributes
= GetFileAttributes (path
)) == -1)
2642 /* Should try mapping GetLastError to errno; for now just indicate
2643 that path doesn't exist. */
2647 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2652 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2657 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2666 sys_chdir (const char * path
)
2668 return _chdir (map_w32_filename (path
, NULL
));
2672 sys_chmod (const char * path
, int mode
)
2674 return _chmod (map_w32_filename (path
, NULL
), mode
);
2678 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2680 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2686 sys_creat (const char * path
, int mode
)
2688 return _creat (map_w32_filename (path
, NULL
), mode
);
2692 sys_fopen (const char * path
, const char * mode
)
2696 const char * mode_save
= mode
;
2698 /* Force all file handles to be non-inheritable. This is necessary to
2699 ensure child processes don't unwittingly inherit handles that might
2700 prevent future file access. */
2704 else if (mode
[0] == 'w' || mode
[0] == 'a')
2705 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2709 /* Only do simplistic option parsing. */
2713 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2716 else if (mode
[0] == 'b')
2721 else if (mode
[0] == 't')
2728 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2732 return _fdopen (fd
, mode_save
);
2735 /* This only works on NTFS volumes, but is useful to have. */
2737 sys_link (const char * old
, const char * new)
2741 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2743 if (old
== NULL
|| new == NULL
)
2749 strcpy (oldname
, map_w32_filename (old
, NULL
));
2750 strcpy (newname
, map_w32_filename (new, NULL
));
2752 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2753 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2754 if (fileh
!= INVALID_HANDLE_VALUE
)
2758 /* Confusingly, the "alternate" stream name field does not apply
2759 when restoring a hard link, and instead contains the actual
2760 stream data for the link (ie. the name of the link to create).
2761 The WIN32_STREAM_ID structure before the cStreamName field is
2762 the stream header, which is then immediately followed by the
2766 WIN32_STREAM_ID wid
;
2767 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2770 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2771 data
.wid
.cStreamName
, MAX_PATH
);
2774 LPVOID context
= NULL
;
2777 data
.wid
.dwStreamId
= BACKUP_LINK
;
2778 data
.wid
.dwStreamAttributes
= 0;
2779 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2780 data
.wid
.Size
.HighPart
= 0;
2781 data
.wid
.dwStreamNameSize
= 0;
2783 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2784 offsetof (WIN32_STREAM_ID
, cStreamName
)
2785 + data
.wid
.Size
.LowPart
,
2786 &wbytes
, FALSE
, FALSE
, &context
)
2787 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2794 /* Should try mapping GetLastError to errno; for now just
2795 indicate a general error (eg. links not supported). */
2796 errno
= EINVAL
; // perhaps EMLINK?
2800 CloseHandle (fileh
);
2809 sys_mkdir (const char * path
)
2811 return _mkdir (map_w32_filename (path
, NULL
));
2814 /* Because of long name mapping issues, we need to implement this
2815 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2816 a unique name, instead of setting the input template to an empty
2819 Standard algorithm seems to be use pid or tid with a letter on the
2820 front (in place of the 6 X's) and cycle through the letters to find a
2821 unique name. We extend that to allow any reasonable character as the
2822 first of the 6 X's. */
2824 sys_mktemp (char * template)
2828 unsigned uid
= GetCurrentThreadId ();
2829 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2831 if (template == NULL
)
2833 p
= template + strlen (template);
2835 /* replace up to the last 5 X's with uid in decimal */
2836 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2838 p
[0] = '0' + uid
% 10;
2842 if (i
< 0 && p
[0] == 'X')
2847 int save_errno
= errno
;
2848 p
[0] = first_char
[i
];
2849 if (sys_access (template, 0) < 0)
2855 while (++i
< sizeof (first_char
));
2858 /* Template is badly formed or else we can't generate a unique name,
2859 so return empty string */
2865 sys_open (const char * path
, int oflag
, int mode
)
2867 const char* mpath
= map_w32_filename (path
, NULL
);
2868 /* Try to open file without _O_CREAT, to be able to write to hidden
2869 and system files. Force all file handles to be
2871 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2874 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2878 sys_rename (const char * oldname
, const char * newname
)
2881 char temp
[MAX_PATH
];
2883 /* MoveFile on Windows 95 doesn't correctly change the short file name
2884 alias in a number of circumstances (it is not easy to predict when
2885 just by looking at oldname and newname, unfortunately). In these
2886 cases, renaming through a temporary name avoids the problem.
2888 A second problem on Windows 95 is that renaming through a temp name when
2889 newname is uppercase fails (the final long name ends up in
2890 lowercase, although the short alias might be uppercase) UNLESS the
2891 long temp name is not 8.3.
2893 So, on Windows 95 we always rename through a temp name, and we make sure
2894 the temp name has a long extension to ensure correct renaming. */
2896 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2898 if (os_subtype
== OS_WIN95
)
2904 oldname
= map_w32_filename (oldname
, NULL
);
2905 if (o
= strrchr (oldname
, '\\'))
2908 o
= (char *) oldname
;
2910 if (p
= strrchr (temp
, '\\'))
2917 /* Force temp name to require a manufactured 8.3 alias - this
2918 seems to make the second rename work properly. */
2919 sprintf (p
, "_.%s.%u", o
, i
);
2921 result
= rename (oldname
, temp
);
2923 /* This loop must surely terminate! */
2924 while (result
< 0 && errno
== EEXIST
);
2929 /* Emulate Unix behavior - newname is deleted if it already exists
2930 (at least if it is a file; don't do this for directories).
2932 Since we mustn't do this if we are just changing the case of the
2933 file name (we would end up deleting the file we are trying to
2934 rename!), we let rename detect if the destination file already
2935 exists - that way we avoid the possible pitfalls of trying to
2936 determine ourselves whether two names really refer to the same
2937 file, which is not always possible in the general case. (Consider
2938 all the permutations of shared or subst'd drives, etc.) */
2940 newname
= map_w32_filename (newname
, NULL
);
2941 result
= rename (temp
, newname
);
2945 && _chmod (newname
, 0666) == 0
2946 && _unlink (newname
) == 0)
2947 result
= rename (temp
, newname
);
2953 sys_rmdir (const char * path
)
2955 return _rmdir (map_w32_filename (path
, NULL
));
2959 sys_unlink (const char * path
)
2961 path
= map_w32_filename (path
, NULL
);
2963 /* On Unix, unlink works without write permission. */
2964 _chmod (path
, 0666);
2965 return _unlink (path
);
2968 static FILETIME utc_base_ft
;
2969 static ULONGLONG utc_base
; /* In 100ns units */
2970 static int init
= 0;
2972 #define FILETIME_TO_U64(result, ft) \
2974 ULARGE_INTEGER uiTemp; \
2975 uiTemp.LowPart = (ft).dwLowDateTime; \
2976 uiTemp.HighPart = (ft).dwHighDateTime; \
2977 result = uiTemp.QuadPart; \
2981 initialize_utc_base (void)
2983 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2992 st
.wMilliseconds
= 0;
2994 SystemTimeToFileTime (&st
, &utc_base_ft
);
2995 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2999 convert_time (FILETIME ft
)
3005 initialize_utc_base();
3009 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3012 FILETIME_TO_U64 (tmp
, ft
);
3013 return (time_t) ((tmp
- utc_base
) / 10000000L);
3018 convert_from_time_t (time_t time
, FILETIME
* pft
)
3024 initialize_utc_base ();
3028 /* time in 100ns units since 1-Jan-1601 */
3029 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3030 pft
->dwHighDateTime
= tmp
.HighPart
;
3031 pft
->dwLowDateTime
= tmp
.LowPart
;
3035 /* No reason to keep this; faking inode values either by hashing or even
3036 using the file index from GetInformationByHandle, is not perfect and
3037 so by default Emacs doesn't use the inode values on Windows.
3038 Instead, we now determine file-truename correctly (except for
3039 possible drive aliasing etc). */
3041 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3043 hashval (const unsigned char * str
)
3048 h
= (h
<< 4) + *str
++;
3054 /* Return the hash value of the canonical pathname, excluding the
3055 drive/UNC header, to get a hopefully unique inode number. */
3057 generate_inode_val (const char * name
)
3059 char fullname
[ MAX_PATH
];
3063 /* Get the truly canonical filename, if it exists. (Note: this
3064 doesn't resolve aliasing due to subst commands, or recognise hard
3066 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3069 parse_root (fullname
, &p
);
3070 /* Normal W32 filesystems are still case insensitive. */
3077 static PSECURITY_DESCRIPTOR
3078 get_file_security_desc (const char *fname
)
3080 PSECURITY_DESCRIPTOR psd
= NULL
;
3082 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3083 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3085 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3087 err
= GetLastError ();
3088 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3092 psd
= xmalloc (sd_len
);
3093 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3105 unsigned n_subauthorities
;
3107 /* Use the last sub-authority value of the RID, the relative
3108 portion of the SID, as user/group ID. */
3109 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3110 if (n_subauthorities
< 1)
3111 return 0; /* the "World" RID */
3112 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3115 /* Caching SID and account values for faster lokup. */
3118 # define FLEXIBLE_ARRAY_MEMBER
3120 # define FLEXIBLE_ARRAY_MEMBER 1
3125 struct w32_id
*next
;
3127 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3130 static struct w32_id
*w32_idlist
;
3133 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3135 struct w32_id
*tail
, *found
;
3137 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3139 if (equal_sid ((PSID
)tail
->sid
, sid
))
3148 strcpy (name
, found
->name
);
3156 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3159 struct w32_id
*new_entry
;
3161 /* We don't want to leave behind stale cache from when Emacs was
3165 sid_len
= get_length_sid (sid
);
3166 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3169 new_entry
->rid
= id
;
3170 strcpy (new_entry
->name
, name
);
3171 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3172 new_entry
->next
= w32_idlist
;
3173 w32_idlist
= new_entry
;
3182 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3183 unsigned *id
, char *nm
, int what
)
3186 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3188 SID_NAME_USE ignore
;
3190 DWORD name_len
= sizeof (name
);
3192 DWORD domain_len
= sizeof (domain
);
3198 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3199 else if (what
== GID
)
3200 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3204 if (!result
|| !is_valid_sid (sid
))
3206 else if (!w32_cached_id (sid
, id
, nm
))
3208 /* If FNAME is a UNC, we need to lookup account on the
3209 specified machine. */
3210 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3211 && fname
[2] != '\0')
3216 for (s
= fname
+ 2, p
= machine
;
3217 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3223 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3224 domain
, &domain_len
, &ignore
)
3225 || name_len
> UNLEN
+1)
3229 *id
= get_rid (sid
);
3231 w32_add_to_cache (sid
, *id
, name
);
3238 get_file_owner_and_group (
3239 PSECURITY_DESCRIPTOR psd
,
3243 int dflt_usr
= 0, dflt_grp
= 0;
3252 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3254 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3257 /* Consider files to belong to current user/group, if we cannot get
3258 more accurate information. */
3261 st
->st_uid
= dflt_passwd
.pw_uid
;
3262 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3266 st
->st_gid
= dflt_passwd
.pw_gid
;
3267 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3271 /* Return non-zero if NAME is a potentially slow filesystem. */
3273 is_slow_fs (const char *name
)
3278 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3279 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3280 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3281 devtype
= GetDriveType (NULL
); /* use root of current drive */
3284 /* GetDriveType needs the root directory of the drive. */
3285 strncpy (drive_root
, name
, 2);
3286 drive_root
[2] = '\\';
3287 drive_root
[3] = '\0';
3288 devtype
= GetDriveType (drive_root
);
3290 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3293 /* MSVC stat function can't cope with UNC names and has other bugs, so
3294 replace it with our own. This also allows us to calculate consistent
3295 inode values without hacks in the main Emacs code. */
3297 stat (const char * path
, struct stat
* buf
)
3302 WIN32_FIND_DATA wfd
;
3304 unsigned __int64 fake_inode
;
3307 int rootdir
= FALSE
;
3308 PSECURITY_DESCRIPTOR psd
= NULL
;
3310 if (path
== NULL
|| buf
== NULL
)
3316 name
= (char *) map_w32_filename (path
, &path
);
3317 /* Must be valid filename, no wild cards or other invalid
3318 characters. We use _mbspbrk to support multibyte strings that
3319 might look to strpbrk as if they included literal *, ?, and other
3320 characters mentioned below that are disallowed by Windows
3322 if (_mbspbrk (name
, "*?|<>\""))
3328 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3329 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3330 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3335 /* Remove trailing directory separator, unless name is the root
3336 directory of a drive or UNC volume in which case ensure there
3337 is a trailing separator. */
3338 len
= strlen (name
);
3339 rootdir
= (path
>= name
+ len
- 1
3340 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3341 name
= strcpy (alloca (len
+ 2), name
);
3343 if (is_unc_volume (name
))
3345 DWORD attrs
= unc_volume_file_attributes (name
);
3350 memset (&wfd
, 0, sizeof (wfd
));
3351 wfd
.dwFileAttributes
= attrs
;
3352 wfd
.ftCreationTime
= utc_base_ft
;
3353 wfd
.ftLastAccessTime
= utc_base_ft
;
3354 wfd
.ftLastWriteTime
= utc_base_ft
;
3355 strcpy (wfd
.cFileName
, name
);
3359 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3360 strcat (name
, "\\");
3361 if (GetDriveType (name
) < 2)
3366 memset (&wfd
, 0, sizeof (wfd
));
3367 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3368 wfd
.ftCreationTime
= utc_base_ft
;
3369 wfd
.ftLastAccessTime
= utc_base_ft
;
3370 wfd
.ftLastWriteTime
= utc_base_ft
;
3371 strcpy (wfd
.cFileName
, name
);
3375 if (IS_DIRECTORY_SEP (name
[len
-1]))
3378 /* (This is hacky, but helps when doing file completions on
3379 network drives.) Optimize by using information available from
3380 active readdir if possible. */
3381 len
= strlen (dir_pathname
);
3382 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3384 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3385 && strnicmp (name
, dir_pathname
, len
) == 0
3386 && IS_DIRECTORY_SEP (name
[len
])
3387 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3389 /* This was the last entry returned by readdir. */
3390 wfd
= dir_find_data
;
3394 logon_network_drive (name
);
3396 fh
= FindFirstFile (name
, &wfd
);
3397 if (fh
== INVALID_HANDLE_VALUE
)
3406 if (!(NILP (Vw32_get_true_file_attributes
)
3407 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3408 /* No access rights required to get info. */
3409 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3410 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3411 != INVALID_HANDLE_VALUE
)
3413 /* This is more accurate in terms of gettting the correct number
3414 of links, but is quite slow (it is noticeable when Emacs is
3415 making a list of file name completions). */
3416 BY_HANDLE_FILE_INFORMATION info
;
3418 if (GetFileInformationByHandle (fh
, &info
))
3420 buf
->st_nlink
= info
.nNumberOfLinks
;
3421 /* Might as well use file index to fake inode values, but this
3422 is not guaranteed to be unique unless we keep a handle open
3423 all the time (even then there are situations where it is
3424 not unique). Reputedly, there are at most 48 bits of info
3425 (on NTFS, presumably less on FAT). */
3426 fake_inode
= info
.nFileIndexHigh
;
3428 fake_inode
+= info
.nFileIndexLow
;
3436 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3438 buf
->st_mode
= S_IFDIR
;
3442 switch (GetFileType (fh
))
3444 case FILE_TYPE_DISK
:
3445 buf
->st_mode
= S_IFREG
;
3447 case FILE_TYPE_PIPE
:
3448 buf
->st_mode
= S_IFIFO
;
3450 case FILE_TYPE_CHAR
:
3451 case FILE_TYPE_UNKNOWN
:
3453 buf
->st_mode
= S_IFCHR
;
3457 psd
= get_file_security_desc (name
);
3458 get_file_owner_and_group (psd
, name
, buf
);
3462 /* Don't bother to make this information more accurate. */
3463 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3468 get_file_owner_and_group (NULL
, name
, buf
);
3473 /* Not sure if there is any point in this. */
3474 if (!NILP (Vw32_generate_fake_inodes
))
3475 fake_inode
= generate_inode_val (name
);
3476 else if (fake_inode
== 0)
3478 /* For want of something better, try to make everything unique. */
3479 static DWORD gen_num
= 0;
3480 fake_inode
= ++gen_num
;
3484 /* MSVC defines _ino_t to be short; other libc's might not. */
3485 if (sizeof (buf
->st_ino
) == 2)
3486 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3488 buf
->st_ino
= fake_inode
;
3490 /* volume_info is set indirectly by map_w32_filename */
3491 buf
->st_dev
= volume_info
.serialnum
;
3492 buf
->st_rdev
= volume_info
.serialnum
;
3495 buf
->st_size
= wfd
.nFileSizeHigh
;
3496 buf
->st_size
<<= 32;
3497 buf
->st_size
+= wfd
.nFileSizeLow
;
3499 /* Convert timestamps to Unix format. */
3500 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3501 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3502 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3503 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3504 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3506 /* determine rwx permissions */
3507 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3508 permission
= S_IREAD
;
3510 permission
= S_IREAD
| S_IWRITE
;
3512 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3513 permission
|= S_IEXEC
;
3514 else if (is_exec (name
))
3515 permission
|= S_IEXEC
;
3517 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3522 /* Provide fstat and utime as well as stat for consistent handling of
3525 fstat (int desc
, struct stat
* buf
)
3527 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3528 BY_HANDLE_FILE_INFORMATION info
;
3529 unsigned __int64 fake_inode
;
3532 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3534 case FILE_TYPE_DISK
:
3535 buf
->st_mode
= S_IFREG
;
3536 if (!GetFileInformationByHandle (fh
, &info
))
3542 case FILE_TYPE_PIPE
:
3543 buf
->st_mode
= S_IFIFO
;
3545 case FILE_TYPE_CHAR
:
3546 case FILE_TYPE_UNKNOWN
:
3548 buf
->st_mode
= S_IFCHR
;
3550 memset (&info
, 0, sizeof (info
));
3551 info
.dwFileAttributes
= 0;
3552 info
.ftCreationTime
= utc_base_ft
;
3553 info
.ftLastAccessTime
= utc_base_ft
;
3554 info
.ftLastWriteTime
= utc_base_ft
;
3557 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3558 buf
->st_mode
= S_IFDIR
;
3560 buf
->st_nlink
= info
.nNumberOfLinks
;
3561 /* Might as well use file index to fake inode values, but this
3562 is not guaranteed to be unique unless we keep a handle open
3563 all the time (even then there are situations where it is
3564 not unique). Reputedly, there are at most 48 bits of info
3565 (on NTFS, presumably less on FAT). */
3566 fake_inode
= info
.nFileIndexHigh
;
3568 fake_inode
+= info
.nFileIndexLow
;
3570 /* MSVC defines _ino_t to be short; other libc's might not. */
3571 if (sizeof (buf
->st_ino
) == 2)
3572 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3574 buf
->st_ino
= fake_inode
;
3576 /* Consider files to belong to current user.
3577 FIXME: this should use GetSecurityInfo API, but it is only
3578 available for _WIN32_WINNT >= 0x501. */
3579 buf
->st_uid
= dflt_passwd
.pw_uid
;
3580 buf
->st_gid
= dflt_passwd
.pw_gid
;
3581 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3582 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3584 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3585 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3587 buf
->st_size
= info
.nFileSizeHigh
;
3588 buf
->st_size
<<= 32;
3589 buf
->st_size
+= info
.nFileSizeLow
;
3591 /* Convert timestamps to Unix format. */
3592 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3593 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3594 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3595 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3596 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3598 /* determine rwx permissions */
3599 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3600 permission
= S_IREAD
;
3602 permission
= S_IREAD
| S_IWRITE
;
3604 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3605 permission
|= S_IEXEC
;
3608 #if 0 /* no way of knowing the filename */
3609 char * p
= strrchr (name
, '.');
3611 (xstrcasecmp (p
, ".exe") == 0 ||
3612 xstrcasecmp (p
, ".com") == 0 ||
3613 xstrcasecmp (p
, ".bat") == 0 ||
3614 xstrcasecmp (p
, ".cmd") == 0))
3615 permission
|= S_IEXEC
;
3619 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3625 utime (const char *name
, struct utimbuf
*times
)
3627 struct utimbuf deftime
;
3634 deftime
.modtime
= deftime
.actime
= time (NULL
);
3638 /* Need write access to set times. */
3639 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3640 0, OPEN_EXISTING
, 0, NULL
);
3643 convert_from_time_t (times
->actime
, &atime
);
3644 convert_from_time_t (times
->modtime
, &mtime
);
3645 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3662 /* Support for browsing other processes and their attributes. See
3663 process.c for the Lisp bindings. */
3665 /* Helper wrapper functions. */
3667 HANDLE WINAPI
create_toolhelp32_snapshot (
3671 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3673 if (g_b_init_create_toolhelp32_snapshot
== 0)
3675 g_b_init_create_toolhelp32_snapshot
= 1;
3676 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3677 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3678 "CreateToolhelp32Snapshot");
3680 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3682 return INVALID_HANDLE_VALUE
;
3684 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3687 BOOL WINAPI
process32_first (
3689 LPPROCESSENTRY32 lppe
)
3691 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3693 if (g_b_init_process32_first
== 0)
3695 g_b_init_process32_first
= 1;
3696 s_pfn_Process32_First
= (Process32First_Proc
)
3697 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3700 if (s_pfn_Process32_First
== NULL
)
3704 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3707 BOOL WINAPI
process32_next (
3709 LPPROCESSENTRY32 lppe
)
3711 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3713 if (g_b_init_process32_next
== 0)
3715 g_b_init_process32_next
= 1;
3716 s_pfn_Process32_Next
= (Process32Next_Proc
)
3717 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3720 if (s_pfn_Process32_Next
== NULL
)
3724 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3727 BOOL WINAPI
open_thread_token (
3728 HANDLE ThreadHandle
,
3729 DWORD DesiredAccess
,
3731 PHANDLE TokenHandle
)
3733 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3734 HMODULE hm_advapi32
= NULL
;
3735 if (is_windows_9x () == TRUE
)
3737 SetLastError (ERROR_NOT_SUPPORTED
);
3740 if (g_b_init_open_thread_token
== 0)
3742 g_b_init_open_thread_token
= 1;
3743 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3744 s_pfn_Open_Thread_Token
=
3745 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3747 if (s_pfn_Open_Thread_Token
== NULL
)
3749 SetLastError (ERROR_NOT_SUPPORTED
);
3753 s_pfn_Open_Thread_Token (
3761 BOOL WINAPI
impersonate_self (
3762 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3764 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3765 HMODULE hm_advapi32
= NULL
;
3766 if (is_windows_9x () == TRUE
)
3770 if (g_b_init_impersonate_self
== 0)
3772 g_b_init_impersonate_self
= 1;
3773 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3774 s_pfn_Impersonate_Self
=
3775 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3777 if (s_pfn_Impersonate_Self
== NULL
)
3781 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3784 BOOL WINAPI
revert_to_self (void)
3786 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3787 HMODULE hm_advapi32
= NULL
;
3788 if (is_windows_9x () == TRUE
)
3792 if (g_b_init_revert_to_self
== 0)
3794 g_b_init_revert_to_self
= 1;
3795 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3796 s_pfn_Revert_To_Self
=
3797 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3799 if (s_pfn_Revert_To_Self
== NULL
)
3803 return s_pfn_Revert_To_Self ();
3806 BOOL WINAPI
get_process_memory_info (
3808 PPROCESS_MEMORY_COUNTERS mem_counters
,
3811 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3812 HMODULE hm_psapi
= NULL
;
3813 if (is_windows_9x () == TRUE
)
3817 if (g_b_init_get_process_memory_info
== 0)
3819 g_b_init_get_process_memory_info
= 1;
3820 hm_psapi
= LoadLibrary ("Psapi.dll");
3822 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3823 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3825 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3829 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3832 BOOL WINAPI
get_process_working_set_size (
3837 static GetProcessWorkingSetSize_Proc
3838 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3840 if (is_windows_9x () == TRUE
)
3844 if (g_b_init_get_process_working_set_size
== 0)
3846 g_b_init_get_process_working_set_size
= 1;
3847 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3848 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3849 "GetProcessWorkingSetSize");
3851 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3855 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3858 BOOL WINAPI
global_memory_status (
3861 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3863 if (is_windows_9x () == TRUE
)
3867 if (g_b_init_global_memory_status
== 0)
3869 g_b_init_global_memory_status
= 1;
3870 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3871 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3872 "GlobalMemoryStatus");
3874 if (s_pfn_Global_Memory_Status
== NULL
)
3878 return s_pfn_Global_Memory_Status (buf
);
3881 BOOL WINAPI
global_memory_status_ex (
3882 MEMORY_STATUS_EX
*buf
)
3884 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3886 if (is_windows_9x () == TRUE
)
3890 if (g_b_init_global_memory_status_ex
== 0)
3892 g_b_init_global_memory_status_ex
= 1;
3893 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3894 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3895 "GlobalMemoryStatusEx");
3897 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3901 return s_pfn_Global_Memory_Status_Ex (buf
);
3905 list_system_processes (void)
3907 struct gcpro gcpro1
;
3908 Lisp_Object proclist
= Qnil
;
3911 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3913 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3915 PROCESSENTRY32 proc_entry
;
3921 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3922 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3923 res
= process32_next (h_snapshot
, &proc_entry
))
3925 proc_id
= proc_entry
.th32ProcessID
;
3926 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3929 CloseHandle (h_snapshot
);
3931 proclist
= Fnreverse (proclist
);
3938 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3940 TOKEN_PRIVILEGES priv
;
3941 DWORD priv_size
= sizeof (priv
);
3942 DWORD opriv_size
= sizeof (*old_priv
);
3943 HANDLE h_token
= NULL
;
3944 HANDLE h_thread
= GetCurrentThread ();
3948 res
= open_thread_token (h_thread
,
3949 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3951 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3953 if (impersonate_self (SecurityImpersonation
))
3954 res
= open_thread_token (h_thread
,
3955 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3960 priv
.PrivilegeCount
= 1;
3961 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3962 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3963 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3964 old_priv
, &opriv_size
)
3965 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3969 CloseHandle (h_token
);
3975 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3977 DWORD priv_size
= sizeof (*priv
);
3978 HANDLE h_token
= NULL
;
3981 if (open_thread_token (GetCurrentThread (),
3982 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3985 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3986 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3990 CloseHandle (h_token
);
3996 ltime (long time_sec
, long time_usec
)
3998 return list3 (make_number ((time_sec
>> 16) & 0xffff),
3999 make_number (time_sec
& 0xffff),
4000 make_number (time_usec
));
4003 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
4006 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
4007 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4010 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4011 ULONGLONG tem1
, tem2
, tem3
, tem
;
4014 || !get_process_times_fn
4015 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4016 &ft_kernel
, &ft_user
))
4019 GetSystemTimeAsFileTime (&ft_current
);
4021 FILETIME_TO_U64 (tem1
, ft_kernel
);
4023 *stime
= U64_TO_LISP_TIME (tem1
);
4025 FILETIME_TO_U64 (tem2
, ft_user
);
4027 *utime
= U64_TO_LISP_TIME (tem2
);
4030 *ttime
= U64_TO_LISP_TIME (tem3
);
4032 FILETIME_TO_U64 (tem
, ft_creation
);
4033 /* Process no 4 (System) returns zero creation time. */
4035 tem
= (tem
- utc_base
) / 10L;
4036 *ctime
= U64_TO_LISP_TIME (tem
);
4040 FILETIME_TO_U64 (tem3
, ft_current
);
4041 tem
= (tem3
- utc_base
) / 10L - tem
;
4043 *etime
= U64_TO_LISP_TIME (tem
);
4047 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4058 system_process_attributes (Lisp_Object pid
)
4060 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4061 Lisp_Object attrs
= Qnil
;
4062 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4063 HANDLE h_snapshot
, h_proc
;
4066 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4067 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4068 DWORD glength
= sizeof (gname
);
4069 HANDLE token
= NULL
;
4070 SID_NAME_USE user_type
;
4071 unsigned char *buf
= NULL
;
4073 TOKEN_USER user_token
;
4074 TOKEN_PRIMARY_GROUP group_token
;
4078 PROCESS_MEMORY_COUNTERS mem
;
4079 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4080 DWORD minrss
, maxrss
;
4082 MEMORY_STATUS_EX memstex
;
4083 double totphys
= 0.0;
4084 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4086 BOOL result
= FALSE
;
4088 CHECK_NUMBER_OR_FLOAT (pid
);
4089 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4091 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4093 GCPRO3 (attrs
, decoded_cmd
, tem
);
4095 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4100 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4101 for (res
= process32_first (h_snapshot
, &pe
); res
;
4102 res
= process32_next (h_snapshot
, &pe
))
4104 if (proc_id
== pe
.th32ProcessID
)
4107 decoded_cmd
= build_string ("Idle");
4110 /* Decode the command name from locale-specific
4112 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4113 strlen (pe
.szExeFile
));
4115 code_convert_string_norecord (cmd_str
,
4116 Vlocale_coding_system
, 0);
4118 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4119 attrs
= Fcons (Fcons (Qppid
,
4120 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4122 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4124 attrs
= Fcons (Fcons (Qthcount
,
4125 make_fixnum_or_float (pe
.cntThreads
)),
4132 CloseHandle (h_snapshot
);
4141 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4143 /* If we were denied a handle to the process, try again after
4144 enabling the SeDebugPrivilege in our process. */
4147 TOKEN_PRIVILEGES priv_current
;
4149 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4151 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4153 restore_privilege (&priv_current
);
4159 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4162 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4163 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4165 buf
= xmalloc (blen
);
4166 result
= get_token_information (token
, TokenUser
,
4167 (LPVOID
)buf
, blen
, &needed
);
4170 memcpy (&user_token
, buf
, sizeof (user_token
));
4171 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4173 euid
= get_rid (user_token
.User
.Sid
);
4174 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4179 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4182 strcpy (uname
, "unknown");
4186 ulength
= strlen (uname
);
4192 /* Determine a reasonable euid and gid values. */
4193 if (xstrcasecmp ("administrator", uname
) == 0)
4195 euid
= 500; /* well-known Administrator uid */
4196 egid
= 513; /* well-known None gid */
4200 /* Get group id and name. */
4201 result
= get_token_information (token
, TokenPrimaryGroup
,
4202 (LPVOID
)buf
, blen
, &needed
);
4203 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4205 buf
= xrealloc (buf
, blen
= needed
);
4206 result
= get_token_information (token
, TokenPrimaryGroup
,
4207 (LPVOID
)buf
, blen
, &needed
);
4211 memcpy (&group_token
, buf
, sizeof (group_token
));
4212 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4214 egid
= get_rid (group_token
.PrimaryGroup
);
4215 dlength
= sizeof (domain
);
4217 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4218 gname
, &glength
, NULL
, &dlength
,
4221 w32_add_to_cache (group_token
.PrimaryGroup
,
4225 strcpy (gname
, "None");
4229 glength
= strlen (gname
);
4237 if (!is_windows_9x ())
4239 /* We couldn't open the process token, presumably because of
4240 insufficient access rights. Assume this process is run
4242 strcpy (uname
, "SYSTEM");
4243 strcpy (gname
, "None");
4244 euid
= 18; /* SYSTEM */
4245 egid
= 513; /* None */
4246 glength
= strlen (gname
);
4247 ulength
= strlen (uname
);
4249 /* If we are running under Windows 9X, where security calls are
4250 not supported, we assume all processes are run by the current
4252 else if (GetUserName (uname
, &ulength
))
4254 if (xstrcasecmp ("administrator", uname
) == 0)
4259 strcpy (gname
, "None");
4260 glength
= strlen (gname
);
4261 ulength
= strlen (uname
);
4267 strcpy (uname
, "administrator");
4268 ulength
= strlen (uname
);
4269 strcpy (gname
, "None");
4270 glength
= strlen (gname
);
4273 CloseHandle (token
);
4276 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4277 tem
= make_unibyte_string (uname
, ulength
);
4278 attrs
= Fcons (Fcons (Quser
,
4279 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4281 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4282 tem
= make_unibyte_string (gname
, glength
);
4283 attrs
= Fcons (Fcons (Qgroup
,
4284 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4287 if (global_memory_status_ex (&memstex
))
4288 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4289 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4291 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4292 double, so we need to do this for it... */
4294 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4295 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4296 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4298 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4300 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4301 else if (global_memory_status (&memst
))
4302 totphys
= memst
.dwTotalPhys
/ 1024.0;
4305 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4308 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4310 attrs
= Fcons (Fcons (Qmajflt
,
4311 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4313 attrs
= Fcons (Fcons (Qvsize
,
4314 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4316 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4318 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4321 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4323 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4325 attrs
= Fcons (Fcons (Qmajflt
,
4326 make_fixnum_or_float (mem
.PageFaultCount
)),
4328 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4330 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4333 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4335 DWORD rss
= maxrss
/ 1024;
4337 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4339 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4342 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4344 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4345 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4346 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4347 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4348 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4349 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4352 /* FIXME: Retrieve command line by walking the PEB of the process. */
4355 CloseHandle (h_proc
);
4361 /* Wrappers for winsock functions to map between our file descriptors
4362 and winsock's handles; also set h_errno for convenience.
4364 To allow Emacs to run on systems which don't have winsock support
4365 installed, we dynamically link to winsock on startup if present, and
4366 otherwise provide the minimum necessary functionality
4367 (eg. gethostname). */
4369 /* function pointers for relevant socket functions */
4370 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4371 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4372 int (PASCAL
*pfn_WSAGetLastError
) (void);
4373 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4374 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4375 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4376 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4377 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4378 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4379 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4380 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4381 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4382 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4383 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4384 int (PASCAL
*pfn_WSACleanup
) (void);
4386 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4387 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4388 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4389 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4390 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4391 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4392 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4393 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4394 const char * optval
, int optlen
);
4395 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4396 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4398 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4399 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4400 struct sockaddr
* from
, int * fromlen
);
4401 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4402 const struct sockaddr
* to
, int tolen
);
4404 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4405 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4406 #ifndef HANDLE_FLAG_INHERIT
4407 #define HANDLE_FLAG_INHERIT 1
4411 static int winsock_inuse
;
4416 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4418 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4419 after WSAStartup returns successfully, but it seems reasonable
4420 to allow unloading winsock anyway in that case. */
4421 if (pfn_WSACleanup () == 0 ||
4422 pfn_WSAGetLastError () == WSAENETDOWN
)
4424 if (FreeLibrary (winsock_lib
))
4433 init_winsock (int load_now
)
4435 WSADATA winsockData
;
4437 if (winsock_lib
!= NULL
)
4440 pfn_SetHandleInformation
= NULL
;
4441 pfn_SetHandleInformation
4442 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4443 "SetHandleInformation");
4445 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4447 if (winsock_lib
!= NULL
)
4449 /* dynamically link to socket functions */
4451 #define LOAD_PROC(fn) \
4452 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4455 LOAD_PROC (WSAStartup
);
4456 LOAD_PROC (WSASetLastError
);
4457 LOAD_PROC (WSAGetLastError
);
4458 LOAD_PROC (WSAEventSelect
);
4459 LOAD_PROC (WSACreateEvent
);
4460 LOAD_PROC (WSACloseEvent
);
4463 LOAD_PROC (connect
);
4464 LOAD_PROC (ioctlsocket
);
4467 LOAD_PROC (closesocket
);
4468 LOAD_PROC (shutdown
);
4471 LOAD_PROC (inet_addr
);
4472 LOAD_PROC (gethostname
);
4473 LOAD_PROC (gethostbyname
);
4474 LOAD_PROC (getservbyname
);
4475 LOAD_PROC (getpeername
);
4476 LOAD_PROC (WSACleanup
);
4477 LOAD_PROC (setsockopt
);
4479 LOAD_PROC (getsockname
);
4481 LOAD_PROC (recvfrom
);
4485 /* specify version 1.1 of winsock */
4486 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4488 if (winsockData
.wVersion
!= 0x101)
4493 /* Report that winsock exists and is usable, but leave
4494 socket functions disabled. I am assuming that calling
4495 WSAStartup does not require any network interaction,
4496 and in particular does not cause or require a dial-up
4497 connection to be established. */
4500 FreeLibrary (winsock_lib
);
4508 FreeLibrary (winsock_lib
);
4518 /* function to set h_errno for compatibility; map winsock error codes to
4519 normal system codes where they overlap (non-overlapping definitions
4520 are already in <sys/socket.h> */
4524 if (winsock_lib
== NULL
)
4527 h_errno
= pfn_WSAGetLastError ();
4531 case WSAEACCES
: h_errno
= EACCES
; break;
4532 case WSAEBADF
: h_errno
= EBADF
; break;
4533 case WSAEFAULT
: h_errno
= EFAULT
; break;
4534 case WSAEINTR
: h_errno
= EINTR
; break;
4535 case WSAEINVAL
: h_errno
= EINVAL
; break;
4536 case WSAEMFILE
: h_errno
= EMFILE
; break;
4537 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4538 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4546 if (h_errno
== 0 && winsock_lib
!= NULL
)
4547 pfn_WSASetLastError (0);
4550 /* Extend strerror to handle the winsock-specific error codes. */
4554 } _wsa_errlist
[] = {
4555 WSAEINTR
, "Interrupted function call",
4556 WSAEBADF
, "Bad file descriptor",
4557 WSAEACCES
, "Permission denied",
4558 WSAEFAULT
, "Bad address",
4559 WSAEINVAL
, "Invalid argument",
4560 WSAEMFILE
, "Too many open files",
4562 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
4563 WSAEINPROGRESS
, "Operation now in progress",
4564 WSAEALREADY
, "Operation already in progress",
4565 WSAENOTSOCK
, "Socket operation on non-socket",
4566 WSAEDESTADDRREQ
, "Destination address required",
4567 WSAEMSGSIZE
, "Message too long",
4568 WSAEPROTOTYPE
, "Protocol wrong type for socket",
4569 WSAENOPROTOOPT
, "Bad protocol option",
4570 WSAEPROTONOSUPPORT
, "Protocol not supported",
4571 WSAESOCKTNOSUPPORT
, "Socket type not supported",
4572 WSAEOPNOTSUPP
, "Operation not supported",
4573 WSAEPFNOSUPPORT
, "Protocol family not supported",
4574 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
4575 WSAEADDRINUSE
, "Address already in use",
4576 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
4577 WSAENETDOWN
, "Network is down",
4578 WSAENETUNREACH
, "Network is unreachable",
4579 WSAENETRESET
, "Network dropped connection on reset",
4580 WSAECONNABORTED
, "Software caused connection abort",
4581 WSAECONNRESET
, "Connection reset by peer",
4582 WSAENOBUFS
, "No buffer space available",
4583 WSAEISCONN
, "Socket is already connected",
4584 WSAENOTCONN
, "Socket is not connected",
4585 WSAESHUTDOWN
, "Cannot send after socket shutdown",
4586 WSAETOOMANYREFS
, "Too many references", /* not sure */
4587 WSAETIMEDOUT
, "Connection timed out",
4588 WSAECONNREFUSED
, "Connection refused",
4589 WSAELOOP
, "Network loop", /* not sure */
4590 WSAENAMETOOLONG
, "Name is too long",
4591 WSAEHOSTDOWN
, "Host is down",
4592 WSAEHOSTUNREACH
, "No route to host",
4593 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
4594 WSAEPROCLIM
, "Too many processes",
4595 WSAEUSERS
, "Too many users", /* not sure */
4596 WSAEDQUOT
, "Double quote in host name", /* really not sure */
4597 WSAESTALE
, "Data is stale", /* not sure */
4598 WSAEREMOTE
, "Remote error", /* not sure */
4600 WSASYSNOTREADY
, "Network subsystem is unavailable",
4601 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
4602 WSANOTINITIALISED
, "Winsock not initialized successfully",
4603 WSAEDISCON
, "Graceful shutdown in progress",
4605 WSAENOMORE
, "No more operations allowed", /* not sure */
4606 WSAECANCELLED
, "Operation cancelled", /* not sure */
4607 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
4608 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
4609 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
4610 WSASYSCALLFAILURE
, "System call failure",
4611 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
4612 WSATYPE_NOT_FOUND
, "Class type not found",
4613 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
4614 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
4615 WSAEREFUSED
, "Operation refused", /* not sure */
4618 WSAHOST_NOT_FOUND
, "Host not found",
4619 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
4620 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
4621 WSANO_DATA
, "Valid name, no data record of requested type",
4627 sys_strerror (int error_no
)
4630 static char unknown_msg
[40];
4632 if (error_no
>= 0 && error_no
< sys_nerr
)
4633 return sys_errlist
[error_no
];
4635 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4636 if (_wsa_errlist
[i
].errnum
== error_no
)
4637 return _wsa_errlist
[i
].msg
;
4639 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4643 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4644 but I believe the method of keeping the socket handle separate (and
4645 insuring it is not inheritable) is the correct one. */
4647 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4649 int socket_to_fd (SOCKET s
);
4652 sys_socket (int af
, int type
, int protocol
)
4656 if (winsock_lib
== NULL
)
4659 return INVALID_SOCKET
;
4664 /* call the real socket function */
4665 s
= pfn_socket (af
, type
, protocol
);
4667 if (s
!= INVALID_SOCKET
)
4668 return socket_to_fd (s
);
4674 /* Convert a SOCKET to a file descriptor. */
4676 socket_to_fd (SOCKET s
)
4681 /* Although under NT 3.5 _open_osfhandle will accept a socket
4682 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4683 that does not work under NT 3.1. However, we can get the same
4684 effect by using a backdoor function to replace an existing
4685 descriptor handle with the one we want. */
4687 /* allocate a file descriptor (with appropriate flags) */
4688 fd
= _open ("NUL:", _O_RDWR
);
4691 /* Make a non-inheritable copy of the socket handle. Note
4692 that it is possible that sockets aren't actually kernel
4693 handles, which appears to be the case on Windows 9x when
4694 the MS Proxy winsock client is installed. */
4696 /* Apparently there is a bug in NT 3.51 with some service
4697 packs, which prevents using DuplicateHandle to make a
4698 socket handle non-inheritable (causes WSACleanup to
4699 hang). The work-around is to use SetHandleInformation
4700 instead if it is available and implemented. */
4701 if (pfn_SetHandleInformation
)
4703 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4707 HANDLE parent
= GetCurrentProcess ();
4708 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4710 if (DuplicateHandle (parent
,
4716 DUPLICATE_SAME_ACCESS
))
4718 /* It is possible that DuplicateHandle succeeds even
4719 though the socket wasn't really a kernel handle,
4720 because a real handle has the same value. So
4721 test whether the new handle really is a socket. */
4722 long nonblocking
= 0;
4723 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4725 pfn_closesocket (s
);
4730 CloseHandle (new_s
);
4735 fd_info
[fd
].hnd
= (HANDLE
) s
;
4737 /* set our own internal flags */
4738 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4744 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4746 /* attach child_process to fd_info */
4747 if (fd_info
[ fd
].cp
!= NULL
)
4749 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4753 fd_info
[ fd
].cp
= cp
;
4756 winsock_inuse
++; /* count open sockets */
4763 pfn_closesocket (s
);
4770 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4772 if (winsock_lib
== NULL
)
4775 return SOCKET_ERROR
;
4779 if (fd_info
[s
].flags
& FILE_SOCKET
)
4781 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4782 if (rc
== SOCKET_ERROR
)
4787 return SOCKET_ERROR
;
4792 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4794 if (winsock_lib
== NULL
)
4797 return SOCKET_ERROR
;
4801 if (fd_info
[s
].flags
& FILE_SOCKET
)
4803 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4804 if (rc
== SOCKET_ERROR
)
4809 return SOCKET_ERROR
;
4813 sys_htons (u_short hostshort
)
4815 return (winsock_lib
!= NULL
) ?
4816 pfn_htons (hostshort
) : hostshort
;
4820 sys_ntohs (u_short netshort
)
4822 return (winsock_lib
!= NULL
) ?
4823 pfn_ntohs (netshort
) : netshort
;
4827 sys_inet_addr (const char * cp
)
4829 return (winsock_lib
!= NULL
) ?
4830 pfn_inet_addr (cp
) : INADDR_NONE
;
4834 sys_gethostname (char * name
, int namelen
)
4836 if (winsock_lib
!= NULL
)
4837 return pfn_gethostname (name
, namelen
);
4839 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4840 return !GetComputerName (name
, (DWORD
*)&namelen
);
4843 return SOCKET_ERROR
;
4847 sys_gethostbyname (const char * name
)
4849 struct hostent
* host
;
4851 if (winsock_lib
== NULL
)
4858 host
= pfn_gethostbyname (name
);
4865 sys_getservbyname (const char * name
, const char * proto
)
4867 struct servent
* serv
;
4869 if (winsock_lib
== NULL
)
4876 serv
= pfn_getservbyname (name
, proto
);
4883 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4885 if (winsock_lib
== NULL
)
4888 return SOCKET_ERROR
;
4892 if (fd_info
[s
].flags
& FILE_SOCKET
)
4894 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4895 if (rc
== SOCKET_ERROR
)
4900 return SOCKET_ERROR
;
4905 sys_shutdown (int s
, int how
)
4907 if (winsock_lib
== NULL
)
4910 return SOCKET_ERROR
;
4914 if (fd_info
[s
].flags
& FILE_SOCKET
)
4916 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4917 if (rc
== SOCKET_ERROR
)
4922 return SOCKET_ERROR
;
4926 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4928 if (winsock_lib
== NULL
)
4931 return SOCKET_ERROR
;
4935 if (fd_info
[s
].flags
& FILE_SOCKET
)
4937 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4938 (const char *)optval
, optlen
);
4939 if (rc
== SOCKET_ERROR
)
4944 return SOCKET_ERROR
;
4948 sys_listen (int s
, int backlog
)
4950 if (winsock_lib
== NULL
)
4953 return SOCKET_ERROR
;
4957 if (fd_info
[s
].flags
& FILE_SOCKET
)
4959 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4960 if (rc
== SOCKET_ERROR
)
4963 fd_info
[s
].flags
|= FILE_LISTEN
;
4967 return SOCKET_ERROR
;
4971 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4973 if (winsock_lib
== NULL
)
4976 return SOCKET_ERROR
;
4980 if (fd_info
[s
].flags
& FILE_SOCKET
)
4982 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4983 if (rc
== SOCKET_ERROR
)
4988 return SOCKET_ERROR
;
4992 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
4994 if (winsock_lib
== NULL
)
5001 if (fd_info
[s
].flags
& FILE_LISTEN
)
5003 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5005 if (t
== INVALID_SOCKET
)
5008 fd
= socket_to_fd (t
);
5010 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5011 ResetEvent (fd_info
[s
].cp
->char_avail
);
5019 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5020 struct sockaddr
* from
, int * fromlen
)
5022 if (winsock_lib
== NULL
)
5025 return SOCKET_ERROR
;
5029 if (fd_info
[s
].flags
& FILE_SOCKET
)
5031 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5032 if (rc
== SOCKET_ERROR
)
5037 return SOCKET_ERROR
;
5041 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5042 const struct sockaddr
* to
, int tolen
)
5044 if (winsock_lib
== NULL
)
5047 return SOCKET_ERROR
;
5051 if (fd_info
[s
].flags
& FILE_SOCKET
)
5053 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5054 if (rc
== SOCKET_ERROR
)
5059 return SOCKET_ERROR
;
5062 /* Windows does not have an fcntl function. Provide an implementation
5063 solely for making sockets non-blocking. */
5065 fcntl (int s
, int cmd
, int options
)
5067 if (winsock_lib
== NULL
)
5074 if (fd_info
[s
].flags
& FILE_SOCKET
)
5076 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5078 unsigned long nblock
= 1;
5079 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5080 if (rc
== SOCKET_ERROR
)
5082 /* Keep track of the fact that we set this to non-blocking. */
5083 fd_info
[s
].flags
|= FILE_NDELAY
;
5089 return SOCKET_ERROR
;
5093 return SOCKET_ERROR
;
5097 /* Shadow main io functions: we need to handle pipes and sockets more
5098 intelligently, and implement non-blocking mode as well. */
5111 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5113 child_process
* cp
= fd_info
[fd
].cp
;
5115 fd_info
[fd
].cp
= NULL
;
5117 if (CHILD_ACTIVE (cp
))
5119 /* if last descriptor to active child_process then cleanup */
5121 for (i
= 0; i
< MAXDESC
; i
++)
5125 if (fd_info
[i
].cp
== cp
)
5130 if (fd_info
[fd
].flags
& FILE_SOCKET
)
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 */
5144 /* Note that sockets do not need special treatment here (at least on
5145 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5146 closesocket is equivalent to CloseHandle, which is to be expected
5147 because socket handles are fully fledged kernel handles. */
5150 if (rc
== 0 && fd
< MAXDESC
)
5151 fd_info
[fd
].flags
= 0;
5162 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5164 /* duplicate our internal info as well */
5165 fd_info
[new_fd
] = fd_info
[fd
];
5172 sys_dup2 (int src
, int dst
)
5176 if (dst
< 0 || dst
>= MAXDESC
)
5182 /* make sure we close the destination first if it's a pipe or socket */
5183 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5186 rc
= _dup2 (src
, dst
);
5189 /* duplicate our internal info as well */
5190 fd_info
[dst
] = fd_info
[src
];
5195 /* Unix pipe() has only one arg */
5197 sys_pipe (int * phandles
)
5202 /* make pipe handles non-inheritable; when we spawn a child, we
5203 replace the relevant handle with an inheritable one. Also put
5204 pipes into binary mode; we will do text mode translation ourselves
5206 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5210 /* Protect against overflow, since Windows can open more handles than
5211 our fd_info array has room for. */
5212 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5214 _close (phandles
[0]);
5215 _close (phandles
[1]);
5220 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5221 fd_info
[phandles
[0]].flags
= flags
;
5223 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5224 fd_info
[phandles
[1]].flags
= flags
;
5232 extern int w32_pipe_read_delay
;
5234 /* Function to do blocking read of one byte, needed to implement
5235 select. It is only allowed on sockets and pipes. */
5237 _sys_read_ahead (int fd
)
5242 if (fd
< 0 || fd
>= MAXDESC
)
5243 return STATUS_READ_ERROR
;
5245 cp
= fd_info
[fd
].cp
;
5247 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5248 return STATUS_READ_ERROR
;
5250 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5251 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5253 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5257 cp
->status
= STATUS_READ_IN_PROGRESS
;
5259 if (fd_info
[fd
].flags
& FILE_PIPE
)
5261 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5263 /* Give subprocess time to buffer some more output for us before
5264 reporting that input is available; we need this because Windows 95
5265 connects DOS programs to pipes by making the pipe appear to be
5266 the normal console stdout - as a result most DOS programs will
5267 write to stdout without buffering, ie. one character at a
5268 time. Even some W32 programs do this - "dir" in a command
5269 shell on NT is very slow if we don't do this. */
5272 int wait
= w32_pipe_read_delay
;
5278 /* Yield remainder of our time slice, effectively giving a
5279 temporary priority boost to the child process. */
5283 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5285 HANDLE hnd
= fd_info
[fd
].hnd
;
5286 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5289 /* Configure timeouts for blocking read. */
5290 if (!GetCommTimeouts (hnd
, &ct
))
5291 return STATUS_READ_ERROR
;
5292 ct
.ReadIntervalTimeout
= 0;
5293 ct
.ReadTotalTimeoutMultiplier
= 0;
5294 ct
.ReadTotalTimeoutConstant
= 0;
5295 if (!SetCommTimeouts (hnd
, &ct
))
5296 return STATUS_READ_ERROR
;
5298 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5300 if (GetLastError () != ERROR_IO_PENDING
)
5301 return STATUS_READ_ERROR
;
5302 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5303 return STATUS_READ_ERROR
;
5306 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5308 unsigned long nblock
= 0;
5309 /* We always want this to block, so temporarily disable NDELAY. */
5310 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5311 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5313 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5315 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5318 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5322 if (rc
== sizeof (char))
5323 cp
->status
= STATUS_READ_SUCCEEDED
;
5325 cp
->status
= STATUS_READ_FAILED
;
5331 _sys_wait_accept (int fd
)
5337 if (fd
< 0 || fd
>= MAXDESC
)
5338 return STATUS_READ_ERROR
;
5340 cp
= fd_info
[fd
].cp
;
5342 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5343 return STATUS_READ_ERROR
;
5345 cp
->status
= STATUS_READ_FAILED
;
5347 hEv
= pfn_WSACreateEvent ();
5348 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5349 if (rc
!= SOCKET_ERROR
)
5351 rc
= WaitForSingleObject (hEv
, INFINITE
);
5352 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5353 if (rc
== WAIT_OBJECT_0
)
5354 cp
->status
= STATUS_READ_SUCCEEDED
;
5356 pfn_WSACloseEvent (hEv
);
5362 sys_read (int fd
, char * buffer
, unsigned int count
)
5367 char * orig_buffer
= buffer
;
5375 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5377 child_process
*cp
= fd_info
[fd
].cp
;
5379 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5387 /* re-read CR carried over from last read */
5388 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5390 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5394 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5397 /* presence of a child_process structure means we are operating in
5398 non-blocking mode - otherwise we just call _read directly.
5399 Note that the child_process structure might be missing because
5400 reap_subprocess has been called; in this case the pipe is
5401 already broken, so calling _read on it is okay. */
5404 int current_status
= cp
->status
;
5406 switch (current_status
)
5408 case STATUS_READ_FAILED
:
5409 case STATUS_READ_ERROR
:
5410 /* report normal EOF if nothing in buffer */
5412 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5415 case STATUS_READ_READY
:
5416 case STATUS_READ_IN_PROGRESS
:
5417 DebPrint (("sys_read called when read is in progress\n"));
5418 errno
= EWOULDBLOCK
;
5421 case STATUS_READ_SUCCEEDED
:
5422 /* consume read-ahead char */
5423 *buffer
++ = cp
->chr
;
5426 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5427 ResetEvent (cp
->char_avail
);
5429 case STATUS_READ_ACKNOWLEDGED
:
5433 DebPrint (("sys_read: bad status %d\n", current_status
));
5438 if (fd_info
[fd
].flags
& FILE_PIPE
)
5440 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5441 to_read
= min (waiting
, (DWORD
) count
);
5444 nchars
+= _read (fd
, buffer
, to_read
);
5446 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5448 HANDLE hnd
= fd_info
[fd
].hnd
;
5449 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5456 /* Configure timeouts for non-blocking read. */
5457 if (!GetCommTimeouts (hnd
, &ct
))
5462 ct
.ReadIntervalTimeout
= MAXDWORD
;
5463 ct
.ReadTotalTimeoutMultiplier
= 0;
5464 ct
.ReadTotalTimeoutConstant
= 0;
5465 if (!SetCommTimeouts (hnd
, &ct
))
5471 if (!ResetEvent (ovl
->hEvent
))
5476 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5478 if (GetLastError () != ERROR_IO_PENDING
)
5483 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5492 else /* FILE_SOCKET */
5494 if (winsock_lib
== NULL
) abort ();
5496 /* do the equivalent of a non-blocking read */
5497 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5498 if (waiting
== 0 && nchars
== 0)
5500 h_errno
= errno
= EWOULDBLOCK
;
5506 /* always use binary mode for sockets */
5507 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5508 if (res
== SOCKET_ERROR
)
5510 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5511 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5521 int nread
= _read (fd
, buffer
, count
);
5524 else if (nchars
== 0)
5529 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5530 /* Perform text mode translation if required. */
5531 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5533 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5534 /* If buffer contains only CR, return that. To be absolutely
5535 sure we should attempt to read the next char, but in
5536 practice a CR to be followed by LF would not appear by
5537 itself in the buffer. */
5538 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5540 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5546 nchars
= _read (fd
, buffer
, count
);
5551 /* From w32xfns.c */
5552 extern HANDLE interrupt_handle
;
5554 /* For now, don't bother with a non-blocking mode */
5556 sys_write (int fd
, const void * buffer
, unsigned int count
)
5566 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5568 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5574 /* Perform text mode translation if required. */
5575 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5577 char * tmpbuf
= alloca (count
* 2);
5578 unsigned char * src
= (void *)buffer
;
5579 unsigned char * dst
= tmpbuf
;
5584 unsigned char *next
;
5585 /* copy next line or remaining bytes */
5586 next
= _memccpy (dst
, src
, '\n', nbytes
);
5589 /* copied one line ending with '\n' */
5590 int copied
= next
- dst
;
5593 /* insert '\r' before '\n' */
5600 /* copied remaining partial line -> now finished */
5607 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5609 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5610 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5611 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5614 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5616 if (GetLastError () != ERROR_IO_PENDING
)
5621 if (detect_input_pending ())
5622 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5625 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5626 if (active
== WAIT_OBJECT_0
)
5627 { /* User pressed C-g, cancel write, then leave. Don't bother
5628 cleaning up as we may only get stuck in buggy drivers. */
5629 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5634 if (active
== WAIT_OBJECT_0
+ 1
5635 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5642 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5644 unsigned long nblock
= 0;
5645 if (winsock_lib
== NULL
) abort ();
5647 /* TODO: implement select() properly so non-blocking I/O works. */
5648 /* For now, make sure the write blocks. */
5649 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5650 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5652 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5654 /* Set the socket back to non-blocking if it was before,
5655 for other operations that support it. */
5656 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5659 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5662 if (nchars
== SOCKET_ERROR
)
5664 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5665 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5671 /* Some networked filesystems don't like too large writes, so
5672 break them into smaller chunks. See the Comments section of
5673 the MSDN documentation of WriteFile for details behind the
5674 choice of the value of CHUNK below. See also the thread
5675 http://thread.gmane.org/gmane.comp.version-control.git/145294
5676 in the git mailing list. */
5677 const unsigned char *p
= buffer
;
5678 const unsigned chunk
= 30 * 1024 * 1024;
5683 unsigned this_chunk
= count
< chunk
? count
: chunk
;
5684 int n
= _write (fd
, p
, this_chunk
);
5692 else if (n
< this_chunk
)
5703 check_windows_init_file (void)
5705 extern int noninteractive
, inhibit_window_system
;
5707 /* A common indication that Emacs is not installed properly is when
5708 it cannot find the Windows installation file. If this file does
5709 not exist in the expected place, tell the user. */
5711 if (!noninteractive
&& !inhibit_window_system
)
5713 extern Lisp_Object Vwindow_system
, Vload_path
, Qfile_exists_p
;
5714 Lisp_Object objs
[2];
5715 Lisp_Object full_load_path
;
5716 Lisp_Object init_file
;
5719 objs
[0] = Vload_path
;
5720 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5721 full_load_path
= Fappend (2, objs
);
5722 init_file
= build_string ("term/w32-win");
5723 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5726 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5727 char *init_file_name
= SDATA (init_file
);
5728 char *load_path
= SDATA (load_path_print
);
5729 char *buffer
= alloca (1024
5730 + strlen (init_file_name
)
5731 + strlen (load_path
));
5734 "The Emacs Windows initialization file \"%s.el\" "
5735 "could not be found in your Emacs installation. "
5736 "Emacs checked the following directories for this file:\n"
5738 "When Emacs cannot find this file, it usually means that it "
5739 "was not installed properly, or its distribution file was "
5740 "not unpacked properly.\nSee the README.W32 file in the "
5741 "top-level Emacs directory for more information.",
5742 init_file_name
, load_path
);
5745 "Emacs Abort Dialog",
5746 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5747 /* Use the low-level Emacs abort. */
5761 /* shutdown the socket interface if necessary */
5770 /* Initialise the socket interface now if available and requested by
5771 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5772 delayed until open-network-stream is called (w32-has-winsock can
5773 also be used to dynamically load or reload winsock).
5775 Conveniently, init_environment is called before us, so
5776 PRELOAD_WINSOCK can be set in the registry. */
5778 /* Always initialize this correctly. */
5781 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5782 init_winsock (TRUE
);
5784 /* Initial preparation for subprocess support: replace our standard
5785 handles with non-inheritable versions. */
5788 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5789 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5790 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5792 parent
= GetCurrentProcess ();
5794 /* ignore errors when duplicating and closing; typically the
5795 handles will be invalid when running as a gui program. */
5796 DuplicateHandle (parent
,
5797 GetStdHandle (STD_INPUT_HANDLE
),
5802 DUPLICATE_SAME_ACCESS
);
5804 DuplicateHandle (parent
,
5805 GetStdHandle (STD_OUTPUT_HANDLE
),
5810 DUPLICATE_SAME_ACCESS
);
5812 DuplicateHandle (parent
,
5813 GetStdHandle (STD_ERROR_HANDLE
),
5818 DUPLICATE_SAME_ACCESS
);
5824 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5825 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5827 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5830 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5831 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5833 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5836 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5837 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5839 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5843 /* unfortunately, atexit depends on implementation of malloc */
5844 /* atexit (term_ntproc); */
5845 signal (SIGABRT
, term_ntproc
);
5847 /* determine which drives are fixed, for GetCachedVolumeInformation */
5849 /* GetDriveType must have trailing backslash. */
5850 char drive
[] = "A:\\";
5852 /* Loop over all possible drive letters */
5853 while (*drive
<= 'Z')
5855 /* Record if this drive letter refers to a fixed drive. */
5856 fixed_drives
[DRIVE_INDEX (*drive
)] =
5857 (GetDriveType (drive
) == DRIVE_FIXED
);
5862 /* Reset the volume info cache. */
5863 volume_cache
= NULL
;
5866 /* Check to see if Emacs has been installed correctly. */
5867 check_windows_init_file ();
5871 shutdown_handler ensures that buffers' autosave files are
5872 up to date when the user logs off, or the system shuts down.
5875 shutdown_handler (DWORD type
)
5877 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5878 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5879 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5880 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5882 /* Shut down cleanly, making sure autosave files are up to date. */
5883 shut_down_emacs (0, 0, Qnil
);
5886 /* Allow other handlers to handle this signal. */
5891 globals_of_w32 is used to initialize those global variables that
5892 must always be initialized on startup even when the global variable
5893 initialized is non zero (see the function main in emacs.c).
5896 globals_of_w32 (void)
5898 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5900 get_process_times_fn
= (GetProcessTimes_Proc
)
5901 GetProcAddress (kernel32
, "GetProcessTimes");
5903 g_b_init_is_windows_9x
= 0;
5904 g_b_init_open_process_token
= 0;
5905 g_b_init_get_token_information
= 0;
5906 g_b_init_lookup_account_sid
= 0;
5907 g_b_init_get_sid_identifier_authority
= 0;
5908 g_b_init_get_sid_sub_authority
= 0;
5909 g_b_init_get_sid_sub_authority_count
= 0;
5910 g_b_init_get_file_security
= 0;
5911 g_b_init_get_security_descriptor_owner
= 0;
5912 g_b_init_get_security_descriptor_group
= 0;
5913 g_b_init_is_valid_sid
= 0;
5914 g_b_init_create_toolhelp32_snapshot
= 0;
5915 g_b_init_process32_first
= 0;
5916 g_b_init_process32_next
= 0;
5917 g_b_init_open_thread_token
= 0;
5918 g_b_init_impersonate_self
= 0;
5919 g_b_init_revert_to_self
= 0;
5920 g_b_init_get_process_memory_info
= 0;
5921 g_b_init_get_process_working_set_size
= 0;
5922 g_b_init_global_memory_status
= 0;
5923 g_b_init_global_memory_status_ex
= 0;
5924 g_b_init_equal_sid
= 0;
5925 g_b_init_copy_sid
= 0;
5926 g_b_init_get_length_sid
= 0;
5927 g_b_init_get_native_system_info
= 0;
5928 g_b_init_get_system_times
= 0;
5929 num_of_processors
= 0;
5930 /* The following sets a handler for shutdown notifications for
5931 console apps. This actually applies to Emacs in both console and
5932 GUI modes, since we had to fool windows into thinking emacs is a
5933 console application to get console mode to work. */
5934 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
5936 /* "None" is the default group name on standalone workstations. */
5937 strcpy (dflt_group_name
, "None");
5940 /* For make-serial-process */
5942 serial_open (char *port
)
5948 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5949 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5950 if (hnd
== INVALID_HANDLE_VALUE
)
5951 error ("Could not open %s", port
);
5952 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5954 error ("Could not open %s", port
);
5958 error ("Could not create child process");
5960 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5961 fd_info
[ fd
].hnd
= hnd
;
5962 fd_info
[ fd
].flags
|=
5963 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5964 if (fd_info
[ fd
].cp
!= NULL
)
5966 error ("fd_info[fd = %d] is already in use", fd
);
5968 fd_info
[ fd
].cp
= cp
;
5969 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5970 if (cp
->ovl_read
.hEvent
== NULL
)
5971 error ("Could not create read event");
5972 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5973 if (cp
->ovl_write
.hEvent
== NULL
)
5974 error ("Could not create write event");
5979 /* For serial-process-configure */
5981 serial_configure (struct Lisp_Process
*p
,
5982 Lisp_Object contact
)
5984 Lisp_Object childp2
= Qnil
;
5985 Lisp_Object tem
= Qnil
;
5989 char summary
[4] = "???"; /* This usually becomes "8N1". */
5991 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
5992 error ("Not a serial process");
5993 hnd
= fd_info
[ p
->outfd
].hnd
;
5995 childp2
= Fcopy_sequence (p
->childp
);
5997 /* Initialize timeouts for blocking read and blocking write. */
5998 if (!GetCommTimeouts (hnd
, &ct
))
5999 error ("GetCommTimeouts() failed");
6000 ct
.ReadIntervalTimeout
= 0;
6001 ct
.ReadTotalTimeoutMultiplier
= 0;
6002 ct
.ReadTotalTimeoutConstant
= 0;
6003 ct
.WriteTotalTimeoutMultiplier
= 0;
6004 ct
.WriteTotalTimeoutConstant
= 0;
6005 if (!SetCommTimeouts (hnd
, &ct
))
6006 error ("SetCommTimeouts() failed");
6007 /* Read port attributes and prepare default configuration. */
6008 memset (&dcb
, 0, sizeof (dcb
));
6009 dcb
.DCBlength
= sizeof (DCB
);
6010 if (!GetCommState (hnd
, &dcb
))
6011 error ("GetCommState() failed");
6014 dcb
.fAbortOnError
= FALSE
;
6015 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6020 /* Configure speed. */
6021 if (!NILP (Fplist_member (contact
, QCspeed
)))
6022 tem
= Fplist_get (contact
, QCspeed
);
6024 tem
= Fplist_get (p
->childp
, QCspeed
);
6026 dcb
.BaudRate
= XINT (tem
);
6027 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6029 /* Configure bytesize. */
6030 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6031 tem
= Fplist_get (contact
, QCbytesize
);
6033 tem
= Fplist_get (p
->childp
, QCbytesize
);
6035 tem
= make_number (8);
6037 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6038 error (":bytesize must be nil (8), 7, or 8");
6039 dcb
.ByteSize
= XINT (tem
);
6040 summary
[0] = XINT (tem
) + '0';
6041 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6043 /* Configure parity. */
6044 if (!NILP (Fplist_member (contact
, QCparity
)))
6045 tem
= Fplist_get (contact
, QCparity
);
6047 tem
= Fplist_get (p
->childp
, QCparity
);
6048 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6049 error (":parity must be nil (no parity), `even', or `odd'");
6050 dcb
.fParity
= FALSE
;
6051 dcb
.Parity
= NOPARITY
;
6052 dcb
.fErrorChar
= FALSE
;
6057 else if (EQ (tem
, Qeven
))
6061 dcb
.Parity
= EVENPARITY
;
6062 dcb
.fErrorChar
= TRUE
;
6064 else if (EQ (tem
, Qodd
))
6068 dcb
.Parity
= ODDPARITY
;
6069 dcb
.fErrorChar
= TRUE
;
6071 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6073 /* Configure stopbits. */
6074 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6075 tem
= Fplist_get (contact
, QCstopbits
);
6077 tem
= Fplist_get (p
->childp
, QCstopbits
);
6079 tem
= make_number (1);
6081 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6082 error (":stopbits must be nil (1 stopbit), 1, or 2");
6083 summary
[2] = XINT (tem
) + '0';
6084 if (XINT (tem
) == 1)
6085 dcb
.StopBits
= ONESTOPBIT
;
6086 else if (XINT (tem
) == 2)
6087 dcb
.StopBits
= TWOSTOPBITS
;
6088 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6090 /* Configure flowcontrol. */
6091 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6092 tem
= Fplist_get (contact
, QCflowcontrol
);
6094 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6095 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6096 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6097 dcb
.fOutxCtsFlow
= FALSE
;
6098 dcb
.fOutxDsrFlow
= FALSE
;
6099 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6100 dcb
.fDsrSensitivity
= FALSE
;
6101 dcb
.fTXContinueOnXoff
= FALSE
;
6104 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6105 dcb
.XonChar
= 17; /* Control-Q */
6106 dcb
.XoffChar
= 19; /* Control-S */
6109 /* Already configured. */
6111 else if (EQ (tem
, Qhw
))
6113 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6114 dcb
.fOutxCtsFlow
= TRUE
;
6116 else if (EQ (tem
, Qsw
))
6121 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6123 /* Activate configuration. */
6124 if (!SetCommState (hnd
, &dcb
))
6125 error ("SetCommState() failed");
6127 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6128 p
->childp
= childp2
;
6133 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
6134 (do not change this comment) */