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, 2011 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 */
40 /* must include CRT headers *before* config.h */
77 #define _ANONYMOUS_UNION
78 #define _ANONYMOUS_STRUCT
81 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
82 use a different name to avoid compilation problems. */
83 typedef struct _MEMORY_STATUS_EX
{
86 DWORDLONG ullTotalPhys
;
87 DWORDLONG ullAvailPhys
;
88 DWORDLONG ullTotalPageFile
;
89 DWORDLONG ullAvailPageFile
;
90 DWORDLONG ullTotalVirtual
;
91 DWORDLONG ullAvailVirtual
;
92 DWORDLONG ullAvailExtendedVirtual
;
93 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
101 #if !defined(__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
102 /* This either is not in psapi.h or guarded by higher value of
103 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
104 defines it in psapi.h */
105 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
107 DWORD PageFaultCount
;
108 DWORD PeakWorkingSetSize
;
109 DWORD WorkingSetSize
;
110 DWORD QuotaPeakPagedPoolUsage
;
111 DWORD QuotaPagedPoolUsage
;
112 DWORD QuotaPeakNonPagedPoolUsage
;
113 DWORD QuotaNonPagedPoolUsage
;
115 DWORD PeakPagefileUsage
;
117 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
120 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
121 #include <sys/socket.h>
145 #include "dispextern.h" /* for xstrcasecmp */
146 #include "coding.h" /* for Vlocale_coding_system */
148 /* For serial_configure and serial_open. */
151 extern Lisp_Object QCport
, QCspeed
, QCprocess
;
152 extern Lisp_Object QCbytesize
, QCstopbits
, QCparity
, Qodd
, Qeven
;
153 extern Lisp_Object QCflowcontrol
, Qhw
, Qsw
, QCsummary
;
155 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
156 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
158 void globals_of_w32 ();
159 static DWORD
get_rid (PSID
);
161 extern Lisp_Object Vw32_downcase_file_names
;
162 extern Lisp_Object Vw32_generate_fake_inodes
;
163 extern Lisp_Object Vw32_get_true_file_attributes
;
164 /* Defined in process.c for its own purpose. */
165 extern Lisp_Object Qlocal
;
167 extern int w32_num_mouse_buttons
;
170 /* Initialization states.
172 WARNING: If you add any more such variables for additional APIs,
173 you MUST add initialization for them to globals_of_w32
174 below. This is because these variables might get set
175 to non-NULL values during dumping, but the dumped Emacs
176 cannot reuse those values, because it could be run on a
177 different version of the OS, where API addresses are
179 static BOOL g_b_init_is_windows_9x
;
180 static BOOL g_b_init_open_process_token
;
181 static BOOL g_b_init_get_token_information
;
182 static BOOL g_b_init_lookup_account_sid
;
183 static BOOL g_b_init_get_sid_identifier_authority
;
184 static BOOL g_b_init_get_sid_sub_authority
;
185 static BOOL g_b_init_get_sid_sub_authority_count
;
186 static BOOL g_b_init_get_file_security
;
187 static BOOL g_b_init_get_security_descriptor_owner
;
188 static BOOL g_b_init_get_security_descriptor_group
;
189 static BOOL g_b_init_is_valid_sid
;
190 static BOOL g_b_init_create_toolhelp32_snapshot
;
191 static BOOL g_b_init_process32_first
;
192 static BOOL g_b_init_process32_next
;
193 static BOOL g_b_init_open_thread_token
;
194 static BOOL g_b_init_impersonate_self
;
195 static BOOL g_b_init_revert_to_self
;
196 static BOOL g_b_init_get_process_memory_info
;
197 static BOOL g_b_init_get_process_working_set_size
;
198 static BOOL g_b_init_global_memory_status
;
199 static BOOL g_b_init_global_memory_status_ex
;
200 static BOOL g_b_init_get_length_sid
;
201 static BOOL g_b_init_equal_sid
;
202 static BOOL g_b_init_copy_sid
;
203 static BOOL g_b_init_get_native_system_info
;
204 static BOOL g_b_init_get_system_times
;
207 BEGIN: Wrapper functions around OpenProcessToken
208 and other functions in advapi32.dll that are only
209 supported in Windows NT / 2k / XP
211 /* ** Function pointer typedefs ** */
212 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
213 HANDLE ProcessHandle
,
215 PHANDLE TokenHandle
);
216 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
218 TOKEN_INFORMATION_CLASS TokenInformationClass
,
219 LPVOID TokenInformation
,
220 DWORD TokenInformationLength
,
221 PDWORD ReturnLength
);
222 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
223 HANDLE process_handle
,
224 LPFILETIME creation_time
,
225 LPFILETIME exit_time
,
226 LPFILETIME kernel_time
,
227 LPFILETIME user_time
);
229 GetProcessTimes_Proc get_process_times_fn
= NULL
;
232 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
233 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
235 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
236 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
238 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
239 LPCTSTR lpSystemName
,
244 LPDWORD cbDomainName
,
245 PSID_NAME_USE peUse
);
246 typedef PSID_IDENTIFIER_AUTHORITY (WINAPI
* GetSidIdentifierAuthority_Proc
) (
248 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
251 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
253 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
255 SECURITY_INFORMATION RequestedInformation
,
256 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
258 LPDWORD lpnLengthNeeded
);
259 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
260 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
262 LPBOOL lpbOwnerDefaulted
);
263 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
264 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
266 LPBOOL lpbGroupDefaulted
);
267 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
269 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
271 DWORD th32ProcessID
);
272 typedef BOOL (WINAPI
* Process32First_Proc
) (
274 LPPROCESSENTRY32 lppe
);
275 typedef BOOL (WINAPI
* Process32Next_Proc
) (
277 LPPROCESSENTRY32 lppe
);
278 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
282 PHANDLE TokenHandle
);
283 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
284 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
285 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
286 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
288 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
290 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
292 DWORD
* lpMinimumWorkingSetSize
,
293 DWORD
* lpMaximumWorkingSetSize
);
294 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
295 LPMEMORYSTATUS lpBuffer
);
296 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
297 LPMEMORY_STATUS_EX lpBuffer
);
298 typedef BOOL (WINAPI
* CopySid_Proc
) (
299 DWORD nDestinationSidLength
,
300 PSID pDestinationSid
,
302 typedef BOOL (WINAPI
* EqualSid_Proc
) (
305 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
307 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
308 LPSYSTEM_INFO lpSystemInfo
);
309 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
310 LPFILETIME lpIdleTime
,
311 LPFILETIME lpKernelTime
,
312 LPFILETIME lpUserTime
);
316 /* ** A utility function ** */
320 static BOOL s_b_ret
=0;
321 OSVERSIONINFO os_ver
;
322 if (g_b_init_is_windows_9x
== 0)
324 g_b_init_is_windows_9x
= 1;
325 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
326 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
327 if (GetVersionEx (&os_ver
))
329 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
335 /* Get total user and system times for get-internal-run-time.
336 Returns a list of three integers if the times are provided by the OS
337 (NT derivatives), otherwise it returns the result of current-time. */
339 w32_get_internal_run_time ()
341 if (get_process_times_fn
)
343 FILETIME create
, exit
, kernel
, user
;
344 HANDLE proc
= GetCurrentProcess ();
345 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
347 LARGE_INTEGER user_int
, kernel_int
, total
;
349 user_int
.LowPart
= user
.dwLowDateTime
;
350 user_int
.HighPart
= user
.dwHighDateTime
;
351 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
352 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
353 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
354 /* FILETIME is 100 nanosecond increments, Emacs only wants
355 microsecond resolution. */
356 total
.QuadPart
/= 10;
357 microseconds
= total
.QuadPart
% 1000000;
358 total
.QuadPart
/= 1000000;
360 /* Sanity check to make sure we can represent the result. */
361 if (total
.HighPart
== 0)
363 int secs
= total
.LowPart
;
365 return list3 (make_number ((secs
>> 16) & 0xffff),
366 make_number (secs
& 0xffff),
367 make_number (microseconds
));
372 return Fcurrent_time ();
375 /* ** The wrapper functions ** */
378 open_process_token (HANDLE ProcessHandle
,
382 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
383 HMODULE hm_advapi32
= NULL
;
384 if (is_windows_9x () == TRUE
)
388 if (g_b_init_open_process_token
== 0)
390 g_b_init_open_process_token
= 1;
391 hm_advapi32
= LoadLibrary ("Advapi32.dll");
392 s_pfn_Open_Process_Token
=
393 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
395 if (s_pfn_Open_Process_Token
== NULL
)
400 s_pfn_Open_Process_Token (
408 get_token_information (HANDLE TokenHandle
,
409 TOKEN_INFORMATION_CLASS TokenInformationClass
,
410 LPVOID TokenInformation
,
411 DWORD TokenInformationLength
,
414 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
415 HMODULE hm_advapi32
= NULL
;
416 if (is_windows_9x () == TRUE
)
420 if (g_b_init_get_token_information
== 0)
422 g_b_init_get_token_information
= 1;
423 hm_advapi32
= LoadLibrary ("Advapi32.dll");
424 s_pfn_Get_Token_Information
=
425 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
427 if (s_pfn_Get_Token_Information
== NULL
)
432 s_pfn_Get_Token_Information (
434 TokenInformationClass
,
436 TokenInformationLength
,
442 lookup_account_sid (LPCTSTR lpSystemName
,
447 LPDWORD cbDomainName
,
450 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
451 HMODULE hm_advapi32
= NULL
;
452 if (is_windows_9x () == TRUE
)
456 if (g_b_init_lookup_account_sid
== 0)
458 g_b_init_lookup_account_sid
= 1;
459 hm_advapi32
= LoadLibrary ("Advapi32.dll");
460 s_pfn_Lookup_Account_Sid
=
461 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
463 if (s_pfn_Lookup_Account_Sid
== NULL
)
468 s_pfn_Lookup_Account_Sid (
479 PSID_IDENTIFIER_AUTHORITY WINAPI
480 get_sid_identifier_authority (PSID pSid
)
482 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority
= NULL
;
483 HMODULE hm_advapi32
= NULL
;
484 if (is_windows_9x () == TRUE
)
488 if (g_b_init_get_sid_identifier_authority
== 0)
490 g_b_init_get_sid_identifier_authority
= 1;
491 hm_advapi32
= LoadLibrary ("Advapi32.dll");
492 s_pfn_Get_Sid_Identifier_Authority
=
493 (GetSidIdentifierAuthority_Proc
) GetProcAddress (
494 hm_advapi32
, "GetSidIdentifierAuthority");
496 if (s_pfn_Get_Sid_Identifier_Authority
== NULL
)
500 return (s_pfn_Get_Sid_Identifier_Authority (pSid
));
504 get_sid_sub_authority (PSID pSid
, DWORD n
)
506 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
507 static DWORD zero
= 0U;
508 HMODULE hm_advapi32
= NULL
;
509 if (is_windows_9x () == TRUE
)
513 if (g_b_init_get_sid_sub_authority
== 0)
515 g_b_init_get_sid_sub_authority
= 1;
516 hm_advapi32
= LoadLibrary ("Advapi32.dll");
517 s_pfn_Get_Sid_Sub_Authority
=
518 (GetSidSubAuthority_Proc
) GetProcAddress (
519 hm_advapi32
, "GetSidSubAuthority");
521 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
525 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
529 get_sid_sub_authority_count (PSID pSid
)
531 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
532 static UCHAR zero
= 0U;
533 HMODULE hm_advapi32
= NULL
;
534 if (is_windows_9x () == TRUE
)
538 if (g_b_init_get_sid_sub_authority_count
== 0)
540 g_b_init_get_sid_sub_authority_count
= 1;
541 hm_advapi32
= LoadLibrary ("Advapi32.dll");
542 s_pfn_Get_Sid_Sub_Authority_Count
=
543 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
544 hm_advapi32
, "GetSidSubAuthorityCount");
546 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
550 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
554 get_file_security (LPCTSTR lpFileName
,
555 SECURITY_INFORMATION RequestedInformation
,
556 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
558 LPDWORD lpnLengthNeeded
)
560 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
561 HMODULE hm_advapi32
= NULL
;
562 if (is_windows_9x () == TRUE
)
566 if (g_b_init_get_file_security
== 0)
568 g_b_init_get_file_security
= 1;
569 hm_advapi32
= LoadLibrary ("Advapi32.dll");
570 s_pfn_Get_File_Security
=
571 (GetFileSecurity_Proc
) GetProcAddress (
572 hm_advapi32
, GetFileSecurity_Name
);
574 if (s_pfn_Get_File_Security
== NULL
)
578 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
579 pSecurityDescriptor
, nLength
,
584 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
586 LPBOOL lpbOwnerDefaulted
)
588 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
589 HMODULE hm_advapi32
= NULL
;
590 if (is_windows_9x () == TRUE
)
594 if (g_b_init_get_security_descriptor_owner
== 0)
596 g_b_init_get_security_descriptor_owner
= 1;
597 hm_advapi32
= LoadLibrary ("Advapi32.dll");
598 s_pfn_Get_Security_Descriptor_Owner
=
599 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
600 hm_advapi32
, "GetSecurityDescriptorOwner");
602 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
606 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
611 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
613 LPBOOL lpbGroupDefaulted
)
615 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
616 HMODULE hm_advapi32
= NULL
;
617 if (is_windows_9x () == TRUE
)
621 if (g_b_init_get_security_descriptor_group
== 0)
623 g_b_init_get_security_descriptor_group
= 1;
624 hm_advapi32
= LoadLibrary ("Advapi32.dll");
625 s_pfn_Get_Security_Descriptor_Group
=
626 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
627 hm_advapi32
, "GetSecurityDescriptorGroup");
629 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
633 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
638 is_valid_sid (PSID sid
)
640 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
641 HMODULE hm_advapi32
= NULL
;
642 if (is_windows_9x () == TRUE
)
646 if (g_b_init_is_valid_sid
== 0)
648 g_b_init_is_valid_sid
= 1;
649 hm_advapi32
= LoadLibrary ("Advapi32.dll");
651 (IsValidSid_Proc
) GetProcAddress (
652 hm_advapi32
, "IsValidSid");
654 if (s_pfn_Is_Valid_Sid
== NULL
)
658 return (s_pfn_Is_Valid_Sid (sid
));
662 equal_sid (PSID sid1
, PSID sid2
)
664 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
665 HMODULE hm_advapi32
= NULL
;
666 if (is_windows_9x () == TRUE
)
670 if (g_b_init_equal_sid
== 0)
672 g_b_init_equal_sid
= 1;
673 hm_advapi32
= LoadLibrary ("Advapi32.dll");
675 (EqualSid_Proc
) GetProcAddress (
676 hm_advapi32
, "EqualSid");
678 if (s_pfn_Equal_Sid
== NULL
)
682 return (s_pfn_Equal_Sid (sid1
, sid2
));
686 get_length_sid (PSID sid
)
688 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
689 HMODULE hm_advapi32
= NULL
;
690 if (is_windows_9x () == TRUE
)
694 if (g_b_init_get_length_sid
== 0)
696 g_b_init_get_length_sid
= 1;
697 hm_advapi32
= LoadLibrary ("Advapi32.dll");
698 s_pfn_Get_Length_Sid
=
699 (GetLengthSid_Proc
) GetProcAddress (
700 hm_advapi32
, "GetLengthSid");
702 if (s_pfn_Get_Length_Sid
== NULL
)
706 return (s_pfn_Get_Length_Sid (sid
));
710 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
712 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
713 HMODULE hm_advapi32
= NULL
;
714 if (is_windows_9x () == TRUE
)
718 if (g_b_init_copy_sid
== 0)
720 g_b_init_copy_sid
= 1;
721 hm_advapi32
= LoadLibrary ("Advapi32.dll");
723 (CopySid_Proc
) GetProcAddress (
724 hm_advapi32
, "CopySid");
726 if (s_pfn_Copy_Sid
== NULL
)
730 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
734 END: Wrapper functions around OpenProcessToken
735 and other functions in advapi32.dll that are only
736 supported in Windows NT / 2k / XP
740 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
742 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
743 if (is_windows_9x () != TRUE
)
745 if (g_b_init_get_native_system_info
== 0)
747 g_b_init_get_native_system_info
= 1;
748 s_pfn_Get_Native_System_Info
=
749 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
750 "GetNativeSystemInfo");
752 if (s_pfn_Get_Native_System_Info
!= NULL
)
753 s_pfn_Get_Native_System_Info (lpSystemInfo
);
756 lpSystemInfo
->dwNumberOfProcessors
= -1;
760 get_system_times (LPFILETIME lpIdleTime
,
761 LPFILETIME lpKernelTime
,
762 LPFILETIME lpUserTime
)
764 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
765 if (is_windows_9x () == TRUE
)
769 if (g_b_init_get_system_times
== 0)
771 g_b_init_get_system_times
= 1;
772 s_pfn_Get_System_times
=
773 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
776 if (s_pfn_Get_System_times
== NULL
)
778 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
781 /* Equivalent of strerror for W32 error codes. */
783 w32_strerror (int error_no
)
785 static char buf
[500];
788 error_no
= GetLastError ();
791 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
793 0, /* choose most suitable language */
794 buf
, sizeof (buf
), NULL
))
795 sprintf (buf
, "w32 error %u", error_no
);
799 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
800 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
802 This is called from alloc.c:valid_pointer_p. */
804 w32_valid_pointer_p (void *p
, int size
)
807 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
811 unsigned char *buf
= alloca (size
);
812 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
821 static char startup_dir
[MAXPATHLEN
];
823 /* Get the current working directory. */
828 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
832 /* Emacs doesn't actually change directory itself, and we want to
833 force our real wd to be where emacs.exe is to avoid unnecessary
834 conflicts when trying to rename or delete directories. */
835 strcpy (dir
, startup_dir
);
841 /* Emulate gethostname. */
843 gethostname (char *buffer
, int size
)
845 /* NT only allows small host names, so the buffer is
846 certainly large enough. */
847 return !GetComputerName (buffer
, &size
);
849 #endif /* HAVE_SOCKETS */
851 /* Emulate getloadavg. */
860 /* Number of processors on this machine. */
861 static unsigned num_of_processors
;
863 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
864 static struct load_sample samples
[16*60];
865 static int first_idx
= -1, last_idx
= -1;
866 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
871 int next_idx
= from
+ 1;
873 if (next_idx
>= max_idx
)
882 int prev_idx
= from
- 1;
885 prev_idx
= max_idx
- 1;
891 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
894 FILETIME ft_idle
, ft_user
, ft_kernel
;
896 /* Initialize the number of processors on this machine. */
897 if (num_of_processors
<= 0)
899 get_native_system_info (&sysinfo
);
900 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
901 if (num_of_processors
<= 0)
903 GetSystemInfo (&sysinfo
);
904 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
906 if (num_of_processors
<= 0)
907 num_of_processors
= 1;
910 /* TODO: Take into account threads that are ready to run, by
911 sampling the "\System\Processor Queue Length" performance
912 counter. The code below accounts only for threads that are
915 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
917 ULARGE_INTEGER uidle
, ukernel
, uuser
;
919 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
920 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
921 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
922 *idle
= uidle
.QuadPart
;
923 *kernel
= ukernel
.QuadPart
;
924 *user
= uuser
.QuadPart
;
934 /* Produce the load average for a given time interval, using the
935 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
936 1-minute, 5-minute, or 15-minute average, respectively. */
940 double retval
= -1.0;
943 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
944 time_t now
= samples
[last_idx
].sample_time
;
946 if (first_idx
!= last_idx
)
948 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
950 tdiff
= difftime (now
, samples
[idx
].sample_time
);
951 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
954 samples
[last_idx
].kernel
+ samples
[last_idx
].user
955 - (samples
[idx
].kernel
+ samples
[idx
].user
);
956 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
958 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
961 if (idx
== first_idx
)
970 getloadavg (double loadavg
[], int nelem
)
973 ULONGLONG idle
, kernel
, user
;
974 time_t now
= time (NULL
);
976 /* Store another sample. We ignore samples that are less than 1 sec
978 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
980 sample_system_load (&idle
, &kernel
, &user
);
981 last_idx
= buf_next (last_idx
);
982 samples
[last_idx
].sample_time
= now
;
983 samples
[last_idx
].idle
= idle
;
984 samples
[last_idx
].kernel
= kernel
;
985 samples
[last_idx
].user
= user
;
986 /* If the buffer has more that 15 min worth of samples, discard
989 first_idx
= last_idx
;
990 while (first_idx
!= last_idx
991 && (difftime (now
, samples
[first_idx
].sample_time
)
992 >= 15.0*60 + 2*DBL_EPSILON
*now
))
993 first_idx
= buf_next (first_idx
);
996 for (elem
= 0; elem
< nelem
; elem
++)
998 double avg
= getavg (elem
);
1002 loadavg
[elem
] = avg
;
1008 /* Emulate getpwuid, getpwnam and others. */
1010 #define PASSWD_FIELD_SIZE 256
1012 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1013 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1014 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1015 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
1016 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
1018 static struct passwd dflt_passwd
=
1030 static char dflt_group_name
[GNLEN
+1];
1032 static struct group dflt_group
=
1034 /* When group information is not available, we return this as the
1035 group for all files. */
1043 return dflt_passwd
.pw_uid
;
1049 /* I could imagine arguing for checking to see whether the user is
1050 in the Administrators group and returning a UID of 0 for that
1051 case, but I don't know how wise that would be in the long run. */
1058 return dflt_passwd
.pw_gid
;
1068 getpwuid (unsigned uid
)
1070 if (uid
== dflt_passwd
.pw_uid
)
1071 return &dflt_passwd
;
1076 getgrgid (gid_t gid
)
1082 getpwnam (char *name
)
1086 pw
= getpwuid (getuid ());
1090 if (xstrcasecmp (name
, pw
->pw_name
))
1099 /* Find the user's real name by opening the process token and
1100 looking up the name associated with the user-sid in that token.
1102 Use the relative portion of the identifier authority value from
1103 the user-sid as the user id value (same for group id using the
1104 primary group sid from the process token). */
1106 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1107 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1108 DWORD glength
= sizeof (gname
);
1109 HANDLE token
= NULL
;
1110 SID_NAME_USE user_type
;
1111 unsigned char *buf
= NULL
;
1113 TOKEN_USER user_token
;
1114 TOKEN_PRIMARY_GROUP group_token
;
1117 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1120 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1121 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1123 buf
= xmalloc (blen
);
1124 result
= get_token_information (token
, TokenUser
,
1125 (LPVOID
)buf
, blen
, &needed
);
1128 memcpy (&user_token
, buf
, sizeof (user_token
));
1129 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1131 domain
, &dlength
, &user_type
);
1139 strcpy (dflt_passwd
.pw_name
, uname
);
1140 /* Determine a reasonable uid value. */
1141 if (xstrcasecmp ("administrator", uname
) == 0)
1143 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1144 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1148 /* Use the last sub-authority value of the RID, the relative
1149 portion of the SID, as user/group ID. */
1150 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1152 /* Get group id and name. */
1153 result
= get_token_information (token
, TokenPrimaryGroup
,
1154 (LPVOID
)buf
, blen
, &needed
);
1155 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1157 buf
= xrealloc (buf
, blen
= needed
);
1158 result
= get_token_information (token
, TokenPrimaryGroup
,
1159 (LPVOID
)buf
, blen
, &needed
);
1163 memcpy (&group_token
, buf
, sizeof (group_token
));
1164 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1165 dlength
= sizeof (domain
);
1166 /* If we can get at the real Primary Group name, use that.
1167 Otherwise, the default group name was already set to
1168 "None" in globals_of_w32. */
1169 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1170 gname
, &glength
, NULL
, &dlength
,
1172 strcpy (dflt_group_name
, gname
);
1175 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1178 /* If security calls are not supported (presumably because we
1179 are running under Windows 9X), fallback to this: */
1180 else if (GetUserName (uname
, &ulength
))
1182 strcpy (dflt_passwd
.pw_name
, uname
);
1183 if (xstrcasecmp ("administrator", uname
) == 0)
1184 dflt_passwd
.pw_uid
= 0;
1186 dflt_passwd
.pw_uid
= 123;
1187 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1191 strcpy (dflt_passwd
.pw_name
, "unknown");
1192 dflt_passwd
.pw_uid
= 123;
1193 dflt_passwd
.pw_gid
= 123;
1195 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1197 /* Ensure HOME and SHELL are defined. */
1198 if (getenv ("HOME") == NULL
)
1200 if (getenv ("SHELL") == NULL
)
1203 /* Set dir and shell from environment variables. */
1204 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1205 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1209 CloseHandle (token
);
1215 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1216 return ((rand () << 15) | rand ());
1226 /* Normalize filename by converting all path separators to
1227 the specified separator. Also conditionally convert upper
1228 case path name components to lower case. */
1231 normalize_filename (fp
, path_sep
)
1238 /* Always lower-case drive letters a-z, even if the filesystem
1239 preserves case in filenames.
1240 This is so filenames can be compared by string comparison
1241 functions that are case-sensitive. Even case-preserving filesystems
1242 do not distinguish case in drive letters. */
1243 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1249 if (NILP (Vw32_downcase_file_names
))
1253 if (*fp
== '/' || *fp
== '\\')
1260 sep
= path_sep
; /* convert to this path separator */
1261 elem
= fp
; /* start of current path element */
1264 if (*fp
>= 'a' && *fp
<= 'z')
1265 elem
= 0; /* don't convert this element */
1267 if (*fp
== 0 || *fp
== ':')
1269 sep
= *fp
; /* restore current separator (or 0) */
1270 *fp
= '/'; /* after conversion of this element */
1273 if (*fp
== '/' || *fp
== '\\')
1275 if (elem
&& elem
!= fp
)
1277 *fp
= 0; /* temporary end of string */
1278 _strlwr (elem
); /* while we convert to lower case */
1280 *fp
= sep
; /* convert (or restore) path separator */
1281 elem
= fp
+ 1; /* next element starts after separator */
1287 /* Destructively turn backslashes into slashes. */
1289 dostounix_filename (p
)
1292 normalize_filename (p
, '/');
1295 /* Destructively turn slashes into backslashes. */
1297 unixtodos_filename (p
)
1300 normalize_filename (p
, '\\');
1303 /* Remove all CR's that are followed by a LF.
1304 (From msdos.c...probably should figure out a way to share it,
1305 although this code isn't going to ever change.) */
1309 register unsigned char *buf
;
1311 unsigned char *np
= buf
;
1312 unsigned char *startp
= buf
;
1313 unsigned char *endp
= buf
+ n
;
1317 while (buf
< endp
- 1)
1321 if (*(++buf
) != 0x0a)
1332 /* Parse the root part of file name, if present. Return length and
1333 optionally store pointer to char after root. */
1335 parse_root (char * name
, char ** pPath
)
1337 char * start
= name
;
1342 /* find the root name of the volume if given */
1343 if (isalpha (name
[0]) && name
[1] == ':')
1345 /* skip past drive specifier */
1347 if (IS_DIRECTORY_SEP (name
[0]))
1350 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1356 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1361 if (IS_DIRECTORY_SEP (name
[0]))
1368 return name
- start
;
1371 /* Get long base name for name; name is assumed to be absolute. */
1373 get_long_basename (char * name
, char * buf
, int size
)
1375 WIN32_FIND_DATA find_data
;
1379 /* must be valid filename, no wild cards or other invalid characters */
1380 if (_mbspbrk (name
, "*?|<>\""))
1383 dir_handle
= FindFirstFile (name
, &find_data
);
1384 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1386 if ((len
= strlen (find_data
.cFileName
)) < size
)
1387 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1390 FindClose (dir_handle
);
1395 /* Get long name for file, if possible (assumed to be absolute). */
1397 w32_get_long_filename (char * name
, char * buf
, int size
)
1402 char full
[ MAX_PATH
];
1405 len
= strlen (name
);
1406 if (len
>= MAX_PATH
)
1409 /* Use local copy for destructive modification. */
1410 memcpy (full
, name
, len
+1);
1411 unixtodos_filename (full
);
1413 /* Copy root part verbatim. */
1414 len
= parse_root (full
, &p
);
1415 memcpy (o
, full
, len
);
1420 while (p
!= NULL
&& *p
)
1423 p
= strchr (q
, '\\');
1425 len
= get_long_basename (full
, o
, size
);
1448 is_unc_volume (const char *filename
)
1450 const char *ptr
= filename
;
1452 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1455 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1461 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1464 sigsetmask (int signal_mask
)
1482 sigunblock (int sig
)
1488 setpgrp (int pid
, int gid
)
1499 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1502 w32_get_resource (key
, lpdwtype
)
1507 HKEY hrootkey
= NULL
;
1510 /* Check both the current user and the local machine to see if
1511 we have any resources. */
1513 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1517 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1518 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1519 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1521 RegCloseKey (hrootkey
);
1527 RegCloseKey (hrootkey
);
1530 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1534 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1535 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1536 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1538 RegCloseKey (hrootkey
);
1544 RegCloseKey (hrootkey
);
1550 char *get_emacs_configuration (void);
1551 extern Lisp_Object Vsystem_configuration
;
1554 init_environment (char ** argv
)
1556 static const char * const tempdirs
[] = {
1557 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1562 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1564 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1565 temporary files and assume "/tmp" if $TMPDIR is unset, which
1566 will break on DOS/Windows. Refuse to work if we cannot find
1567 a directory, not even "c:/", usable for that purpose. */
1568 for (i
= 0; i
< imax
; i
++)
1570 const char *tmp
= tempdirs
[i
];
1573 tmp
= getenv (tmp
+ 1);
1574 /* Note that `access' can lie to us if the directory resides on a
1575 read-only filesystem, like CD-ROM or a write-protected floppy.
1576 The only way to be really sure is to actually create a file and
1577 see if it succeeds. But I think that's too much to ask. */
1578 if (tmp
&& _access (tmp
, D_OK
) == 0)
1580 char * var
= alloca (strlen (tmp
) + 8);
1581 sprintf (var
, "TMPDIR=%s", tmp
);
1582 _putenv (strdup (var
));
1589 Fcons (build_string ("no usable temporary directories found!!"),
1591 "While setting TMPDIR: ");
1593 /* Check for environment variables and use registry settings if they
1594 don't exist. Fallback on default values where applicable. */
1599 char locale_name
[32];
1600 struct stat ignored
;
1601 char default_home
[MAX_PATH
];
1603 static const struct env_entry
1610 {"PRELOAD_WINSOCK", NULL
},
1611 {"emacs_dir", "C:/emacs"},
1612 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1613 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1614 {"EMACSDATA", "%emacs_dir%/etc"},
1615 {"EMACSPATH", "%emacs_dir%/bin"},
1616 /* We no longer set INFOPATH because Info-default-directory-list
1618 /* {"INFOPATH", "%emacs_dir%/info"}, */
1619 {"EMACSDOC", "%emacs_dir%/etc"},
1624 #define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1626 /* We need to copy dflt_envvars[] and work on the copy because we
1627 don't want the dumped Emacs to inherit the values of
1628 environment variables we saw during dumping (which could be on
1629 a different system). The defaults above must be left intact. */
1630 struct env_entry env_vars
[N_ENV_VARS
];
1632 for (i
= 0; i
< N_ENV_VARS
; i
++)
1633 env_vars
[i
] = dflt_envvars
[i
];
1635 /* For backwards compatibility, check if a .emacs file exists in C:/
1636 If not, then we can try to default to the appdata directory under the
1637 user's profile, which is more likely to be writable. */
1638 if (stat ("C:/.emacs", &ignored
) < 0)
1640 HRESULT profile_result
;
1641 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1642 of Windows 95 and NT4 that have not been updated to include
1644 ShGetFolderPath_fn get_folder_path
;
1645 get_folder_path
= (ShGetFolderPath_fn
)
1646 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1648 if (get_folder_path
!= NULL
)
1650 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1653 /* If we can't get the appdata dir, revert to old behavior. */
1654 if (profile_result
== S_OK
)
1655 env_vars
[0].def_value
= default_home
;
1659 /* Get default locale info and use it for LANG. */
1660 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1661 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1662 locale_name
, sizeof (locale_name
)))
1664 for (i
= 0; i
< N_ENV_VARS
; i
++)
1666 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1668 env_vars
[i
].def_value
= locale_name
;
1674 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1676 /* Treat emacs_dir specially: set it unconditionally based on our
1677 location, if it appears that we are running from the bin subdir
1678 of a standard installation. */
1681 char modname
[MAX_PATH
];
1683 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1685 if ((p
= strrchr (modname
, '\\')) == NULL
)
1689 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1691 char buf
[SET_ENV_BUF_SIZE
];
1694 for (p
= modname
; *p
; p
++)
1695 if (*p
== '\\') *p
= '/';
1697 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1698 _putenv (strdup (buf
));
1700 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1702 /* FIXME: should use substring of get_emacs_configuration ().
1703 But I don't think the Windows build supports alpha, mips etc
1704 anymore, so have taken the easy option for now. */
1705 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1708 p
= strrchr (modname
, '\\');
1712 p
= strrchr (modname
, '\\');
1713 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1715 char buf
[SET_ENV_BUF_SIZE
];
1718 for (p
= modname
; *p
; p
++)
1719 if (*p
== '\\') *p
= '/';
1721 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1722 _putenv (strdup (buf
));
1728 for (i
= 0; i
< N_ENV_VARS
; i
++)
1730 if (!getenv (env_vars
[i
].name
))
1734 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1735 /* Also ignore empty environment variables. */
1739 lpval
= env_vars
[i
].def_value
;
1740 dwType
= REG_EXPAND_SZ
;
1746 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1748 if (dwType
== REG_EXPAND_SZ
)
1749 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1750 else if (dwType
== REG_SZ
)
1751 strcpy (buf1
, lpval
);
1752 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1754 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1756 _putenv (strdup (buf2
));
1766 /* Rebuild system configuration to reflect invoking system. */
1767 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1769 /* Another special case: on NT, the PATH variable is actually named
1770 "Path" although cmd.exe (perhaps NT itself) arranges for
1771 environment variable lookup and setting to be case insensitive.
1772 However, Emacs assumes a fully case sensitive environment, so we
1773 need to change "Path" to "PATH" to match the expectations of
1774 various elisp packages. We do this by the sneaky method of
1775 modifying the string in the C runtime environ entry.
1777 The same applies to COMSPEC. */
1781 for (envp
= environ
; *envp
; envp
++)
1782 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1783 memcpy (*envp
, "PATH=", 5);
1784 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1785 memcpy (*envp
, "COMSPEC=", 8);
1788 /* Remember the initial working directory for getwd, then make the
1789 real wd be the location of emacs.exe to avoid conflicts when
1790 renaming or deleting directories. (We also don't call chdir when
1791 running subprocesses for the same reason.) */
1792 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1797 static char modname
[MAX_PATH
];
1799 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1801 if ((p
= strrchr (modname
, '\\')) == NULL
)
1805 SetCurrentDirectory (modname
);
1807 /* Ensure argv[0] has the full path to Emacs. */
1812 /* Determine if there is a middle mouse button, to allow parse_button
1813 to decide whether right mouse events should be mouse-2 or
1815 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1821 emacs_root_dir (void)
1823 static char root_dir
[FILENAME_MAX
];
1826 p
= getenv ("emacs_dir");
1829 strcpy (root_dir
, p
);
1830 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1831 dostounix_filename (root_dir
);
1835 /* We don't have scripts to automatically determine the system configuration
1836 for Emacs before it's compiled, and we don't want to have to make the
1837 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1841 get_emacs_configuration (void)
1843 char *arch
, *oem
, *os
;
1845 static char configuration_buffer
[32];
1847 /* Determine the processor type. */
1848 switch (get_processor_type ())
1851 #ifdef PROCESSOR_INTEL_386
1852 case PROCESSOR_INTEL_386
:
1853 case PROCESSOR_INTEL_486
:
1854 case PROCESSOR_INTEL_PENTIUM
:
1859 #ifdef PROCESSOR_MIPS_R2000
1860 case PROCESSOR_MIPS_R2000
:
1861 case PROCESSOR_MIPS_R3000
:
1862 case PROCESSOR_MIPS_R4000
:
1867 #ifdef PROCESSOR_ALPHA_21064
1868 case PROCESSOR_ALPHA_21064
:
1878 /* Use the OEM field to reflect the compiler/library combination. */
1880 #define COMPILER_NAME "msvc"
1883 #define COMPILER_NAME "mingw"
1885 #define COMPILER_NAME "unknown"
1888 oem
= COMPILER_NAME
;
1890 switch (osinfo_cache
.dwPlatformId
) {
1891 case VER_PLATFORM_WIN32_NT
:
1893 build_num
= osinfo_cache
.dwBuildNumber
;
1895 case VER_PLATFORM_WIN32_WINDOWS
:
1896 if (osinfo_cache
.dwMinorVersion
== 0) {
1901 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1903 case VER_PLATFORM_WIN32s
:
1904 /* Not supported, should not happen. */
1906 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1914 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1915 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1916 get_w32_major_version (), get_w32_minor_version (), build_num
);
1918 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1921 return configuration_buffer
;
1925 get_emacs_configuration_options (void)
1927 static char options_buffer
[256];
1929 /* Work out the effective configure options for this build. */
1931 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1934 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1936 #define COMPILER_VERSION ""
1940 sprintf (options_buffer
, COMPILER_VERSION
);
1942 strcat (options_buffer
, " --no-opt");
1945 strcat (options_buffer
, " --cflags");
1946 strcat (options_buffer
, USER_CFLAGS
);
1949 strcat (options_buffer
, " --ldflags");
1950 strcat (options_buffer
, USER_LDFLAGS
);
1952 return options_buffer
;
1956 #include <sys/timeb.h>
1958 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1960 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1965 tv
->tv_sec
= tb
.time
;
1966 tv
->tv_usec
= tb
.millitm
* 1000L;
1967 /* Implementation note: _ftime sometimes doesn't update the dstflag
1968 according to the new timezone when the system timezone is
1969 changed. We could fix that by using GetSystemTime and
1970 GetTimeZoneInformation, but that doesn't seem necessary, since
1971 Emacs always calls gettimeofday with the 2nd argument NULL (see
1975 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1976 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1980 /* ------------------------------------------------------------------------- */
1981 /* IO support and wrapper functions for W32 API. */
1982 /* ------------------------------------------------------------------------- */
1984 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1985 on network directories, so we handle that case here.
1986 (Ulrich Leodolter, 1/11/95). */
1988 sys_ctime (const time_t *t
)
1990 char *str
= (char *) ctime (t
);
1991 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1994 /* Emulate sleep...we could have done this with a define, but that
1995 would necessitate including windows.h in the files that used it.
1996 This is much easier. */
1998 sys_sleep (int seconds
)
2000 Sleep (seconds
* 1000);
2003 /* Internal MSVC functions for low-level descriptor munging */
2004 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2005 extern int __cdecl
_free_osfhnd (int fd
);
2007 /* parallel array of private info on file handles */
2008 filedesc fd_info
[ MAXDESC
];
2010 typedef struct volume_info_data
{
2011 struct volume_info_data
* next
;
2013 /* time when info was obtained */
2016 /* actual volume info */
2025 /* Global referenced by various functions. */
2026 static volume_info_data volume_info
;
2028 /* Vector to indicate which drives are local and fixed (for which cached
2029 data never expires). */
2030 static BOOL fixed_drives
[26];
2032 /* Consider cached volume information to be stale if older than 10s,
2033 at least for non-local drives. Info for fixed drives is never stale. */
2034 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2035 #define VOLINFO_STILL_VALID( root_dir, info ) \
2036 ( ( isalpha (root_dir[0]) && \
2037 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2038 || GetTickCount () - info->timestamp < 10000 )
2040 /* Cache support functions. */
2042 /* Simple linked list with linear search is sufficient. */
2043 static volume_info_data
*volume_cache
= NULL
;
2045 static volume_info_data
*
2046 lookup_volume_info (char * root_dir
)
2048 volume_info_data
* info
;
2050 for (info
= volume_cache
; info
; info
= info
->next
)
2051 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2057 add_volume_info (char * root_dir
, volume_info_data
* info
)
2059 info
->root_dir
= xstrdup (root_dir
);
2060 info
->next
= volume_cache
;
2061 volume_cache
= info
;
2065 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2066 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2067 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2069 GetCachedVolumeInformation (char * root_dir
)
2071 volume_info_data
* info
;
2072 char default_root
[ MAX_PATH
];
2074 /* NULL for root_dir means use root from current directory. */
2075 if (root_dir
== NULL
)
2077 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2079 parse_root (default_root
, &root_dir
);
2081 root_dir
= default_root
;
2084 /* Local fixed drives can be cached permanently. Removable drives
2085 cannot be cached permanently, since the volume name and serial
2086 number (if nothing else) can change. Remote drives should be
2087 treated as if they are removable, since there is no sure way to
2088 tell whether they are or not. Also, the UNC association of drive
2089 letters mapped to remote volumes can be changed at any time (even
2090 by other processes) without notice.
2092 As a compromise, so we can benefit from caching info for remote
2093 volumes, we use a simple expiry mechanism to invalidate cache
2094 entries that are more than ten seconds old. */
2097 /* No point doing this, because WNetGetConnection is even slower than
2098 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2099 GetDriveType is about the only call of this type which does not
2100 involve network access, and so is extremely quick). */
2102 /* Map drive letter to UNC if remote. */
2103 if ( isalpha (root_dir
[0]) && !fixed
[ DRIVE_INDEX (root_dir
[0]) ] )
2105 char remote_name
[ 256 ];
2106 char drive
[3] = { root_dir
[0], ':' };
2108 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2110 /* do something */ ;
2114 info
= lookup_volume_info (root_dir
);
2116 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2124 /* Info is not cached, or is stale. */
2125 if (!GetVolumeInformation (root_dir
,
2126 name
, sizeof (name
),
2130 type
, sizeof (type
)))
2133 /* Cache the volume information for future use, overwriting existing
2134 entry if present. */
2137 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2138 add_volume_info (root_dir
, info
);
2146 info
->name
= xstrdup (name
);
2147 info
->serialnum
= serialnum
;
2148 info
->maxcomp
= maxcomp
;
2149 info
->flags
= flags
;
2150 info
->type
= xstrdup (type
);
2151 info
->timestamp
= GetTickCount ();
2157 /* Get information on the volume where name is held; set path pointer to
2158 start of pathname in name (past UNC header\volume header if present). */
2160 get_volume_info (const char * name
, const char ** pPath
)
2162 char temp
[MAX_PATH
];
2163 char *rootname
= NULL
; /* default to current volume */
2164 volume_info_data
* info
;
2169 /* find the root name of the volume if given */
2170 if (isalpha (name
[0]) && name
[1] == ':')
2178 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2185 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2198 info
= GetCachedVolumeInformation (rootname
);
2201 /* Set global referenced by other functions. */
2202 volume_info
= *info
;
2208 /* Determine if volume is FAT format (ie. only supports short 8.3
2209 names); also set path pointer to start of pathname in name. */
2211 is_fat_volume (const char * name
, const char ** pPath
)
2213 if (get_volume_info (name
, pPath
))
2214 return (volume_info
.maxcomp
== 12);
2218 /* Map filename to a valid 8.3 name if necessary. */
2220 map_w32_filename (const char * name
, const char ** pPath
)
2222 static char shortname
[MAX_PATH
];
2223 char * str
= shortname
;
2226 const char * save_name
= name
;
2228 if (strlen (name
) >= MAX_PATH
)
2230 /* Return a filename which will cause callers to fail. */
2231 strcpy (shortname
, "?");
2235 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2237 register int left
= 8; /* maximum number of chars in part */
2238 register int extn
= 0; /* extension added? */
2239 register int dots
= 2; /* maximum number of dots allowed */
2242 *str
++ = *name
++; /* skip past UNC header */
2244 while ((c
= *name
++))
2251 extn
= 0; /* reset extension flags */
2252 dots
= 2; /* max 2 dots */
2253 left
= 8; /* max length 8 for main part */
2257 extn
= 0; /* reset extension flags */
2258 dots
= 2; /* max 2 dots */
2259 left
= 8; /* max length 8 for main part */
2264 /* Convert path components of the form .xxx to _xxx,
2265 but leave . and .. as they are. This allows .emacs
2266 to be read as _emacs, for example. */
2270 IS_DIRECTORY_SEP (*name
))
2285 extn
= 1; /* we've got an extension */
2286 left
= 3; /* 3 chars in extension */
2290 /* any embedded dots after the first are converted to _ */
2295 case '#': /* don't lose these, they're important */
2297 str
[-1] = c
; /* replace last character of part */
2302 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2304 dots
= 0; /* started a path component */
2313 strcpy (shortname
, name
);
2314 unixtodos_filename (shortname
);
2318 *pPath
= shortname
+ (path
- save_name
);
2324 is_exec (const char * name
)
2326 char * p
= strrchr (name
, '.');
2329 && (xstrcasecmp (p
, ".exe") == 0 ||
2330 xstrcasecmp (p
, ".com") == 0 ||
2331 xstrcasecmp (p
, ".bat") == 0 ||
2332 xstrcasecmp (p
, ".cmd") == 0));
2335 /* Emulate the Unix directory procedures opendir, closedir,
2336 and readdir. We can't use the procedures supplied in sysdep.c,
2337 so we provide them here. */
2339 struct direct dir_static
; /* simulated directory contents */
2340 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2341 static int dir_is_fat
;
2342 static char dir_pathname
[MAXPATHLEN
+1];
2343 static WIN32_FIND_DATA dir_find_data
;
2345 /* Support shares on a network resource as subdirectories of a read-only
2347 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2348 HANDLE
open_unc_volume (const char *);
2349 char *read_unc_volume (HANDLE
, char *, int);
2350 void close_unc_volume (HANDLE
);
2353 opendir (char *filename
)
2357 /* Opening is done by FindFirstFile. However, a read is inherent to
2358 this operation, so we defer the open until read time. */
2360 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2362 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2365 if (is_unc_volume (filename
))
2367 wnet_enum_handle
= open_unc_volume (filename
);
2368 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2372 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2379 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2380 dir_pathname
[MAXPATHLEN
] = '\0';
2381 dir_is_fat
= is_fat_volume (filename
, NULL
);
2387 closedir (DIR *dirp
)
2389 /* If we have a find-handle open, close it. */
2390 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2392 FindClose (dir_find_handle
);
2393 dir_find_handle
= INVALID_HANDLE_VALUE
;
2395 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2397 close_unc_volume (wnet_enum_handle
);
2398 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2400 xfree ((char *) dirp
);
2406 int downcase
= !NILP (Vw32_downcase_file_names
);
2408 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2410 if (!read_unc_volume (wnet_enum_handle
,
2411 dir_find_data
.cFileName
,
2415 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2416 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2418 char filename
[MAXNAMLEN
+ 3];
2421 strcpy (filename
, dir_pathname
);
2422 ln
= strlen (filename
) - 1;
2423 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2424 strcat (filename
, "\\");
2425 strcat (filename
, "*");
2427 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2429 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2434 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2438 /* Emacs never uses this value, so don't bother making it match
2439 value returned by stat(). */
2440 dir_static
.d_ino
= 1;
2442 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2444 /* If the file name in cFileName[] includes `?' characters, it means
2445 the original file name used characters that cannot be represented
2446 by the current ANSI codepage. To avoid total lossage, retrieve
2447 the short 8+3 alias of the long file name. */
2448 if (_mbspbrk (dir_static
.d_name
, "?"))
2450 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2451 downcase
= 1; /* 8+3 aliases are returned in all caps */
2453 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2454 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2455 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
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_find_data
.cFileName
, "?"))
2463 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2464 /* 8+3 aliases are returned in all caps, which could break
2465 various alists that look at filenames' extensions. */
2469 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2470 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2472 _strlwr (dir_static
.d_name
);
2476 for (p
= dir_static
.d_name
; *p
; p
++)
2477 if (*p
>= 'a' && *p
<= 'z')
2480 _strlwr (dir_static
.d_name
);
2487 open_unc_volume (const char *path
)
2493 nr
.dwScope
= RESOURCE_GLOBALNET
;
2494 nr
.dwType
= RESOURCETYPE_DISK
;
2495 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2496 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2497 nr
.lpLocalName
= NULL
;
2498 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2499 nr
.lpComment
= NULL
;
2500 nr
.lpProvider
= NULL
;
2502 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2503 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2505 if (result
== NO_ERROR
)
2508 return INVALID_HANDLE_VALUE
;
2512 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2516 DWORD bufsize
= 512;
2521 buffer
= alloca (bufsize
);
2522 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2523 if (result
!= NO_ERROR
)
2526 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2527 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2529 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2532 strncpy (readbuf
, ptr
, size
);
2537 close_unc_volume (HANDLE henum
)
2539 if (henum
!= INVALID_HANDLE_VALUE
)
2540 WNetCloseEnum (henum
);
2544 unc_volume_file_attributes (const char *path
)
2549 henum
= open_unc_volume (path
);
2550 if (henum
== INVALID_HANDLE_VALUE
)
2553 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2555 close_unc_volume (henum
);
2560 /* Ensure a network connection is authenticated. */
2562 logon_network_drive (const char *path
)
2564 NETRESOURCE resource
;
2565 char share
[MAX_PATH
];
2570 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2571 drvtype
= DRIVE_REMOTE
;
2572 else if (path
[0] == '\0' || path
[1] != ':')
2573 drvtype
= GetDriveType (NULL
);
2580 drvtype
= GetDriveType (drive
);
2583 /* Only logon to networked drives. */
2584 if (drvtype
!= DRIVE_REMOTE
)
2588 strncpy (share
, path
, MAX_PATH
);
2589 /* Truncate to just server and share name. */
2590 for (i
= 2; i
< MAX_PATH
; i
++)
2592 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2599 resource
.dwType
= RESOURCETYPE_DISK
;
2600 resource
.lpLocalName
= NULL
;
2601 resource
.lpRemoteName
= share
;
2602 resource
.lpProvider
= NULL
;
2604 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2607 /* Shadow some MSVC runtime functions to map requests for long filenames
2608 to reasonable short names if necessary. This was originally added to
2609 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2613 sys_access (const char * path
, int mode
)
2617 /* MSVC implementation doesn't recognize D_OK. */
2618 path
= map_w32_filename (path
, NULL
);
2619 if (is_unc_volume (path
))
2621 attributes
= unc_volume_file_attributes (path
);
2622 if (attributes
== -1) {
2627 else if ((attributes
= GetFileAttributes (path
)) == -1)
2629 /* Should try mapping GetLastError to errno; for now just indicate
2630 that path doesn't exist. */
2634 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2639 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2644 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2653 sys_chdir (const char * path
)
2655 return _chdir (map_w32_filename (path
, NULL
));
2659 sys_chmod (const char * path
, int mode
)
2661 return _chmod (map_w32_filename (path
, NULL
), mode
);
2665 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2667 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2673 sys_creat (const char * path
, int mode
)
2675 return _creat (map_w32_filename (path
, NULL
), mode
);
2679 sys_fopen (const char * path
, const char * mode
)
2683 const char * mode_save
= mode
;
2685 /* Force all file handles to be non-inheritable. This is necessary to
2686 ensure child processes don't unwittingly inherit handles that might
2687 prevent future file access. */
2691 else if (mode
[0] == 'w' || mode
[0] == 'a')
2692 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2696 /* Only do simplistic option parsing. */
2700 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2703 else if (mode
[0] == 'b')
2708 else if (mode
[0] == 't')
2715 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2719 return _fdopen (fd
, mode_save
);
2722 /* This only works on NTFS volumes, but is useful to have. */
2724 sys_link (const char * old
, const char * new)
2728 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2730 if (old
== NULL
|| new == NULL
)
2736 strcpy (oldname
, map_w32_filename (old
, NULL
));
2737 strcpy (newname
, map_w32_filename (new, NULL
));
2739 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2740 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2741 if (fileh
!= INVALID_HANDLE_VALUE
)
2745 /* Confusingly, the "alternate" stream name field does not apply
2746 when restoring a hard link, and instead contains the actual
2747 stream data for the link (ie. the name of the link to create).
2748 The WIN32_STREAM_ID structure before the cStreamName field is
2749 the stream header, which is then immediately followed by the
2753 WIN32_STREAM_ID wid
;
2754 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2757 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2758 data
.wid
.cStreamName
, MAX_PATH
);
2761 LPVOID context
= NULL
;
2764 data
.wid
.dwStreamId
= BACKUP_LINK
;
2765 data
.wid
.dwStreamAttributes
= 0;
2766 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2767 data
.wid
.Size
.HighPart
= 0;
2768 data
.wid
.dwStreamNameSize
= 0;
2770 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2771 offsetof (WIN32_STREAM_ID
, cStreamName
)
2772 + data
.wid
.Size
.LowPart
,
2773 &wbytes
, FALSE
, FALSE
, &context
)
2774 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2781 /* Should try mapping GetLastError to errno; for now just
2782 indicate a general error (eg. links not supported). */
2783 errno
= EINVAL
; // perhaps EMLINK?
2787 CloseHandle (fileh
);
2796 sys_mkdir (const char * path
)
2798 return _mkdir (map_w32_filename (path
, NULL
));
2801 /* Because of long name mapping issues, we need to implement this
2802 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2803 a unique name, instead of setting the input template to an empty
2806 Standard algorithm seems to be use pid or tid with a letter on the
2807 front (in place of the 6 X's) and cycle through the letters to find a
2808 unique name. We extend that to allow any reasonable character as the
2809 first of the 6 X's. */
2811 sys_mktemp (char * template)
2815 unsigned uid
= GetCurrentThreadId ();
2816 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2818 if (template == NULL
)
2820 p
= template + strlen (template);
2822 /* replace up to the last 5 X's with uid in decimal */
2823 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2825 p
[0] = '0' + uid
% 10;
2829 if (i
< 0 && p
[0] == 'X')
2834 int save_errno
= errno
;
2835 p
[0] = first_char
[i
];
2836 if (sys_access (template, 0) < 0)
2842 while (++i
< sizeof (first_char
));
2845 /* Template is badly formed or else we can't generate a unique name,
2846 so return empty string */
2852 sys_open (const char * path
, int oflag
, int mode
)
2854 const char* mpath
= map_w32_filename (path
, NULL
);
2855 /* Try to open file without _O_CREAT, to be able to write to hidden
2856 and system files. Force all file handles to be
2858 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2861 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2865 sys_rename (const char * oldname
, const char * newname
)
2868 char temp
[MAX_PATH
];
2870 /* MoveFile on Windows 95 doesn't correctly change the short file name
2871 alias in a number of circumstances (it is not easy to predict when
2872 just by looking at oldname and newname, unfortunately). In these
2873 cases, renaming through a temporary name avoids the problem.
2875 A second problem on Windows 95 is that renaming through a temp name when
2876 newname is uppercase fails (the final long name ends up in
2877 lowercase, although the short alias might be uppercase) UNLESS the
2878 long temp name is not 8.3.
2880 So, on Windows 95 we always rename through a temp name, and we make sure
2881 the temp name has a long extension to ensure correct renaming. */
2883 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2885 if (os_subtype
== OS_WIN95
)
2891 oldname
= map_w32_filename (oldname
, NULL
);
2892 if (o
= strrchr (oldname
, '\\'))
2895 o
= (char *) oldname
;
2897 if (p
= strrchr (temp
, '\\'))
2904 /* Force temp name to require a manufactured 8.3 alias - this
2905 seems to make the second rename work properly. */
2906 sprintf (p
, "_.%s.%u", o
, i
);
2908 result
= rename (oldname
, temp
);
2910 /* This loop must surely terminate! */
2911 while (result
< 0 && errno
== EEXIST
);
2916 /* Emulate Unix behavior - newname is deleted if it already exists
2917 (at least if it is a file; don't do this for directories).
2919 Since we mustn't do this if we are just changing the case of the
2920 file name (we would end up deleting the file we are trying to
2921 rename!), we let rename detect if the destination file already
2922 exists - that way we avoid the possible pitfalls of trying to
2923 determine ourselves whether two names really refer to the same
2924 file, which is not always possible in the general case. (Consider
2925 all the permutations of shared or subst'd drives, etc.) */
2927 newname
= map_w32_filename (newname
, NULL
);
2928 result
= rename (temp
, newname
);
2932 && _chmod (newname
, 0666) == 0
2933 && _unlink (newname
) == 0)
2934 result
= rename (temp
, newname
);
2940 sys_rmdir (const char * path
)
2942 return _rmdir (map_w32_filename (path
, NULL
));
2946 sys_unlink (const char * path
)
2948 path
= map_w32_filename (path
, NULL
);
2950 /* On Unix, unlink works without write permission. */
2951 _chmod (path
, 0666);
2952 return _unlink (path
);
2955 static FILETIME utc_base_ft
;
2956 static ULONGLONG utc_base
; /* In 100ns units */
2957 static int init
= 0;
2959 #define FILETIME_TO_U64(result, ft) \
2961 ULARGE_INTEGER uiTemp; \
2962 uiTemp.LowPart = (ft).dwLowDateTime; \
2963 uiTemp.HighPart = (ft).dwHighDateTime; \
2964 result = uiTemp.QuadPart; \
2968 initialize_utc_base ()
2970 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2979 st
.wMilliseconds
= 0;
2981 SystemTimeToFileTime (&st
, &utc_base_ft
);
2982 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2986 convert_time (FILETIME ft
)
2992 initialize_utc_base ();
2996 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2999 FILETIME_TO_U64 (tmp
, ft
);
3000 return (time_t) ((tmp
- utc_base
) / 10000000L);
3005 convert_from_time_t (time_t time
, FILETIME
* pft
)
3011 initialize_utc_base ();
3015 /* time in 100ns units since 1-Jan-1601 */
3016 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3017 pft
->dwHighDateTime
= tmp
.HighPart
;
3018 pft
->dwLowDateTime
= tmp
.LowPart
;
3022 /* No reason to keep this; faking inode values either by hashing or even
3023 using the file index from GetInformationByHandle, is not perfect and
3024 so by default Emacs doesn't use the inode values on Windows.
3025 Instead, we now determine file-truename correctly (except for
3026 possible drive aliasing etc). */
3028 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3030 hashval (const unsigned char * str
)
3035 h
= (h
<< 4) + *str
++;
3041 /* Return the hash value of the canonical pathname, excluding the
3042 drive/UNC header, to get a hopefully unique inode number. */
3044 generate_inode_val (const char * name
)
3046 char fullname
[ MAX_PATH
];
3050 /* Get the truly canonical filename, if it exists. (Note: this
3051 doesn't resolve aliasing due to subst commands, or recognise hard
3053 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3056 parse_root (fullname
, &p
);
3057 /* Normal W32 filesystems are still case insensitive. */
3064 static PSECURITY_DESCRIPTOR
3065 get_file_security_desc (const char *fname
)
3067 PSECURITY_DESCRIPTOR psd
= NULL
;
3069 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3070 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3072 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3074 err
= GetLastError ();
3075 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3079 psd
= xmalloc (sd_len
);
3080 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3092 unsigned n_subauthorities
;
3094 /* Use the last sub-authority value of the RID, the relative
3095 portion of the SID, as user/group ID. */
3096 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3097 if (n_subauthorities
< 1)
3098 return 0; /* the "World" RID */
3099 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3102 /* Caching SID and account values for faster lokup. */
3105 # define FLEXIBLE_ARRAY_MEMBER
3107 # define FLEXIBLE_ARRAY_MEMBER 1
3112 struct w32_id
*next
;
3114 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3117 static struct w32_id
*w32_idlist
;
3120 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3122 struct w32_id
*tail
, *found
;
3124 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3126 if (equal_sid ((PSID
)tail
->sid
, sid
))
3135 strcpy (name
, found
->name
);
3143 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3146 struct w32_id
*new_entry
;
3148 /* We don't want to leave behind stale cache from when Emacs was
3152 sid_len
= get_length_sid (sid
);
3153 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3156 new_entry
->rid
= id
;
3157 strcpy (new_entry
->name
, name
);
3158 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3159 new_entry
->next
= w32_idlist
;
3160 w32_idlist
= new_entry
;
3169 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3170 unsigned *id
, char *nm
, int what
)
3173 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3175 SID_NAME_USE ignore
;
3177 DWORD name_len
= sizeof (name
);
3179 DWORD domain_len
= sizeof (domain
);
3185 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3186 else if (what
== GID
)
3187 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3191 if (!result
|| !is_valid_sid (sid
))
3193 else if (!w32_cached_id (sid
, id
, nm
))
3195 /* If FNAME is a UNC, we need to lookup account on the
3196 specified machine. */
3197 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3198 && fname
[2] != '\0')
3203 for (s
= fname
+ 2, p
= machine
;
3204 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3210 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3211 domain
, &domain_len
, &ignore
)
3212 || name_len
> UNLEN
+1)
3216 *id
= get_rid (sid
);
3218 w32_add_to_cache (sid
, *id
, name
);
3225 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3229 int dflt_usr
= 0, dflt_grp
= 0;
3238 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3240 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3243 /* Consider files to belong to current user/group, if we cannot get
3244 more accurate information. */
3247 st
->st_uid
= dflt_passwd
.pw_uid
;
3248 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3252 st
->st_gid
= dflt_passwd
.pw_gid
;
3253 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3257 /* Return non-zero if NAME is a potentially slow filesystem. */
3259 is_slow_fs (const char *name
)
3264 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3265 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3266 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3267 devtype
= GetDriveType (NULL
); /* use root of current drive */
3270 /* GetDriveType needs the root directory of the drive. */
3271 strncpy (drive_root
, name
, 2);
3272 drive_root
[2] = '\\';
3273 drive_root
[3] = '\0';
3274 devtype
= GetDriveType (drive_root
);
3276 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3279 /* MSVC stat function can't cope with UNC names and has other bugs, so
3280 replace it with our own. This also allows us to calculate consistent
3281 inode values without hacks in the main Emacs code. */
3283 stat (const char * path
, struct stat
* buf
)
3288 WIN32_FIND_DATA wfd
;
3290 unsigned __int64 fake_inode
;
3293 int rootdir
= FALSE
;
3294 PSECURITY_DESCRIPTOR psd
= NULL
;
3296 if (path
== NULL
|| buf
== NULL
)
3302 name
= (char *) map_w32_filename (path
, &path
);
3303 /* Must be valid filename, no wild cards or other invalid
3304 characters. We use _mbspbrk to support multibyte strings that
3305 might look to strpbrk as if they included literal *, ?, and other
3306 characters mentioned below that are disallowed by Windows
3308 if (_mbspbrk (name
, "*?|<>\""))
3314 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3315 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3316 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3321 /* Remove trailing directory separator, unless name is the root
3322 directory of a drive or UNC volume in which case ensure there
3323 is a trailing separator. */
3324 len
= strlen (name
);
3325 rootdir
= (path
>= name
+ len
- 1
3326 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3327 name
= strcpy (alloca (len
+ 2), name
);
3329 if (is_unc_volume (name
))
3331 DWORD attrs
= unc_volume_file_attributes (name
);
3336 memset (&wfd
, 0, sizeof (wfd
));
3337 wfd
.dwFileAttributes
= attrs
;
3338 wfd
.ftCreationTime
= utc_base_ft
;
3339 wfd
.ftLastAccessTime
= utc_base_ft
;
3340 wfd
.ftLastWriteTime
= utc_base_ft
;
3341 strcpy (wfd
.cFileName
, name
);
3345 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3346 strcat (name
, "\\");
3347 if (GetDriveType (name
) < 2)
3352 memset (&wfd
, 0, sizeof (wfd
));
3353 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3354 wfd
.ftCreationTime
= utc_base_ft
;
3355 wfd
.ftLastAccessTime
= utc_base_ft
;
3356 wfd
.ftLastWriteTime
= utc_base_ft
;
3357 strcpy (wfd
.cFileName
, name
);
3361 if (IS_DIRECTORY_SEP (name
[len
-1]))
3364 /* (This is hacky, but helps when doing file completions on
3365 network drives.) Optimize by using information available from
3366 active readdir if possible. */
3367 len
= strlen (dir_pathname
);
3368 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3370 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3371 && strnicmp (name
, dir_pathname
, len
) == 0
3372 && IS_DIRECTORY_SEP (name
[len
])
3373 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3375 /* This was the last entry returned by readdir. */
3376 wfd
= dir_find_data
;
3380 logon_network_drive (name
);
3382 fh
= FindFirstFile (name
, &wfd
);
3383 if (fh
== INVALID_HANDLE_VALUE
)
3392 if (!(NILP (Vw32_get_true_file_attributes
)
3393 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3394 /* No access rights required to get info. */
3395 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3396 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3397 != INVALID_HANDLE_VALUE
)
3399 /* This is more accurate in terms of gettting the correct number
3400 of links, but is quite slow (it is noticeable when Emacs is
3401 making a list of file name completions). */
3402 BY_HANDLE_FILE_INFORMATION info
;
3404 if (GetFileInformationByHandle (fh
, &info
))
3406 buf
->st_nlink
= info
.nNumberOfLinks
;
3407 /* Might as well use file index to fake inode values, but this
3408 is not guaranteed to be unique unless we keep a handle open
3409 all the time (even then there are situations where it is
3410 not unique). Reputedly, there are at most 48 bits of info
3411 (on NTFS, presumably less on FAT). */
3412 fake_inode
= info
.nFileIndexHigh
;
3414 fake_inode
+= info
.nFileIndexLow
;
3422 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3424 buf
->st_mode
= S_IFDIR
;
3428 switch (GetFileType (fh
))
3430 case FILE_TYPE_DISK
:
3431 buf
->st_mode
= S_IFREG
;
3433 case FILE_TYPE_PIPE
:
3434 buf
->st_mode
= S_IFIFO
;
3436 case FILE_TYPE_CHAR
:
3437 case FILE_TYPE_UNKNOWN
:
3439 buf
->st_mode
= S_IFCHR
;
3443 psd
= get_file_security_desc (name
);
3444 get_file_owner_and_group (psd
, name
, buf
);
3448 /* Don't bother to make this information more accurate. */
3449 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3454 get_file_owner_and_group (NULL
, name
, buf
);
3459 /* Not sure if there is any point in this. */
3460 if (!NILP (Vw32_generate_fake_inodes
))
3461 fake_inode
= generate_inode_val (name
);
3462 else if (fake_inode
== 0)
3464 /* For want of something better, try to make everything unique. */
3465 static DWORD gen_num
= 0;
3466 fake_inode
= ++gen_num
;
3470 /* MSVC defines _ino_t to be short; other libc's might not. */
3471 if (sizeof (buf
->st_ino
) == 2)
3472 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3474 buf
->st_ino
= fake_inode
;
3476 /* volume_info is set indirectly by map_w32_filename */
3477 buf
->st_dev
= volume_info
.serialnum
;
3478 buf
->st_rdev
= volume_info
.serialnum
;
3481 buf
->st_size
= wfd
.nFileSizeHigh
;
3482 buf
->st_size
<<= 32;
3483 buf
->st_size
+= wfd
.nFileSizeLow
;
3485 /* Convert timestamps to Unix format. */
3486 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3487 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3488 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3489 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3490 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3492 /* determine rwx permissions */
3493 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3494 permission
= S_IREAD
;
3496 permission
= S_IREAD
| S_IWRITE
;
3498 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3499 permission
|= S_IEXEC
;
3500 else if (is_exec (name
))
3501 permission
|= S_IEXEC
;
3503 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3508 /* Provide fstat and utime as well as stat for consistent handling of
3511 fstat (int desc
, struct stat
* buf
)
3513 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3514 BY_HANDLE_FILE_INFORMATION info
;
3515 unsigned __int64 fake_inode
;
3518 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3520 case FILE_TYPE_DISK
:
3521 buf
->st_mode
= S_IFREG
;
3522 if (!GetFileInformationByHandle (fh
, &info
))
3528 case FILE_TYPE_PIPE
:
3529 buf
->st_mode
= S_IFIFO
;
3531 case FILE_TYPE_CHAR
:
3532 case FILE_TYPE_UNKNOWN
:
3534 buf
->st_mode
= S_IFCHR
;
3536 memset (&info
, 0, sizeof (info
));
3537 info
.dwFileAttributes
= 0;
3538 info
.ftCreationTime
= utc_base_ft
;
3539 info
.ftLastAccessTime
= utc_base_ft
;
3540 info
.ftLastWriteTime
= utc_base_ft
;
3543 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3544 buf
->st_mode
= S_IFDIR
;
3546 buf
->st_nlink
= info
.nNumberOfLinks
;
3547 /* Might as well use file index to fake inode values, but this
3548 is not guaranteed to be unique unless we keep a handle open
3549 all the time (even then there are situations where it is
3550 not unique). Reputedly, there are at most 48 bits of info
3551 (on NTFS, presumably less on FAT). */
3552 fake_inode
= info
.nFileIndexHigh
;
3554 fake_inode
+= info
.nFileIndexLow
;
3556 /* MSVC defines _ino_t to be short; other libc's might not. */
3557 if (sizeof (buf
->st_ino
) == 2)
3558 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3560 buf
->st_ino
= fake_inode
;
3562 /* Consider files to belong to current user.
3563 FIXME: this should use GetSecurityInfo API, but it is only
3564 available for _WIN32_WINNT >= 0x501. */
3565 buf
->st_uid
= dflt_passwd
.pw_uid
;
3566 buf
->st_gid
= dflt_passwd
.pw_gid
;
3567 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3568 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3570 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3571 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3573 buf
->st_size
= info
.nFileSizeHigh
;
3574 buf
->st_size
<<= 32;
3575 buf
->st_size
+= info
.nFileSizeLow
;
3577 /* Convert timestamps to Unix format. */
3578 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3579 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3580 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3581 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3582 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3584 /* determine rwx permissions */
3585 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3586 permission
= S_IREAD
;
3588 permission
= S_IREAD
| S_IWRITE
;
3590 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3591 permission
|= S_IEXEC
;
3594 #if 0 /* no way of knowing the filename */
3595 char * p
= strrchr (name
, '.');
3597 (xstrcasecmp (p
, ".exe") == 0 ||
3598 xstrcasecmp (p
, ".com") == 0 ||
3599 xstrcasecmp (p
, ".bat") == 0 ||
3600 xstrcasecmp (p
, ".cmd") == 0))
3601 permission
|= S_IEXEC
;
3605 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3611 utime (const char *name
, struct utimbuf
*times
)
3613 struct utimbuf deftime
;
3620 deftime
.modtime
= deftime
.actime
= time (NULL
);
3624 /* Need write access to set times. */
3625 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3626 0, OPEN_EXISTING
, 0, NULL
);
3629 convert_from_time_t (times
->actime
, &atime
);
3630 convert_from_time_t (times
->modtime
, &mtime
);
3631 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3648 /* Support for browsing other processes and their attributes. See
3649 process.c for the Lisp bindings. */
3651 /* Helper wrapper functions. */
3654 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
3656 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3658 if (g_b_init_create_toolhelp32_snapshot
== 0)
3660 g_b_init_create_toolhelp32_snapshot
= 1;
3661 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3662 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3663 "CreateToolhelp32Snapshot");
3665 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3667 return INVALID_HANDLE_VALUE
;
3669 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3673 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3675 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3677 if (g_b_init_process32_first
== 0)
3679 g_b_init_process32_first
= 1;
3680 s_pfn_Process32_First
= (Process32First_Proc
)
3681 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3684 if (s_pfn_Process32_First
== NULL
)
3688 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3692 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3694 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3696 if (g_b_init_process32_next
== 0)
3698 g_b_init_process32_next
= 1;
3699 s_pfn_Process32_Next
= (Process32Next_Proc
)
3700 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3703 if (s_pfn_Process32_Next
== NULL
)
3707 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3711 open_thread_token (HANDLE ThreadHandle
,
3712 DWORD DesiredAccess
,
3714 PHANDLE TokenHandle
)
3716 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3717 HMODULE hm_advapi32
= NULL
;
3718 if (is_windows_9x () == TRUE
)
3720 SetLastError (ERROR_NOT_SUPPORTED
);
3723 if (g_b_init_open_thread_token
== 0)
3725 g_b_init_open_thread_token
= 1;
3726 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3727 s_pfn_Open_Thread_Token
=
3728 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3730 if (s_pfn_Open_Thread_Token
== NULL
)
3732 SetLastError (ERROR_NOT_SUPPORTED
);
3736 s_pfn_Open_Thread_Token (
3745 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3747 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3748 HMODULE hm_advapi32
= NULL
;
3749 if (is_windows_9x () == TRUE
)
3753 if (g_b_init_impersonate_self
== 0)
3755 g_b_init_impersonate_self
= 1;
3756 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3757 s_pfn_Impersonate_Self
=
3758 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3760 if (s_pfn_Impersonate_Self
== NULL
)
3764 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3768 revert_to_self (void)
3770 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3771 HMODULE hm_advapi32
= NULL
;
3772 if (is_windows_9x () == TRUE
)
3776 if (g_b_init_revert_to_self
== 0)
3778 g_b_init_revert_to_self
= 1;
3779 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3780 s_pfn_Revert_To_Self
=
3781 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3783 if (s_pfn_Revert_To_Self
== NULL
)
3787 return s_pfn_Revert_To_Self ();
3791 get_process_memory_info (HANDLE h_proc
,
3792 PPROCESS_MEMORY_COUNTERS mem_counters
,
3795 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3796 HMODULE hm_psapi
= NULL
;
3797 if (is_windows_9x () == TRUE
)
3801 if (g_b_init_get_process_memory_info
== 0)
3803 g_b_init_get_process_memory_info
= 1;
3804 hm_psapi
= LoadLibrary ("Psapi.dll");
3806 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3807 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3809 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3813 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3817 get_process_working_set_size (HANDLE h_proc
, DWORD
*minrss
, DWORD
*maxrss
)
3819 static GetProcessWorkingSetSize_Proc
3820 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3822 if (is_windows_9x () == TRUE
)
3826 if (g_b_init_get_process_working_set_size
== 0)
3828 g_b_init_get_process_working_set_size
= 1;
3829 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3830 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3831 "GetProcessWorkingSetSize");
3833 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3837 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3841 global_memory_status (MEMORYSTATUS
*buf
)
3843 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3845 if (is_windows_9x () == TRUE
)
3849 if (g_b_init_global_memory_status
== 0)
3851 g_b_init_global_memory_status
= 1;
3852 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3853 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3854 "GlobalMemoryStatus");
3856 if (s_pfn_Global_Memory_Status
== NULL
)
3860 return s_pfn_Global_Memory_Status (buf
);
3864 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
3866 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3868 if (is_windows_9x () == TRUE
)
3872 if (g_b_init_global_memory_status_ex
== 0)
3874 g_b_init_global_memory_status_ex
= 1;
3875 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3876 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3877 "GlobalMemoryStatusEx");
3879 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3883 return s_pfn_Global_Memory_Status_Ex (buf
);
3887 list_system_processes ()
3889 struct gcpro gcpro1
;
3890 Lisp_Object proclist
= Qnil
;
3893 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3895 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3897 PROCESSENTRY32 proc_entry
;
3903 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3904 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3905 res
= process32_next (h_snapshot
, &proc_entry
))
3907 proc_id
= proc_entry
.th32ProcessID
;
3908 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3911 CloseHandle (h_snapshot
);
3913 proclist
= Fnreverse (proclist
);
3920 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3922 TOKEN_PRIVILEGES priv
;
3923 DWORD priv_size
= sizeof (priv
);
3924 DWORD opriv_size
= sizeof (*old_priv
);
3925 HANDLE h_token
= NULL
;
3926 HANDLE h_thread
= GetCurrentThread ();
3930 res
= open_thread_token (h_thread
,
3931 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3933 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3935 if (impersonate_self (SecurityImpersonation
))
3936 res
= open_thread_token (h_thread
,
3937 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3942 priv
.PrivilegeCount
= 1;
3943 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3944 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3945 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3946 old_priv
, &opriv_size
)
3947 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3951 CloseHandle (h_token
);
3957 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3959 DWORD priv_size
= sizeof (*priv
);
3960 HANDLE h_token
= NULL
;
3963 if (open_thread_token (GetCurrentThread (),
3964 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3967 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3968 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3972 CloseHandle (h_token
);
3978 ltime (time_sec
, time_usec
)
3979 long time_sec
, time_usec
;
3981 return list3 (make_number ((time_sec
>> 16) & 0xffff),
3982 make_number (time_sec
& 0xffff),
3983 make_number (time_usec
));
3986 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
3989 process_times (h_proc
, ctime
, etime
, stime
, utime
, ttime
, pcpu
)
3991 Lisp_Object
*ctime
, *etime
, *stime
, *utime
, *ttime
;
3994 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
3995 ULONGLONG tem1
, tem2
, tem3
, tem
;
3998 || !get_process_times_fn
3999 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4000 &ft_kernel
, &ft_user
))
4003 GetSystemTimeAsFileTime (&ft_current
);
4005 FILETIME_TO_U64 (tem1
, ft_kernel
);
4007 *stime
= U64_TO_LISP_TIME (tem1
);
4009 FILETIME_TO_U64 (tem2
, ft_user
);
4011 *utime
= U64_TO_LISP_TIME (tem2
);
4014 *ttime
= U64_TO_LISP_TIME (tem3
);
4016 FILETIME_TO_U64 (tem
, ft_creation
);
4017 /* Process no 4 (System) returns zero creation time. */
4019 tem
= (tem
- utc_base
) / 10L;
4020 *ctime
= U64_TO_LISP_TIME (tem
);
4024 FILETIME_TO_U64 (tem3
, ft_current
);
4025 tem
= (tem3
- utc_base
) / 10L - tem
;
4027 *etime
= U64_TO_LISP_TIME (tem
);
4031 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4042 system_process_attributes (pid
)
4045 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4046 Lisp_Object attrs
= Qnil
;
4047 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4048 HANDLE h_snapshot
, h_proc
;
4051 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4052 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4053 DWORD glength
= sizeof (gname
);
4054 HANDLE token
= NULL
;
4055 SID_NAME_USE user_type
;
4056 unsigned char *buf
= NULL
;
4058 TOKEN_USER user_token
;
4059 TOKEN_PRIMARY_GROUP group_token
;
4063 PROCESS_MEMORY_COUNTERS mem
;
4064 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4065 DWORD minrss
, maxrss
;
4067 MEMORY_STATUS_EX memstex
;
4068 double totphys
= 0.0;
4069 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4071 BOOL result
= FALSE
;
4073 CHECK_NUMBER_OR_FLOAT (pid
);
4074 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4076 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4078 GCPRO3 (attrs
, decoded_cmd
, tem
);
4080 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4085 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4086 for (res
= process32_first (h_snapshot
, &pe
); res
;
4087 res
= process32_next (h_snapshot
, &pe
))
4089 if (proc_id
== pe
.th32ProcessID
)
4092 decoded_cmd
= build_string ("Idle");
4095 /* Decode the command name from locale-specific
4097 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4098 strlen (pe
.szExeFile
));
4100 code_convert_string_norecord (cmd_str
,
4101 Vlocale_coding_system
, 0);
4103 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4104 attrs
= Fcons (Fcons (Qppid
,
4105 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4107 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4109 attrs
= Fcons (Fcons (Qthcount
,
4110 make_fixnum_or_float (pe
.cntThreads
)),
4117 CloseHandle (h_snapshot
);
4126 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4128 /* If we were denied a handle to the process, try again after
4129 enabling the SeDebugPrivilege in our process. */
4132 TOKEN_PRIVILEGES priv_current
;
4134 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4136 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4138 restore_privilege (&priv_current
);
4144 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4147 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4148 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4150 buf
= xmalloc (blen
);
4151 result
= get_token_information (token
, TokenUser
,
4152 (LPVOID
)buf
, blen
, &needed
);
4155 memcpy (&user_token
, buf
, sizeof (user_token
));
4156 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4158 euid
= get_rid (user_token
.User
.Sid
);
4159 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4164 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4167 strcpy (uname
, "unknown");
4171 ulength
= strlen (uname
);
4177 /* Determine a reasonable euid and gid values. */
4178 if (xstrcasecmp ("administrator", uname
) == 0)
4180 euid
= 500; /* well-known Administrator uid */
4181 egid
= 513; /* well-known None gid */
4185 /* Get group id and name. */
4186 result
= get_token_information (token
, TokenPrimaryGroup
,
4187 (LPVOID
)buf
, blen
, &needed
);
4188 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4190 buf
= xrealloc (buf
, blen
= needed
);
4191 result
= get_token_information (token
, TokenPrimaryGroup
,
4192 (LPVOID
)buf
, blen
, &needed
);
4196 memcpy (&group_token
, buf
, sizeof (group_token
));
4197 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4199 egid
= get_rid (group_token
.PrimaryGroup
);
4200 dlength
= sizeof (domain
);
4202 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4203 gname
, &glength
, NULL
, &dlength
,
4206 w32_add_to_cache (group_token
.PrimaryGroup
,
4210 strcpy (gname
, "None");
4214 glength
= strlen (gname
);
4222 if (!is_windows_9x ())
4224 /* We couldn't open the process token, presumably because of
4225 insufficient access rights. Assume this process is run
4227 strcpy (uname
, "SYSTEM");
4228 strcpy (gname
, "None");
4229 euid
= 18; /* SYSTEM */
4230 egid
= 513; /* None */
4231 glength
= strlen (gname
);
4232 ulength
= strlen (uname
);
4234 /* If we are running under Windows 9X, where security calls are
4235 not supported, we assume all processes are run by the current
4237 else if (GetUserName (uname
, &ulength
))
4239 if (xstrcasecmp ("administrator", uname
) == 0)
4244 strcpy (gname
, "None");
4245 glength
= strlen (gname
);
4246 ulength
= strlen (uname
);
4252 strcpy (uname
, "administrator");
4253 ulength
= strlen (uname
);
4254 strcpy (gname
, "None");
4255 glength
= strlen (gname
);
4258 CloseHandle (token
);
4261 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4262 tem
= make_unibyte_string (uname
, ulength
);
4263 attrs
= Fcons (Fcons (Quser
,
4264 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4266 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4267 tem
= make_unibyte_string (gname
, glength
);
4268 attrs
= Fcons (Fcons (Qgroup
,
4269 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4272 if (global_memory_status_ex (&memstex
))
4273 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4274 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4276 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4277 double, so we need to do this for it... */
4279 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4280 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4281 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4283 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4285 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4286 else if (global_memory_status (&memst
))
4287 totphys
= memst
.dwTotalPhys
/ 1024.0;
4290 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4293 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4295 attrs
= Fcons (Fcons (Qmajflt
,
4296 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4298 attrs
= Fcons (Fcons (Qvsize
,
4299 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4301 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4303 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4306 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4308 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4310 attrs
= Fcons (Fcons (Qmajflt
,
4311 make_fixnum_or_float (mem
.PageFaultCount
)),
4313 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4315 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4318 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4320 DWORD rss
= maxrss
/ 1024;
4322 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4324 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4327 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4329 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4330 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4331 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4332 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4333 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4334 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4337 /* FIXME: Retrieve command line by walking the PEB of the process. */
4340 CloseHandle (h_proc
);
4348 /* Wrappers for winsock functions to map between our file descriptors
4349 and winsock's handles; also set h_errno for convenience.
4351 To allow Emacs to run on systems which don't have winsock support
4352 installed, we dynamically link to winsock on startup if present, and
4353 otherwise provide the minimum necessary functionality
4354 (eg. gethostname). */
4356 /* function pointers for relevant socket functions */
4357 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4358 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4359 int (PASCAL
*pfn_WSAGetLastError
) (void);
4360 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4361 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4362 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4363 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4364 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4365 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4366 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4367 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4368 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4369 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4370 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4371 int (PASCAL
*pfn_WSACleanup
) (void);
4373 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4374 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4375 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4376 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4377 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4378 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4379 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4380 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4381 const char * optval
, int optlen
);
4382 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4383 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4385 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4386 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4387 struct sockaddr
* from
, int * fromlen
);
4388 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4389 const struct sockaddr
* to
, int tolen
);
4391 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4392 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4393 #ifndef HANDLE_FLAG_INHERIT
4394 #define HANDLE_FLAG_INHERIT 1
4398 static int winsock_inuse
;
4403 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4405 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4406 after WSAStartup returns successfully, but it seems reasonable
4407 to allow unloading winsock anyway in that case. */
4408 if (pfn_WSACleanup () == 0 ||
4409 pfn_WSAGetLastError () == WSAENETDOWN
)
4411 if (FreeLibrary (winsock_lib
))
4420 init_winsock (int load_now
)
4422 WSADATA winsockData
;
4424 if (winsock_lib
!= NULL
)
4427 pfn_SetHandleInformation
= NULL
;
4428 pfn_SetHandleInformation
4429 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4430 "SetHandleInformation");
4432 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4434 if (winsock_lib
!= NULL
)
4436 /* dynamically link to socket functions */
4438 #define LOAD_PROC(fn) \
4439 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4442 LOAD_PROC (WSAStartup
);
4443 LOAD_PROC (WSASetLastError
);
4444 LOAD_PROC (WSAGetLastError
);
4445 LOAD_PROC (WSAEventSelect
);
4446 LOAD_PROC (WSACreateEvent
);
4447 LOAD_PROC (WSACloseEvent
);
4450 LOAD_PROC (connect
);
4451 LOAD_PROC (ioctlsocket
);
4454 LOAD_PROC (closesocket
);
4455 LOAD_PROC (shutdown
);
4458 LOAD_PROC (inet_addr
);
4459 LOAD_PROC (gethostname
);
4460 LOAD_PROC (gethostbyname
);
4461 LOAD_PROC (getservbyname
);
4462 LOAD_PROC (getpeername
);
4463 LOAD_PROC (WSACleanup
);
4464 LOAD_PROC (setsockopt
);
4466 LOAD_PROC (getsockname
);
4468 LOAD_PROC (recvfrom
);
4472 /* specify version 1.1 of winsock */
4473 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4475 if (winsockData
.wVersion
!= 0x101)
4480 /* Report that winsock exists and is usable, but leave
4481 socket functions disabled. I am assuming that calling
4482 WSAStartup does not require any network interaction,
4483 and in particular does not cause or require a dial-up
4484 connection to be established. */
4487 FreeLibrary (winsock_lib
);
4495 FreeLibrary (winsock_lib
);
4505 /* function to set h_errno for compatibility; map winsock error codes to
4506 normal system codes where they overlap (non-overlapping definitions
4507 are already in <sys/socket.h> */
4511 if (winsock_lib
== NULL
)
4514 h_errno
= pfn_WSAGetLastError ();
4518 case WSAEACCES
: h_errno
= EACCES
; break;
4519 case WSAEBADF
: h_errno
= EBADF
; break;
4520 case WSAEFAULT
: h_errno
= EFAULT
; break;
4521 case WSAEINTR
: h_errno
= EINTR
; break;
4522 case WSAEINVAL
: h_errno
= EINVAL
; break;
4523 case WSAEMFILE
: h_errno
= EMFILE
; break;
4524 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4525 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4533 if (h_errno
== 0 && winsock_lib
!= NULL
)
4534 pfn_WSASetLastError (0);
4537 /* Extend strerror to handle the winsock-specific error codes. */
4541 } _wsa_errlist
[] = {
4542 WSAEINTR
, "Interrupted function call",
4543 WSAEBADF
, "Bad file descriptor",
4544 WSAEACCES
, "Permission denied",
4545 WSAEFAULT
, "Bad address",
4546 WSAEINVAL
, "Invalid argument",
4547 WSAEMFILE
, "Too many open files",
4549 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
4550 WSAEINPROGRESS
, "Operation now in progress",
4551 WSAEALREADY
, "Operation already in progress",
4552 WSAENOTSOCK
, "Socket operation on non-socket",
4553 WSAEDESTADDRREQ
, "Destination address required",
4554 WSAEMSGSIZE
, "Message too long",
4555 WSAEPROTOTYPE
, "Protocol wrong type for socket",
4556 WSAENOPROTOOPT
, "Bad protocol option",
4557 WSAEPROTONOSUPPORT
, "Protocol not supported",
4558 WSAESOCKTNOSUPPORT
, "Socket type not supported",
4559 WSAEOPNOTSUPP
, "Operation not supported",
4560 WSAEPFNOSUPPORT
, "Protocol family not supported",
4561 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
4562 WSAEADDRINUSE
, "Address already in use",
4563 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
4564 WSAENETDOWN
, "Network is down",
4565 WSAENETUNREACH
, "Network is unreachable",
4566 WSAENETRESET
, "Network dropped connection on reset",
4567 WSAECONNABORTED
, "Software caused connection abort",
4568 WSAECONNRESET
, "Connection reset by peer",
4569 WSAENOBUFS
, "No buffer space available",
4570 WSAEISCONN
, "Socket is already connected",
4571 WSAENOTCONN
, "Socket is not connected",
4572 WSAESHUTDOWN
, "Cannot send after socket shutdown",
4573 WSAETOOMANYREFS
, "Too many references", /* not sure */
4574 WSAETIMEDOUT
, "Connection timed out",
4575 WSAECONNREFUSED
, "Connection refused",
4576 WSAELOOP
, "Network loop", /* not sure */
4577 WSAENAMETOOLONG
, "Name is too long",
4578 WSAEHOSTDOWN
, "Host is down",
4579 WSAEHOSTUNREACH
, "No route to host",
4580 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
4581 WSAEPROCLIM
, "Too many processes",
4582 WSAEUSERS
, "Too many users", /* not sure */
4583 WSAEDQUOT
, "Double quote in host name", /* really not sure */
4584 WSAESTALE
, "Data is stale", /* not sure */
4585 WSAEREMOTE
, "Remote error", /* not sure */
4587 WSASYSNOTREADY
, "Network subsystem is unavailable",
4588 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
4589 WSANOTINITIALISED
, "Winsock not initialized successfully",
4590 WSAEDISCON
, "Graceful shutdown in progress",
4592 WSAENOMORE
, "No more operations allowed", /* not sure */
4593 WSAECANCELLED
, "Operation cancelled", /* not sure */
4594 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
4595 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
4596 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
4597 WSASYSCALLFAILURE
, "System call failure",
4598 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
4599 WSATYPE_NOT_FOUND
, "Class type not found",
4600 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
4601 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
4602 WSAEREFUSED
, "Operation refused", /* not sure */
4605 WSAHOST_NOT_FOUND
, "Host not found",
4606 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
4607 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
4608 WSANO_DATA
, "Valid name, no data record of requested type",
4614 sys_strerror (int error_no
)
4617 static char unknown_msg
[40];
4619 if (error_no
>= 0 && error_no
< sys_nerr
)
4620 return sys_errlist
[error_no
];
4622 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4623 if (_wsa_errlist
[i
].errnum
== error_no
)
4624 return _wsa_errlist
[i
].msg
;
4626 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4630 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4631 but I believe the method of keeping the socket handle separate (and
4632 insuring it is not inheritable) is the correct one. */
4634 //#define SOCK_REPLACE_HANDLE
4636 #ifdef SOCK_REPLACE_HANDLE
4637 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
4639 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4642 int socket_to_fd (SOCKET s
);
4645 sys_socket (int af
, int type
, int protocol
)
4649 if (winsock_lib
== NULL
)
4652 return INVALID_SOCKET
;
4657 /* call the real socket function */
4658 s
= pfn_socket (af
, type
, protocol
);
4660 if (s
!= INVALID_SOCKET
)
4661 return socket_to_fd (s
);
4667 /* Convert a SOCKET to a file descriptor. */
4669 socket_to_fd (SOCKET s
)
4674 /* Although under NT 3.5 _open_osfhandle will accept a socket
4675 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4676 that does not work under NT 3.1. However, we can get the same
4677 effect by using a backdoor function to replace an existing
4678 descriptor handle with the one we want. */
4680 /* allocate a file descriptor (with appropriate flags) */
4681 fd
= _open ("NUL:", _O_RDWR
);
4684 #ifdef SOCK_REPLACE_HANDLE
4685 /* now replace handle to NUL with our socket handle */
4686 CloseHandle ((HANDLE
) _get_osfhandle (fd
));
4688 _set_osfhnd (fd
, s
);
4689 /* setmode (fd, _O_BINARY); */
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
;
4738 /* set our own internal flags */
4739 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4745 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4747 /* attach child_process to fd_info */
4748 if (fd_info
[ fd
].cp
!= NULL
)
4750 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4754 fd_info
[ fd
].cp
= cp
;
4757 winsock_inuse
++; /* count open sockets */
4764 pfn_closesocket (s
);
4771 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4773 if (winsock_lib
== NULL
)
4776 return SOCKET_ERROR
;
4780 if (fd_info
[s
].flags
& FILE_SOCKET
)
4782 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4783 if (rc
== SOCKET_ERROR
)
4788 return SOCKET_ERROR
;
4793 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4795 if (winsock_lib
== NULL
)
4798 return SOCKET_ERROR
;
4802 if (fd_info
[s
].flags
& FILE_SOCKET
)
4804 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4805 if (rc
== SOCKET_ERROR
)
4810 return SOCKET_ERROR
;
4814 sys_htons (u_short hostshort
)
4816 return (winsock_lib
!= NULL
) ?
4817 pfn_htons (hostshort
) : hostshort
;
4821 sys_ntohs (u_short netshort
)
4823 return (winsock_lib
!= NULL
) ?
4824 pfn_ntohs (netshort
) : netshort
;
4828 sys_inet_addr (const char * cp
)
4830 return (winsock_lib
!= NULL
) ?
4831 pfn_inet_addr (cp
) : INADDR_NONE
;
4835 sys_gethostname (char * name
, int namelen
)
4837 if (winsock_lib
!= NULL
)
4838 return pfn_gethostname (name
, namelen
);
4840 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4841 return !GetComputerName (name
, (DWORD
*)&namelen
);
4844 return SOCKET_ERROR
;
4848 sys_gethostbyname (const char * name
)
4850 struct hostent
* host
;
4852 if (winsock_lib
== NULL
)
4859 host
= pfn_gethostbyname (name
);
4866 sys_getservbyname (const char * name
, const char * proto
)
4868 struct servent
* serv
;
4870 if (winsock_lib
== NULL
)
4877 serv
= pfn_getservbyname (name
, proto
);
4884 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4886 if (winsock_lib
== NULL
)
4889 return SOCKET_ERROR
;
4893 if (fd_info
[s
].flags
& FILE_SOCKET
)
4895 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4896 if (rc
== SOCKET_ERROR
)
4901 return SOCKET_ERROR
;
4906 sys_shutdown (int s
, int how
)
4908 if (winsock_lib
== NULL
)
4911 return SOCKET_ERROR
;
4915 if (fd_info
[s
].flags
& FILE_SOCKET
)
4917 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4918 if (rc
== SOCKET_ERROR
)
4923 return SOCKET_ERROR
;
4927 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4929 if (winsock_lib
== NULL
)
4932 return SOCKET_ERROR
;
4936 if (fd_info
[s
].flags
& FILE_SOCKET
)
4938 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4939 (const char *)optval
, optlen
);
4940 if (rc
== SOCKET_ERROR
)
4945 return SOCKET_ERROR
;
4949 sys_listen (int s
, int backlog
)
4951 if (winsock_lib
== NULL
)
4954 return SOCKET_ERROR
;
4958 if (fd_info
[s
].flags
& FILE_SOCKET
)
4960 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4961 if (rc
== SOCKET_ERROR
)
4964 fd_info
[s
].flags
|= FILE_LISTEN
;
4968 return SOCKET_ERROR
;
4972 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4974 if (winsock_lib
== NULL
)
4977 return SOCKET_ERROR
;
4981 if (fd_info
[s
].flags
& FILE_SOCKET
)
4983 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4984 if (rc
== SOCKET_ERROR
)
4989 return SOCKET_ERROR
;
4993 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
4995 if (winsock_lib
== NULL
)
5002 if (fd_info
[s
].flags
& FILE_LISTEN
)
5004 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5006 if (t
== INVALID_SOCKET
)
5009 fd
= socket_to_fd (t
);
5011 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5012 ResetEvent (fd_info
[s
].cp
->char_avail
);
5020 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5021 struct sockaddr
* from
, int * fromlen
)
5023 if (winsock_lib
== NULL
)
5026 return SOCKET_ERROR
;
5030 if (fd_info
[s
].flags
& FILE_SOCKET
)
5032 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5033 if (rc
== SOCKET_ERROR
)
5038 return SOCKET_ERROR
;
5042 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5043 const struct sockaddr
* to
, int tolen
)
5045 if (winsock_lib
== NULL
)
5048 return SOCKET_ERROR
;
5052 if (fd_info
[s
].flags
& FILE_SOCKET
)
5054 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5055 if (rc
== SOCKET_ERROR
)
5060 return SOCKET_ERROR
;
5063 /* Windows does not have an fcntl function. Provide an implementation
5064 solely for making sockets non-blocking. */
5066 fcntl (int s
, int cmd
, int options
)
5068 if (winsock_lib
== NULL
)
5075 if (fd_info
[s
].flags
& FILE_SOCKET
)
5077 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5079 unsigned long nblock
= 1;
5080 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5081 if (rc
== SOCKET_ERROR
)
5083 /* Keep track of the fact that we set this to non-blocking. */
5084 fd_info
[s
].flags
|= FILE_NDELAY
;
5090 return SOCKET_ERROR
;
5094 return SOCKET_ERROR
;
5097 #endif /* HAVE_SOCKETS */
5100 /* Shadow main io functions: we need to handle pipes and sockets more
5101 intelligently, and implement non-blocking mode as well. */
5114 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5116 child_process
* cp
= fd_info
[fd
].cp
;
5118 fd_info
[fd
].cp
= NULL
;
5120 if (CHILD_ACTIVE (cp
))
5122 /* if last descriptor to active child_process then cleanup */
5124 for (i
= 0; i
< MAXDESC
; i
++)
5128 if (fd_info
[i
].cp
== cp
)
5134 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5136 #ifndef SOCK_REPLACE_HANDLE
5137 if (winsock_lib
== NULL
) abort ();
5139 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5140 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5142 winsock_inuse
--; /* count open sockets */
5150 /* Note that sockets do not need special treatment here (at least on
5151 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5152 closesocket is equivalent to CloseHandle, which is to be expected
5153 because socket handles are fully fledged kernel handles. */
5156 if (rc
== 0 && fd
< MAXDESC
)
5157 fd_info
[fd
].flags
= 0;
5168 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5170 /* duplicate our internal info as well */
5171 fd_info
[new_fd
] = fd_info
[fd
];
5178 sys_dup2 (int src
, int dst
)
5182 if (dst
< 0 || dst
>= MAXDESC
)
5188 /* make sure we close the destination first if it's a pipe or socket */
5189 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5192 rc
= _dup2 (src
, dst
);
5195 /* duplicate our internal info as well */
5196 fd_info
[dst
] = fd_info
[src
];
5201 /* Unix pipe() has only one arg */
5203 sys_pipe (int * phandles
)
5208 /* make pipe handles non-inheritable; when we spawn a child, we
5209 replace the relevant handle with an inheritable one. Also put
5210 pipes into binary mode; we will do text mode translation ourselves
5212 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5216 /* Protect against overflow, since Windows can open more handles than
5217 our fd_info array has room for. */
5218 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5220 _close (phandles
[0]);
5221 _close (phandles
[1]);
5226 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5227 fd_info
[phandles
[0]].flags
= flags
;
5229 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5230 fd_info
[phandles
[1]].flags
= flags
;
5238 extern int w32_pipe_read_delay
;
5240 /* Function to do blocking read of one byte, needed to implement
5241 select. It is only allowed on sockets and pipes. */
5243 _sys_read_ahead (int fd
)
5248 if (fd
< 0 || fd
>= MAXDESC
)
5249 return STATUS_READ_ERROR
;
5251 cp
= fd_info
[fd
].cp
;
5253 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5254 return STATUS_READ_ERROR
;
5256 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5257 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5259 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5263 cp
->status
= STATUS_READ_IN_PROGRESS
;
5265 if (fd_info
[fd
].flags
& FILE_PIPE
)
5267 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5269 /* Give subprocess time to buffer some more output for us before
5270 reporting that input is available; we need this because Windows 95
5271 connects DOS programs to pipes by making the pipe appear to be
5272 the normal console stdout - as a result most DOS programs will
5273 write to stdout without buffering, ie. one character at a
5274 time. Even some W32 programs do this - "dir" in a command
5275 shell on NT is very slow if we don't do this. */
5278 int wait
= w32_pipe_read_delay
;
5284 /* Yield remainder of our time slice, effectively giving a
5285 temporary priority boost to the child process. */
5289 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5291 HANDLE hnd
= fd_info
[fd
].hnd
;
5292 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5295 /* Configure timeouts for blocking read. */
5296 if (!GetCommTimeouts (hnd
, &ct
))
5297 return STATUS_READ_ERROR
;
5298 ct
.ReadIntervalTimeout
= 0;
5299 ct
.ReadTotalTimeoutMultiplier
= 0;
5300 ct
.ReadTotalTimeoutConstant
= 0;
5301 if (!SetCommTimeouts (hnd
, &ct
))
5302 return STATUS_READ_ERROR
;
5304 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5306 if (GetLastError () != ERROR_IO_PENDING
)
5307 return STATUS_READ_ERROR
;
5308 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5309 return STATUS_READ_ERROR
;
5313 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5315 unsigned long nblock
= 0;
5316 /* We always want this to block, so temporarily disable NDELAY. */
5317 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5318 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5320 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5322 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5325 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5330 if (rc
== sizeof (char))
5331 cp
->status
= STATUS_READ_SUCCEEDED
;
5333 cp
->status
= STATUS_READ_FAILED
;
5339 _sys_wait_accept (int fd
)
5345 if (fd
< 0 || fd
>= MAXDESC
)
5346 return STATUS_READ_ERROR
;
5348 cp
= fd_info
[fd
].cp
;
5350 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5351 return STATUS_READ_ERROR
;
5353 cp
->status
= STATUS_READ_FAILED
;
5355 hEv
= pfn_WSACreateEvent ();
5356 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5357 if (rc
!= SOCKET_ERROR
)
5359 rc
= WaitForSingleObject (hEv
, INFINITE
);
5360 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5361 if (rc
== WAIT_OBJECT_0
)
5362 cp
->status
= STATUS_READ_SUCCEEDED
;
5364 pfn_WSACloseEvent (hEv
);
5370 sys_read (int fd
, char * buffer
, unsigned int count
)
5375 char * orig_buffer
= buffer
;
5383 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5385 child_process
*cp
= fd_info
[fd
].cp
;
5387 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5395 /* re-read CR carried over from last read */
5396 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5398 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5402 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5405 /* presence of a child_process structure means we are operating in
5406 non-blocking mode - otherwise we just call _read directly.
5407 Note that the child_process structure might be missing because
5408 reap_subprocess has been called; in this case the pipe is
5409 already broken, so calling _read on it is okay. */
5412 int current_status
= cp
->status
;
5414 switch (current_status
)
5416 case STATUS_READ_FAILED
:
5417 case STATUS_READ_ERROR
:
5418 /* report normal EOF if nothing in buffer */
5420 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5423 case STATUS_READ_READY
:
5424 case STATUS_READ_IN_PROGRESS
:
5425 DebPrint (("sys_read called when read is in progress\n"));
5426 errno
= EWOULDBLOCK
;
5429 case STATUS_READ_SUCCEEDED
:
5430 /* consume read-ahead char */
5431 *buffer
++ = cp
->chr
;
5434 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5435 ResetEvent (cp
->char_avail
);
5437 case STATUS_READ_ACKNOWLEDGED
:
5441 DebPrint (("sys_read: bad status %d\n", current_status
));
5446 if (fd_info
[fd
].flags
& FILE_PIPE
)
5448 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5449 to_read
= min (waiting
, (DWORD
) count
);
5452 nchars
+= _read (fd
, buffer
, to_read
);
5454 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5456 HANDLE hnd
= fd_info
[fd
].hnd
;
5457 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5464 /* Configure timeouts for non-blocking read. */
5465 if (!GetCommTimeouts (hnd
, &ct
))
5470 ct
.ReadIntervalTimeout
= MAXDWORD
;
5471 ct
.ReadTotalTimeoutMultiplier
= 0;
5472 ct
.ReadTotalTimeoutConstant
= 0;
5473 if (!SetCommTimeouts (hnd
, &ct
))
5479 if (!ResetEvent (ovl
->hEvent
))
5484 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5486 if (GetLastError () != ERROR_IO_PENDING
)
5491 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5501 else /* FILE_SOCKET */
5503 if (winsock_lib
== NULL
) abort ();
5505 /* do the equivalent of a non-blocking read */
5506 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5507 if (waiting
== 0 && nchars
== 0)
5509 h_errno
= errno
= EWOULDBLOCK
;
5515 /* always use binary mode for sockets */
5516 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5517 if (res
== SOCKET_ERROR
)
5519 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5520 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5531 int nread
= _read (fd
, buffer
, count
);
5534 else if (nchars
== 0)
5539 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5540 /* Perform text mode translation if required. */
5541 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5543 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5544 /* If buffer contains only CR, return that. To be absolutely
5545 sure we should attempt to read the next char, but in
5546 practice a CR to be followed by LF would not appear by
5547 itself in the buffer. */
5548 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5550 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5556 nchars
= _read (fd
, buffer
, count
);
5561 /* From w32xfns.c */
5562 extern HANDLE interrupt_handle
;
5564 /* For now, don't bother with a non-blocking mode */
5566 sys_write (int fd
, const void * buffer
, unsigned int count
)
5576 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5578 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5584 /* Perform text mode translation if required. */
5585 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5587 char * tmpbuf
= alloca (count
* 2);
5588 unsigned char * src
= (void *)buffer
;
5589 unsigned char * dst
= tmpbuf
;
5594 unsigned char *next
;
5595 /* copy next line or remaining bytes */
5596 next
= _memccpy (dst
, src
, '\n', nbytes
);
5599 /* copied one line ending with '\n' */
5600 int copied
= next
- dst
;
5603 /* insert '\r' before '\n' */
5610 /* copied remaining partial line -> now finished */
5617 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5619 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5620 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5621 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5624 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5626 if (GetLastError () != ERROR_IO_PENDING
)
5631 if (detect_input_pending ())
5632 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5635 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5636 if (active
== WAIT_OBJECT_0
)
5637 { /* User pressed C-g, cancel write, then leave. Don't bother
5638 cleaning up as we may only get stuck in buggy drivers. */
5639 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5644 if (active
== WAIT_OBJECT_0
+ 1
5645 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5654 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5656 unsigned long nblock
= 0;
5657 if (winsock_lib
== NULL
) abort ();
5659 /* TODO: implement select() properly so non-blocking I/O works. */
5660 /* For now, make sure the write blocks. */
5661 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5662 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5664 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5666 /* Set the socket back to non-blocking if it was before,
5667 for other operations that support it. */
5668 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5671 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5674 if (nchars
== SOCKET_ERROR
)
5676 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5677 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5683 nchars
= _write (fd
, buffer
, count
);
5688 /* The Windows CRT functions are "optimized for speed", so they don't
5689 check for timezone and DST changes if they were last called less
5690 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
5691 all Emacs features that repeatedly call time functions (e.g.,
5692 display-time) are in real danger of missing timezone and DST
5693 changes. Calling tzset before each localtime call fixes that. */
5695 sys_localtime (const time_t *t
)
5698 return localtime (t
);
5702 check_windows_init_file ()
5704 extern int noninteractive
, inhibit_window_system
;
5706 /* A common indication that Emacs is not installed properly is when
5707 it cannot find the Windows installation file. If this file does
5708 not exist in the expected place, tell the user. */
5710 if (!noninteractive
&& !inhibit_window_system
)
5712 extern Lisp_Object Vwindow_system
, Vload_path
, Qfile_exists_p
;
5713 Lisp_Object objs
[2];
5714 Lisp_Object full_load_path
;
5715 Lisp_Object init_file
;
5718 objs
[0] = Vload_path
;
5719 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5720 full_load_path
= Fappend (2, objs
);
5721 init_file
= build_string ("term/w32-win");
5722 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5725 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5726 char *init_file_name
= SDATA (init_file
);
5727 char *load_path
= SDATA (load_path_print
);
5728 char *buffer
= alloca (1024
5729 + strlen (init_file_name
)
5730 + strlen (load_path
));
5733 "The Emacs Windows initialization file \"%s.el\" "
5734 "could not be found in your Emacs installation. "
5735 "Emacs checked the following directories for this file:\n"
5737 "When Emacs cannot find this file, it usually means that it "
5738 "was not installed properly, or its distribution file was "
5739 "not unpacked properly.\nSee the README.W32 file in the "
5740 "top-level Emacs directory for more information.",
5741 init_file_name
, load_path
);
5744 "Emacs Abort Dialog",
5745 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5746 /* Use the low-level Emacs abort. */
5761 /* shutdown the socket interface if necessary */
5772 /* Initialise the socket interface now if available and requested by
5773 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5774 delayed until open-network-stream is called (w32-has-winsock can
5775 also be used to dynamically load or reload winsock).
5777 Conveniently, init_environment is called before us, so
5778 PRELOAD_WINSOCK can be set in the registry. */
5780 /* Always initialize this correctly. */
5783 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5784 init_winsock (TRUE
);
5787 /* Initial preparation for subprocess support: replace our standard
5788 handles with non-inheritable versions. */
5791 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5792 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5793 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5795 parent
= GetCurrentProcess ();
5797 /* ignore errors when duplicating and closing; typically the
5798 handles will be invalid when running as a gui program. */
5799 DuplicateHandle (parent
,
5800 GetStdHandle (STD_INPUT_HANDLE
),
5805 DUPLICATE_SAME_ACCESS
);
5807 DuplicateHandle (parent
,
5808 GetStdHandle (STD_OUTPUT_HANDLE
),
5813 DUPLICATE_SAME_ACCESS
);
5815 DuplicateHandle (parent
,
5816 GetStdHandle (STD_ERROR_HANDLE
),
5821 DUPLICATE_SAME_ACCESS
);
5827 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5828 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5830 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5833 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5834 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5836 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5839 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5840 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5842 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5846 /* unfortunately, atexit depends on implementation of malloc */
5847 /* atexit (term_ntproc); */
5848 signal (SIGABRT
, term_ntproc
);
5850 /* determine which drives are fixed, for GetCachedVolumeInformation */
5852 /* GetDriveType must have trailing backslash. */
5853 char drive
[] = "A:\\";
5855 /* Loop over all possible drive letters */
5856 while (*drive
<= 'Z')
5858 /* Record if this drive letter refers to a fixed drive. */
5859 fixed_drives
[DRIVE_INDEX (*drive
)] =
5860 (GetDriveType (drive
) == DRIVE_FIXED
);
5865 /* Reset the volume info cache. */
5866 volume_cache
= NULL
;
5869 /* Check to see if Emacs has been installed correctly. */
5870 check_windows_init_file ();
5874 shutdown_handler ensures that buffers' autosave files are
5875 up to date when the user logs off, or the system shuts down.
5878 shutdown_handler (DWORD type
)
5880 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5881 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5882 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5883 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5885 /* Shut down cleanly, making sure autosave files are up to date. */
5886 shut_down_emacs (0, 0, Qnil
);
5889 /* Allow other handlers to handle this signal. */
5894 globals_of_w32 is used to initialize those global variables that
5895 must always be initialized on startup even when the global variable
5896 initialized is non zero (see the function main in emacs.c).
5901 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5903 get_process_times_fn
= (GetProcessTimes_Proc
)
5904 GetProcAddress (kernel32
, "GetProcessTimes");
5906 g_b_init_is_windows_9x
= 0;
5907 g_b_init_open_process_token
= 0;
5908 g_b_init_get_token_information
= 0;
5909 g_b_init_lookup_account_sid
= 0;
5910 g_b_init_get_sid_identifier_authority
= 0;
5911 g_b_init_get_sid_sub_authority
= 0;
5912 g_b_init_get_sid_sub_authority_count
= 0;
5913 g_b_init_get_file_security
= 0;
5914 g_b_init_get_security_descriptor_owner
= 0;
5915 g_b_init_get_security_descriptor_group
= 0;
5916 g_b_init_is_valid_sid
= 0;
5917 g_b_init_create_toolhelp32_snapshot
= 0;
5918 g_b_init_process32_first
= 0;
5919 g_b_init_process32_next
= 0;
5920 g_b_init_open_thread_token
= 0;
5921 g_b_init_impersonate_self
= 0;
5922 g_b_init_revert_to_self
= 0;
5923 g_b_init_get_process_memory_info
= 0;
5924 g_b_init_get_process_working_set_size
= 0;
5925 g_b_init_global_memory_status
= 0;
5926 g_b_init_global_memory_status_ex
= 0;
5927 g_b_init_equal_sid
= 0;
5928 g_b_init_copy_sid
= 0;
5929 g_b_init_get_length_sid
= 0;
5930 g_b_init_get_native_system_info
= 0;
5931 g_b_init_get_system_times
= 0;
5932 num_of_processors
= 0;
5933 /* The following sets a handler for shutdown notifications for
5934 console apps. This actually applies to Emacs in both console and
5935 GUI modes, since we had to fool windows into thinking emacs is a
5936 console application to get console mode to work. */
5937 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
5939 /* "None" is the default group name on standalone workstations. */
5940 strcpy (dflt_group_name
, "None");
5943 /* For make-serial-process */
5945 serial_open (char *port
)
5951 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5952 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5953 if (hnd
== INVALID_HANDLE_VALUE
)
5954 error ("Could not open %s", port
);
5955 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5957 error ("Could not open %s", port
);
5961 error ("Could not create child process");
5963 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5964 fd_info
[ fd
].hnd
= hnd
;
5965 fd_info
[ fd
].flags
|=
5966 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5967 if (fd_info
[ fd
].cp
!= NULL
)
5969 error ("fd_info[fd = %d] is already in use", fd
);
5971 fd_info
[ fd
].cp
= cp
;
5972 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5973 if (cp
->ovl_read
.hEvent
== NULL
)
5974 error ("Could not create read event");
5975 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5976 if (cp
->ovl_write
.hEvent
== NULL
)
5977 error ("Could not create write event");
5982 /* For serial-process-configure */
5984 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
5986 Lisp_Object childp2
= Qnil
;
5987 Lisp_Object tem
= Qnil
;
5991 char summary
[4] = "???"; /* This usually becomes "8N1". */
5993 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
5994 error ("Not a serial process");
5995 hnd
= fd_info
[ p
->outfd
].hnd
;
5997 childp2
= Fcopy_sequence (p
->childp
);
5999 /* Initialize timeouts for blocking read and blocking write. */
6000 if (!GetCommTimeouts (hnd
, &ct
))
6001 error ("GetCommTimeouts() failed");
6002 ct
.ReadIntervalTimeout
= 0;
6003 ct
.ReadTotalTimeoutMultiplier
= 0;
6004 ct
.ReadTotalTimeoutConstant
= 0;
6005 ct
.WriteTotalTimeoutMultiplier
= 0;
6006 ct
.WriteTotalTimeoutConstant
= 0;
6007 if (!SetCommTimeouts (hnd
, &ct
))
6008 error ("SetCommTimeouts() failed");
6009 /* Read port attributes and prepare default configuration. */
6010 memset (&dcb
, 0, sizeof (dcb
));
6011 dcb
.DCBlength
= sizeof (DCB
);
6012 if (!GetCommState (hnd
, &dcb
))
6013 error ("GetCommState() failed");
6016 dcb
.fAbortOnError
= FALSE
;
6017 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6022 /* Configure speed. */
6023 if (!NILP (Fplist_member (contact
, QCspeed
)))
6024 tem
= Fplist_get (contact
, QCspeed
);
6026 tem
= Fplist_get (p
->childp
, QCspeed
);
6028 dcb
.BaudRate
= XINT (tem
);
6029 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6031 /* Configure bytesize. */
6032 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6033 tem
= Fplist_get (contact
, QCbytesize
);
6035 tem
= Fplist_get (p
->childp
, QCbytesize
);
6037 tem
= make_number (8);
6039 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6040 error (":bytesize must be nil (8), 7, or 8");
6041 dcb
.ByteSize
= XINT (tem
);
6042 summary
[0] = XINT (tem
) + '0';
6043 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6045 /* Configure parity. */
6046 if (!NILP (Fplist_member (contact
, QCparity
)))
6047 tem
= Fplist_get (contact
, QCparity
);
6049 tem
= Fplist_get (p
->childp
, QCparity
);
6050 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6051 error (":parity must be nil (no parity), `even', or `odd'");
6052 dcb
.fParity
= FALSE
;
6053 dcb
.Parity
= NOPARITY
;
6054 dcb
.fErrorChar
= FALSE
;
6059 else if (EQ (tem
, Qeven
))
6063 dcb
.Parity
= EVENPARITY
;
6064 dcb
.fErrorChar
= TRUE
;
6066 else if (EQ (tem
, Qodd
))
6070 dcb
.Parity
= ODDPARITY
;
6071 dcb
.fErrorChar
= TRUE
;
6073 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6075 /* Configure stopbits. */
6076 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6077 tem
= Fplist_get (contact
, QCstopbits
);
6079 tem
= Fplist_get (p
->childp
, QCstopbits
);
6081 tem
= make_number (1);
6083 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6084 error (":stopbits must be nil (1 stopbit), 1, or 2");
6085 summary
[2] = XINT (tem
) + '0';
6086 if (XINT (tem
) == 1)
6087 dcb
.StopBits
= ONESTOPBIT
;
6088 else if (XINT (tem
) == 2)
6089 dcb
.StopBits
= TWOSTOPBITS
;
6090 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6092 /* Configure flowcontrol. */
6093 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6094 tem
= Fplist_get (contact
, QCflowcontrol
);
6096 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6097 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6098 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6099 dcb
.fOutxCtsFlow
= FALSE
;
6100 dcb
.fOutxDsrFlow
= FALSE
;
6101 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6102 dcb
.fDsrSensitivity
= FALSE
;
6103 dcb
.fTXContinueOnXoff
= FALSE
;
6106 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6107 dcb
.XonChar
= 17; /* Control-Q */
6108 dcb
.XoffChar
= 19; /* Control-S */
6111 /* Already configured. */
6113 else if (EQ (tem
, Qhw
))
6115 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6116 dcb
.fOutxCtsFlow
= TRUE
;
6118 else if (EQ (tem
, Qsw
))
6123 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6125 /* Activate configuration. */
6126 if (!SetCommState (hnd
, &dcb
))
6127 error ("SetCommState() failed");
6129 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6130 p
->childp
= childp2
;
6135 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
6136 (do not change this comment) */