1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3 2007, 2008 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
23 #include <stddef.h> /* for offsetof */
33 #include <sys/utime.h>
34 #include <mbstring.h> /* for _mbspbrk */
37 /* must include CRT headers *before* config.h */
72 #define _ANONYMOUS_UNION
73 #define _ANONYMOUS_STRUCT
76 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
77 use a different name to avoid compilation problems. */
78 typedef struct _MEMORY_STATUS_EX
{
81 DWORDLONG ullTotalPhys
;
82 DWORDLONG ullAvailPhys
;
83 DWORDLONG ullTotalPageFile
;
84 DWORDLONG ullAvailPageFile
;
85 DWORDLONG ullTotalVirtual
;
86 DWORDLONG ullAvailVirtual
;
87 DWORDLONG ullAvailExtendedVirtual
;
88 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
95 /* This either is not in psapi.h or guarded by higher value of
96 _WIN32_WINNT than what we use. */
97 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
100 DWORD PeakWorkingSetSize
;
101 DWORD WorkingSetSize
;
102 DWORD QuotaPeakPagedPoolUsage
;
103 DWORD QuotaPagedPoolUsage
;
104 DWORD QuotaPeakNonPagedPoolUsage
;
105 DWORD QuotaNonPagedPoolUsage
;
107 DWORD PeakPagefileUsage
;
109 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
111 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
112 #include <sys/socket.h>
136 #include "dispextern.h" /* for xstrcasecmp */
137 #include "coding.h" /* for Vlocale_coding_system */
139 /* For serial_configure and serial_open. */
142 extern Lisp_Object QCport
, QCspeed
, QCprocess
;
143 extern Lisp_Object QCbytesize
, QCstopbits
, QCparity
, Qodd
, Qeven
;
144 extern Lisp_Object QCflowcontrol
, Qhw
, Qsw
, QCsummary
;
146 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
147 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
149 void globals_of_w32 ();
150 static DWORD
get_rid (PSID
);
152 extern Lisp_Object Vw32_downcase_file_names
;
153 extern Lisp_Object Vw32_generate_fake_inodes
;
154 extern Lisp_Object Vw32_get_true_file_attributes
;
155 /* Defined in process.c for its own purpose. */
156 extern Lisp_Object Qlocal
;
158 extern int w32_num_mouse_buttons
;
161 /* Initialization states.
163 WARNING: If you add any more such variables for additional APIs,
164 you MUST add initialization for them to globals_of_w32
165 below. This is because these variables might get set
166 to non-NULL values during dumping, but the dumped Emacs
167 cannot reuse those values, because it could be run on a
168 different version of the OS, where API addresses are
170 static BOOL g_b_init_is_windows_9x
;
171 static BOOL g_b_init_open_process_token
;
172 static BOOL g_b_init_get_token_information
;
173 static BOOL g_b_init_lookup_account_sid
;
174 static BOOL g_b_init_get_sid_identifier_authority
;
175 static BOOL g_b_init_get_sid_sub_authority
;
176 static BOOL g_b_init_get_sid_sub_authority_count
;
177 static BOOL g_b_init_get_file_security
;
178 static BOOL g_b_init_get_security_descriptor_owner
;
179 static BOOL g_b_init_get_security_descriptor_group
;
180 static BOOL g_b_init_is_valid_sid
;
181 static BOOL g_b_init_create_toolhelp32_snapshot
;
182 static BOOL g_b_init_process32_first
;
183 static BOOL g_b_init_process32_next
;
184 static BOOL g_b_init_open_thread_token
;
185 static BOOL g_b_init_impersonate_self
;
186 static BOOL g_b_init_revert_to_self
;
187 static BOOL g_b_init_get_process_memory_info
;
188 static BOOL g_b_init_get_process_working_set_size
;
189 static BOOL g_b_init_global_memory_status
;
190 static BOOL g_b_init_global_memory_status_ex
;
191 static BOOL g_b_init_get_length_sid
;
192 static BOOL g_b_init_equal_sid
;
193 static BOOL g_b_init_copy_sid
;
196 BEGIN: Wrapper functions around OpenProcessToken
197 and other functions in advapi32.dll that are only
198 supported in Windows NT / 2k / XP
200 /* ** Function pointer typedefs ** */
201 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
202 HANDLE ProcessHandle
,
204 PHANDLE TokenHandle
);
205 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
207 TOKEN_INFORMATION_CLASS TokenInformationClass
,
208 LPVOID TokenInformation
,
209 DWORD TokenInformationLength
,
210 PDWORD ReturnLength
);
211 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
212 HANDLE process_handle
,
213 LPFILETIME creation_time
,
214 LPFILETIME exit_time
,
215 LPFILETIME kernel_time
,
216 LPFILETIME user_time
);
218 GetProcessTimes_Proc get_process_times_fn
= NULL
;
221 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
222 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
224 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
225 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
227 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
228 LPCTSTR lpSystemName
,
233 LPDWORD cbDomainName
,
234 PSID_NAME_USE peUse
);
235 typedef PSID_IDENTIFIER_AUTHORITY (WINAPI
* GetSidIdentifierAuthority_Proc
) (
237 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
240 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
242 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
244 SECURITY_INFORMATION RequestedInformation
,
245 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
247 LPDWORD lpnLengthNeeded
);
248 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
249 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
251 LPBOOL lpbOwnerDefaulted
);
252 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
253 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
255 LPBOOL lpbGroupDefaulted
);
256 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
258 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
260 DWORD th32ProcessID
);
261 typedef BOOL (WINAPI
* Process32First_Proc
) (
263 LPPROCESSENTRY32 lppe
);
264 typedef BOOL (WINAPI
* Process32Next_Proc
) (
266 LPPROCESSENTRY32 lppe
);
267 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
271 PHANDLE TokenHandle
);
272 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
273 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
274 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
275 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
277 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
279 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
281 DWORD
* lpMinimumWorkingSetSize
,
282 DWORD
* lpMaximumWorkingSetSize
);
283 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
284 LPMEMORYSTATUS lpBuffer
);
285 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
286 LPMEMORY_STATUS_EX lpBuffer
);
287 typedef BOOL (WINAPI
* CopySid_Proc
) (
288 DWORD nDestinationSidLength
,
289 PSID pDestinationSid
,
291 typedef BOOL (WINAPI
* EqualSid_Proc
) (
294 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
299 /* ** A utility function ** */
303 static BOOL s_b_ret
=0;
304 OSVERSIONINFO os_ver
;
305 if (g_b_init_is_windows_9x
== 0)
307 g_b_init_is_windows_9x
= 1;
308 ZeroMemory(&os_ver
, sizeof(OSVERSIONINFO
));
309 os_ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
310 if (GetVersionEx (&os_ver
))
312 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
318 /* Get total user and system times for get-internal-run-time.
319 Returns a list of three integers if the times are provided by the OS
320 (NT derivatives), otherwise it returns the result of current-time. */
322 w32_get_internal_run_time ()
324 if (get_process_times_fn
)
326 FILETIME create
, exit
, kernel
, user
;
327 HANDLE proc
= GetCurrentProcess();
328 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
330 LARGE_INTEGER user_int
, kernel_int
, total
;
332 user_int
.LowPart
= user
.dwLowDateTime
;
333 user_int
.HighPart
= user
.dwHighDateTime
;
334 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
335 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
336 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
337 /* FILETIME is 100 nanosecond increments, Emacs only wants
338 microsecond resolution. */
339 total
.QuadPart
/= 10;
340 microseconds
= total
.QuadPart
% 1000000;
341 total
.QuadPart
/= 1000000;
343 /* Sanity check to make sure we can represent the result. */
344 if (total
.HighPart
== 0)
346 int secs
= total
.LowPart
;
348 return list3 (make_number ((secs
>> 16) & 0xffff),
349 make_number (secs
& 0xffff),
350 make_number (microseconds
));
355 return Fcurrent_time ();
358 /* ** The wrapper functions ** */
360 BOOL WINAPI
open_process_token (
361 HANDLE ProcessHandle
,
365 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
366 HMODULE hm_advapi32
= NULL
;
367 if (is_windows_9x () == TRUE
)
371 if (g_b_init_open_process_token
== 0)
373 g_b_init_open_process_token
= 1;
374 hm_advapi32
= LoadLibrary ("Advapi32.dll");
375 s_pfn_Open_Process_Token
=
376 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
378 if (s_pfn_Open_Process_Token
== NULL
)
383 s_pfn_Open_Process_Token (
390 BOOL WINAPI
get_token_information (
392 TOKEN_INFORMATION_CLASS TokenInformationClass
,
393 LPVOID TokenInformation
,
394 DWORD TokenInformationLength
,
397 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
398 HMODULE hm_advapi32
= NULL
;
399 if (is_windows_9x () == TRUE
)
403 if (g_b_init_get_token_information
== 0)
405 g_b_init_get_token_information
= 1;
406 hm_advapi32
= LoadLibrary ("Advapi32.dll");
407 s_pfn_Get_Token_Information
=
408 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
410 if (s_pfn_Get_Token_Information
== NULL
)
415 s_pfn_Get_Token_Information (
417 TokenInformationClass
,
419 TokenInformationLength
,
424 BOOL WINAPI
lookup_account_sid (
425 LPCTSTR lpSystemName
,
430 LPDWORD cbDomainName
,
433 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
434 HMODULE hm_advapi32
= NULL
;
435 if (is_windows_9x () == TRUE
)
439 if (g_b_init_lookup_account_sid
== 0)
441 g_b_init_lookup_account_sid
= 1;
442 hm_advapi32
= LoadLibrary ("Advapi32.dll");
443 s_pfn_Lookup_Account_Sid
=
444 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
446 if (s_pfn_Lookup_Account_Sid
== NULL
)
451 s_pfn_Lookup_Account_Sid (
462 PSID_IDENTIFIER_AUTHORITY WINAPI
get_sid_identifier_authority (
465 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority
= NULL
;
466 HMODULE hm_advapi32
= NULL
;
467 if (is_windows_9x () == TRUE
)
471 if (g_b_init_get_sid_identifier_authority
== 0)
473 g_b_init_get_sid_identifier_authority
= 1;
474 hm_advapi32
= LoadLibrary ("Advapi32.dll");
475 s_pfn_Get_Sid_Identifier_Authority
=
476 (GetSidIdentifierAuthority_Proc
) GetProcAddress (
477 hm_advapi32
, "GetSidIdentifierAuthority");
479 if (s_pfn_Get_Sid_Identifier_Authority
== NULL
)
483 return (s_pfn_Get_Sid_Identifier_Authority (pSid
));
486 PDWORD WINAPI
get_sid_sub_authority (
490 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
491 static DWORD zero
= 0U;
492 HMODULE hm_advapi32
= NULL
;
493 if (is_windows_9x () == TRUE
)
497 if (g_b_init_get_sid_sub_authority
== 0)
499 g_b_init_get_sid_sub_authority
= 1;
500 hm_advapi32
= LoadLibrary ("Advapi32.dll");
501 s_pfn_Get_Sid_Sub_Authority
=
502 (GetSidSubAuthority_Proc
) GetProcAddress (
503 hm_advapi32
, "GetSidSubAuthority");
505 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
509 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
512 PUCHAR WINAPI
get_sid_sub_authority_count (
515 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
516 static UCHAR zero
= 0U;
517 HMODULE hm_advapi32
= NULL
;
518 if (is_windows_9x () == TRUE
)
522 if (g_b_init_get_sid_sub_authority_count
== 0)
524 g_b_init_get_sid_sub_authority_count
= 1;
525 hm_advapi32
= LoadLibrary ("Advapi32.dll");
526 s_pfn_Get_Sid_Sub_Authority_Count
=
527 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
528 hm_advapi32
, "GetSidSubAuthorityCount");
530 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
534 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
537 BOOL WINAPI
get_file_security (
539 SECURITY_INFORMATION RequestedInformation
,
540 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
542 LPDWORD lpnLengthNeeded
)
544 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
545 HMODULE hm_advapi32
= NULL
;
546 if (is_windows_9x () == TRUE
)
550 if (g_b_init_get_file_security
== 0)
552 g_b_init_get_file_security
= 1;
553 hm_advapi32
= LoadLibrary ("Advapi32.dll");
554 s_pfn_Get_File_Security
=
555 (GetFileSecurity_Proc
) GetProcAddress (
556 hm_advapi32
, GetFileSecurity_Name
);
558 if (s_pfn_Get_File_Security
== NULL
)
562 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
563 pSecurityDescriptor
, nLength
,
567 BOOL WINAPI
get_security_descriptor_owner (
568 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
570 LPBOOL lpbOwnerDefaulted
)
572 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
573 HMODULE hm_advapi32
= NULL
;
574 if (is_windows_9x () == TRUE
)
578 if (g_b_init_get_security_descriptor_owner
== 0)
580 g_b_init_get_security_descriptor_owner
= 1;
581 hm_advapi32
= LoadLibrary ("Advapi32.dll");
582 s_pfn_Get_Security_Descriptor_Owner
=
583 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
584 hm_advapi32
, "GetSecurityDescriptorOwner");
586 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
590 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
594 BOOL WINAPI
get_security_descriptor_group (
595 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
597 LPBOOL lpbGroupDefaulted
)
599 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
600 HMODULE hm_advapi32
= NULL
;
601 if (is_windows_9x () == TRUE
)
605 if (g_b_init_get_security_descriptor_group
== 0)
607 g_b_init_get_security_descriptor_group
= 1;
608 hm_advapi32
= LoadLibrary ("Advapi32.dll");
609 s_pfn_Get_Security_Descriptor_Group
=
610 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
611 hm_advapi32
, "GetSecurityDescriptorGroup");
613 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
617 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
621 BOOL WINAPI
is_valid_sid (
624 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
625 HMODULE hm_advapi32
= NULL
;
626 if (is_windows_9x () == TRUE
)
630 if (g_b_init_is_valid_sid
== 0)
632 g_b_init_is_valid_sid
= 1;
633 hm_advapi32
= LoadLibrary ("Advapi32.dll");
635 (IsValidSid_Proc
) GetProcAddress (
636 hm_advapi32
, "IsValidSid");
638 if (s_pfn_Is_Valid_Sid
== NULL
)
642 return (s_pfn_Is_Valid_Sid (sid
));
645 BOOL WINAPI
equal_sid (
649 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
650 HMODULE hm_advapi32
= NULL
;
651 if (is_windows_9x () == TRUE
)
655 if (g_b_init_equal_sid
== 0)
657 g_b_init_equal_sid
= 1;
658 hm_advapi32
= LoadLibrary ("Advapi32.dll");
660 (EqualSid_Proc
) GetProcAddress (
661 hm_advapi32
, "EqualSid");
663 if (s_pfn_Equal_Sid
== NULL
)
667 return (s_pfn_Equal_Sid (sid1
, sid2
));
670 DWORD WINAPI
get_length_sid (
673 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
674 HMODULE hm_advapi32
= NULL
;
675 if (is_windows_9x () == TRUE
)
679 if (g_b_init_get_length_sid
== 0)
681 g_b_init_get_length_sid
= 1;
682 hm_advapi32
= LoadLibrary ("Advapi32.dll");
683 s_pfn_Get_Length_Sid
=
684 (GetLengthSid_Proc
) GetProcAddress (
685 hm_advapi32
, "GetLengthSid");
687 if (s_pfn_Get_Length_Sid
== NULL
)
691 return (s_pfn_Get_Length_Sid (sid
));
694 BOOL WINAPI
copy_sid (
699 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
700 HMODULE hm_advapi32
= NULL
;
701 if (is_windows_9x () == TRUE
)
705 if (g_b_init_copy_sid
== 0)
707 g_b_init_copy_sid
= 1;
708 hm_advapi32
= LoadLibrary ("Advapi32.dll");
710 (CopySid_Proc
) GetProcAddress (
711 hm_advapi32
, "CopySid");
713 if (s_pfn_Copy_Sid
== NULL
)
717 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
721 END: Wrapper functions around OpenProcessToken
722 and other functions in advapi32.dll that are only
723 supported in Windows NT / 2k / XP
727 /* Equivalent of strerror for W32 error codes. */
729 w32_strerror (int error_no
)
731 static char buf
[500];
734 error_no
= GetLastError ();
737 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
739 0, /* choose most suitable language */
740 buf
, sizeof (buf
), NULL
))
741 sprintf (buf
, "w32 error %u", error_no
);
745 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
746 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
748 This is called from alloc.c:valid_pointer_p. */
750 w32_valid_pointer_p (void *p
, int size
)
753 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
757 unsigned char *buf
= alloca (size
);
758 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
767 static char startup_dir
[MAXPATHLEN
];
769 /* Get the current working directory. */
774 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
778 /* Emacs doesn't actually change directory itself, and we want to
779 force our real wd to be where emacs.exe is to avoid unnecessary
780 conflicts when trying to rename or delete directories. */
781 strcpy (dir
, startup_dir
);
787 /* Emulate gethostname. */
789 gethostname (char *buffer
, int size
)
791 /* NT only allows small host names, so the buffer is
792 certainly large enough. */
793 return !GetComputerName (buffer
, &size
);
795 #endif /* HAVE_SOCKETS */
797 /* Emulate getloadavg. */
799 getloadavg (double loadavg
[], int nelem
)
803 /* A faithful emulation is going to have to be saved for a rainy day. */
804 for (i
= 0; i
< nelem
; i
++)
811 /* Emulate getpwuid, getpwnam and others. */
813 #define PASSWD_FIELD_SIZE 256
815 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
816 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
817 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
818 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
819 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
821 static struct passwd dflt_passwd
=
833 static char dflt_group_name
[GNLEN
+1];
835 static struct group dflt_group
=
837 /* When group information is not available, we return this as the
838 group for all files. */
846 return dflt_passwd
.pw_uid
;
852 /* I could imagine arguing for checking to see whether the user is
853 in the Administrators group and returning a UID of 0 for that
854 case, but I don't know how wise that would be in the long run. */
861 return dflt_passwd
.pw_gid
;
873 if (uid
== dflt_passwd
.pw_uid
)
885 getpwnam (char *name
)
889 pw
= getpwuid (getuid ());
893 if (xstrcasecmp (name
, pw
->pw_name
))
902 /* Find the user's real name by opening the process token and
903 looking up the name associated with the user-sid in that token.
905 Use the relative portion of the identifier authority value from
906 the user-sid as the user id value (same for group id using the
907 primary group sid from the process token). */
909 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
910 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
911 DWORD glength
= sizeof (gname
);
913 SID_NAME_USE user_type
;
914 unsigned char *buf
= NULL
;
916 TOKEN_USER user_token
;
917 TOKEN_PRIMARY_GROUP group_token
;
920 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
923 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
924 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
926 buf
= xmalloc (blen
);
927 result
= get_token_information (token
, TokenUser
,
928 (LPVOID
)buf
, blen
, &needed
);
931 memcpy (&user_token
, buf
, sizeof (user_token
));
932 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
934 domain
, &dlength
, &user_type
);
942 strcpy (dflt_passwd
.pw_name
, uname
);
943 /* Determine a reasonable uid value. */
944 if (xstrcasecmp ("administrator", uname
) == 0)
946 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
947 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
951 /* Use the last sub-authority value of the RID, the relative
952 portion of the SID, as user/group ID. */
953 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
955 /* Get group id and name. */
956 result
= get_token_information (token
, TokenPrimaryGroup
,
957 (LPVOID
)buf
, blen
, &needed
);
958 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
960 buf
= xrealloc (buf
, blen
= needed
);
961 result
= get_token_information (token
, TokenPrimaryGroup
,
962 (LPVOID
)buf
, blen
, &needed
);
966 memcpy (&group_token
, buf
, sizeof (group_token
));
967 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
968 dlength
= sizeof (domain
);
969 /* If we can get at the real Primary Group name, use that.
970 Otherwise, the default group name was already set to
971 "None" in globals_of_w32. */
972 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
973 gname
, &glength
, NULL
, &dlength
,
975 strcpy (dflt_group_name
, gname
);
978 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
981 /* If security calls are not supported (presumably because we
982 are running under Windows 9X), fallback to this: */
983 else if (GetUserName (uname
, &ulength
))
985 strcpy (dflt_passwd
.pw_name
, uname
);
986 if (xstrcasecmp ("administrator", uname
) == 0)
987 dflt_passwd
.pw_uid
= 0;
989 dflt_passwd
.pw_uid
= 123;
990 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
994 strcpy (dflt_passwd
.pw_name
, "unknown");
995 dflt_passwd
.pw_uid
= 123;
996 dflt_passwd
.pw_gid
= 123;
998 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1000 /* Ensure HOME and SHELL are defined. */
1001 if (getenv ("HOME") == NULL
)
1003 if (getenv ("SHELL") == NULL
)
1006 /* Set dir and shell from environment variables. */
1007 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1008 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1012 CloseHandle (token
);
1018 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1019 return ((rand () << 15) | rand ());
1029 /* Normalize filename by converting all path separators to
1030 the specified separator. Also conditionally convert upper
1031 case path name components to lower case. */
1034 normalize_filename (fp
, path_sep
)
1041 /* Always lower-case drive letters a-z, even if the filesystem
1042 preserves case in filenames.
1043 This is so filenames can be compared by string comparison
1044 functions that are case-sensitive. Even case-preserving filesystems
1045 do not distinguish case in drive letters. */
1046 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1052 if (NILP (Vw32_downcase_file_names
))
1056 if (*fp
== '/' || *fp
== '\\')
1063 sep
= path_sep
; /* convert to this path separator */
1064 elem
= fp
; /* start of current path element */
1067 if (*fp
>= 'a' && *fp
<= 'z')
1068 elem
= 0; /* don't convert this element */
1070 if (*fp
== 0 || *fp
== ':')
1072 sep
= *fp
; /* restore current separator (or 0) */
1073 *fp
= '/'; /* after conversion of this element */
1076 if (*fp
== '/' || *fp
== '\\')
1078 if (elem
&& elem
!= fp
)
1080 *fp
= 0; /* temporary end of string */
1081 _strlwr (elem
); /* while we convert to lower case */
1083 *fp
= sep
; /* convert (or restore) path separator */
1084 elem
= fp
+ 1; /* next element starts after separator */
1090 /* Destructively turn backslashes into slashes. */
1092 dostounix_filename (p
)
1095 normalize_filename (p
, '/');
1098 /* Destructively turn slashes into backslashes. */
1100 unixtodos_filename (p
)
1103 normalize_filename (p
, '\\');
1106 /* Remove all CR's that are followed by a LF.
1107 (From msdos.c...probably should figure out a way to share it,
1108 although this code isn't going to ever change.) */
1112 register unsigned char *buf
;
1114 unsigned char *np
= buf
;
1115 unsigned char *startp
= buf
;
1116 unsigned char *endp
= buf
+ n
;
1120 while (buf
< endp
- 1)
1124 if (*(++buf
) != 0x0a)
1135 /* Parse the root part of file name, if present. Return length and
1136 optionally store pointer to char after root. */
1138 parse_root (char * name
, char ** pPath
)
1140 char * start
= name
;
1145 /* find the root name of the volume if given */
1146 if (isalpha (name
[0]) && name
[1] == ':')
1148 /* skip past drive specifier */
1150 if (IS_DIRECTORY_SEP (name
[0]))
1153 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1159 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1164 if (IS_DIRECTORY_SEP (name
[0]))
1171 return name
- start
;
1174 /* Get long base name for name; name is assumed to be absolute. */
1176 get_long_basename (char * name
, char * buf
, int size
)
1178 WIN32_FIND_DATA find_data
;
1182 /* must be valid filename, no wild cards or other invalid characters */
1183 if (_mbspbrk (name
, "*?|<>\""))
1186 dir_handle
= FindFirstFile (name
, &find_data
);
1187 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1189 if ((len
= strlen (find_data
.cFileName
)) < size
)
1190 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1193 FindClose (dir_handle
);
1198 /* Get long name for file, if possible (assumed to be absolute). */
1200 w32_get_long_filename (char * name
, char * buf
, int size
)
1205 char full
[ MAX_PATH
];
1208 len
= strlen (name
);
1209 if (len
>= MAX_PATH
)
1212 /* Use local copy for destructive modification. */
1213 memcpy (full
, name
, len
+1);
1214 unixtodos_filename (full
);
1216 /* Copy root part verbatim. */
1217 len
= parse_root (full
, &p
);
1218 memcpy (o
, full
, len
);
1223 while (p
!= NULL
&& *p
)
1226 p
= strchr (q
, '\\');
1228 len
= get_long_basename (full
, o
, size
);
1251 is_unc_volume (const char *filename
)
1253 const char *ptr
= filename
;
1255 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1258 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1264 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1267 sigsetmask (int signal_mask
)
1285 sigunblock (int sig
)
1291 setpgrp (int pid
, int gid
)
1302 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1305 w32_get_resource (key
, lpdwtype
)
1310 HKEY hrootkey
= NULL
;
1313 /* Check both the current user and the local machine to see if
1314 we have any resources. */
1316 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1320 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1321 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1322 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1324 RegCloseKey (hrootkey
);
1330 RegCloseKey (hrootkey
);
1333 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1337 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1338 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1339 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1341 RegCloseKey (hrootkey
);
1347 RegCloseKey (hrootkey
);
1353 char *get_emacs_configuration (void);
1354 extern Lisp_Object Vsystem_configuration
;
1357 init_environment (char ** argv
)
1359 static const char * const tempdirs
[] = {
1360 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1365 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1367 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1368 temporary files and assume "/tmp" if $TMPDIR is unset, which
1369 will break on DOS/Windows. Refuse to work if we cannot find
1370 a directory, not even "c:/", usable for that purpose. */
1371 for (i
= 0; i
< imax
; i
++)
1373 const char *tmp
= tempdirs
[i
];
1376 tmp
= getenv (tmp
+ 1);
1377 /* Note that `access' can lie to us if the directory resides on a
1378 read-only filesystem, like CD-ROM or a write-protected floppy.
1379 The only way to be really sure is to actually create a file and
1380 see if it succeeds. But I think that's too much to ask. */
1381 if (tmp
&& _access (tmp
, D_OK
) == 0)
1383 char * var
= alloca (strlen (tmp
) + 8);
1384 sprintf (var
, "TMPDIR=%s", tmp
);
1385 _putenv (strdup (var
));
1392 Fcons (build_string ("no usable temporary directories found!!"),
1394 "While setting TMPDIR: ");
1396 /* Check for environment variables and use registry settings if they
1397 don't exist. Fallback on default values where applicable. */
1402 char locale_name
[32];
1403 struct stat ignored
;
1404 char default_home
[MAX_PATH
];
1406 static const struct env_entry
1413 {"PRELOAD_WINSOCK", NULL
},
1414 {"emacs_dir", "C:/emacs"},
1415 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1416 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1417 {"EMACSDATA", "%emacs_dir%/etc"},
1418 {"EMACSPATH", "%emacs_dir%/bin"},
1419 /* We no longer set INFOPATH because Info-default-directory-list
1421 /* {"INFOPATH", "%emacs_dir%/info"}, */
1422 {"EMACSDOC", "%emacs_dir%/etc"},
1427 #define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1429 /* We need to copy dflt_envvars[] and work on the copy because we
1430 don't want the dumped Emacs to inherit the values of
1431 environment variables we saw during dumping (which could be on
1432 a different system). The defaults above must be left intact. */
1433 struct env_entry env_vars
[N_ENV_VARS
];
1435 for (i
= 0; i
< N_ENV_VARS
; i
++)
1436 env_vars
[i
] = dflt_envvars
[i
];
1438 /* For backwards compatibility, check if a .emacs file exists in C:/
1439 If not, then we can try to default to the appdata directory under the
1440 user's profile, which is more likely to be writable. */
1441 if (stat ("C:/.emacs", &ignored
) < 0)
1443 HRESULT profile_result
;
1444 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1445 of Windows 95 and NT4 that have not been updated to include
1447 ShGetFolderPath_fn get_folder_path
;
1448 get_folder_path
= (ShGetFolderPath_fn
)
1449 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1451 if (get_folder_path
!= NULL
)
1453 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1456 /* If we can't get the appdata dir, revert to old behavior. */
1457 if (profile_result
== S_OK
)
1458 env_vars
[0].def_value
= default_home
;
1462 /* Get default locale info and use it for LANG. */
1463 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1464 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1465 locale_name
, sizeof (locale_name
)))
1467 for (i
= 0; i
< N_ENV_VARS
; i
++)
1469 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1471 env_vars
[i
].def_value
= locale_name
;
1477 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1479 /* Treat emacs_dir specially: set it unconditionally based on our
1480 location, if it appears that we are running from the bin subdir
1481 of a standard installation. */
1484 char modname
[MAX_PATH
];
1486 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1488 if ((p
= strrchr (modname
, '\\')) == NULL
)
1492 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1494 char buf
[SET_ENV_BUF_SIZE
];
1497 for (p
= modname
; *p
; p
++)
1498 if (*p
== '\\') *p
= '/';
1500 _snprintf (buf
, sizeof(buf
)-1, "emacs_dir=%s", modname
);
1501 _putenv (strdup (buf
));
1503 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1505 /* FIXME: should use substring of get_emacs_configuration ().
1506 But I don't think the Windows build supports alpha, mips etc
1507 anymore, so have taken the easy option for now. */
1508 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1511 p
= strrchr (modname
, '\\');
1515 p
= strrchr (modname
, '\\');
1516 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1518 char buf
[SET_ENV_BUF_SIZE
];
1521 for (p
= modname
; *p
; p
++)
1522 if (*p
== '\\') *p
= '/';
1524 _snprintf (buf
, sizeof(buf
)-1, "emacs_dir=%s", modname
);
1525 _putenv (strdup (buf
));
1531 for (i
= 0; i
< N_ENV_VARS
; i
++)
1533 if (!getenv (env_vars
[i
].name
))
1537 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1538 /* Also ignore empty environment variables. */
1542 lpval
= env_vars
[i
].def_value
;
1543 dwType
= REG_EXPAND_SZ
;
1549 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1551 if (dwType
== REG_EXPAND_SZ
)
1552 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof(buf1
));
1553 else if (dwType
== REG_SZ
)
1554 strcpy (buf1
, lpval
);
1555 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1557 _snprintf (buf2
, sizeof(buf2
)-1, "%s=%s", env_vars
[i
].name
,
1559 _putenv (strdup (buf2
));
1569 /* Rebuild system configuration to reflect invoking system. */
1570 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1572 /* Another special case: on NT, the PATH variable is actually named
1573 "Path" although cmd.exe (perhaps NT itself) arranges for
1574 environment variable lookup and setting to be case insensitive.
1575 However, Emacs assumes a fully case sensitive environment, so we
1576 need to change "Path" to "PATH" to match the expectations of
1577 various elisp packages. We do this by the sneaky method of
1578 modifying the string in the C runtime environ entry.
1580 The same applies to COMSPEC. */
1584 for (envp
= environ
; *envp
; envp
++)
1585 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1586 memcpy (*envp
, "PATH=", 5);
1587 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1588 memcpy (*envp
, "COMSPEC=", 8);
1591 /* Remember the initial working directory for getwd, then make the
1592 real wd be the location of emacs.exe to avoid conflicts when
1593 renaming or deleting directories. (We also don't call chdir when
1594 running subprocesses for the same reason.) */
1595 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1600 static char modname
[MAX_PATH
];
1602 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1604 if ((p
= strrchr (modname
, '\\')) == NULL
)
1608 SetCurrentDirectory (modname
);
1610 /* Ensure argv[0] has the full path to Emacs. */
1615 /* Determine if there is a middle mouse button, to allow parse_button
1616 to decide whether right mouse events should be mouse-2 or
1618 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1624 emacs_root_dir (void)
1626 static char root_dir
[FILENAME_MAX
];
1629 p
= getenv ("emacs_dir");
1632 strcpy (root_dir
, p
);
1633 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1634 dostounix_filename (root_dir
);
1638 /* We don't have scripts to automatically determine the system configuration
1639 for Emacs before it's compiled, and we don't want to have to make the
1640 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1644 get_emacs_configuration (void)
1646 char *arch
, *oem
, *os
;
1648 static char configuration_buffer
[32];
1650 /* Determine the processor type. */
1651 switch (get_processor_type ())
1654 #ifdef PROCESSOR_INTEL_386
1655 case PROCESSOR_INTEL_386
:
1656 case PROCESSOR_INTEL_486
:
1657 case PROCESSOR_INTEL_PENTIUM
:
1662 #ifdef PROCESSOR_MIPS_R2000
1663 case PROCESSOR_MIPS_R2000
:
1664 case PROCESSOR_MIPS_R3000
:
1665 case PROCESSOR_MIPS_R4000
:
1670 #ifdef PROCESSOR_ALPHA_21064
1671 case PROCESSOR_ALPHA_21064
:
1681 /* Use the OEM field to reflect the compiler/library combination. */
1683 #define COMPILER_NAME "msvc"
1686 #define COMPILER_NAME "mingw"
1688 #define COMPILER_NAME "unknown"
1691 oem
= COMPILER_NAME
;
1693 switch (osinfo_cache
.dwPlatformId
) {
1694 case VER_PLATFORM_WIN32_NT
:
1696 build_num
= osinfo_cache
.dwBuildNumber
;
1698 case VER_PLATFORM_WIN32_WINDOWS
:
1699 if (osinfo_cache
.dwMinorVersion
== 0) {
1704 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1706 case VER_PLATFORM_WIN32s
:
1707 /* Not supported, should not happen. */
1709 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1717 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1718 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1719 get_w32_major_version (), get_w32_minor_version (), build_num
);
1721 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1724 return configuration_buffer
;
1728 get_emacs_configuration_options (void)
1730 static char options_buffer
[256];
1732 /* Work out the effective configure options for this build. */
1734 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1737 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1739 #define COMPILER_VERSION ""
1743 sprintf (options_buffer
, COMPILER_VERSION
);
1745 strcat (options_buffer
, " --no-opt");
1748 strcat (options_buffer
, " --cflags");
1749 strcat (options_buffer
, USER_CFLAGS
);
1752 strcat (options_buffer
, " --ldflags");
1753 strcat (options_buffer
, USER_LDFLAGS
);
1755 return options_buffer
;
1759 #include <sys/timeb.h>
1761 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1763 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1768 tv
->tv_sec
= tb
.time
;
1769 tv
->tv_usec
= tb
.millitm
* 1000L;
1772 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1773 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1777 /* ------------------------------------------------------------------------- */
1778 /* IO support and wrapper functions for W32 API. */
1779 /* ------------------------------------------------------------------------- */
1781 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1782 on network directories, so we handle that case here.
1783 (Ulrich Leodolter, 1/11/95). */
1785 sys_ctime (const time_t *t
)
1787 char *str
= (char *) ctime (t
);
1788 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1791 /* Emulate sleep...we could have done this with a define, but that
1792 would necessitate including windows.h in the files that used it.
1793 This is much easier. */
1795 sys_sleep (int seconds
)
1797 Sleep (seconds
* 1000);
1800 /* Internal MSVC functions for low-level descriptor munging */
1801 extern int __cdecl
_set_osfhnd (int fd
, long h
);
1802 extern int __cdecl
_free_osfhnd (int fd
);
1804 /* parallel array of private info on file handles */
1805 filedesc fd_info
[ MAXDESC
];
1807 typedef struct volume_info_data
{
1808 struct volume_info_data
* next
;
1810 /* time when info was obtained */
1813 /* actual volume info */
1822 /* Global referenced by various functions. */
1823 static volume_info_data volume_info
;
1825 /* Vector to indicate which drives are local and fixed (for which cached
1826 data never expires). */
1827 static BOOL fixed_drives
[26];
1829 /* Consider cached volume information to be stale if older than 10s,
1830 at least for non-local drives. Info for fixed drives is never stale. */
1831 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
1832 #define VOLINFO_STILL_VALID( root_dir, info ) \
1833 ( ( isalpha (root_dir[0]) && \
1834 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
1835 || GetTickCount () - info->timestamp < 10000 )
1837 /* Cache support functions. */
1839 /* Simple linked list with linear search is sufficient. */
1840 static volume_info_data
*volume_cache
= NULL
;
1842 static volume_info_data
*
1843 lookup_volume_info (char * root_dir
)
1845 volume_info_data
* info
;
1847 for (info
= volume_cache
; info
; info
= info
->next
)
1848 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
1854 add_volume_info (char * root_dir
, volume_info_data
* info
)
1856 info
->root_dir
= xstrdup (root_dir
);
1857 info
->next
= volume_cache
;
1858 volume_cache
= info
;
1862 /* Wrapper for GetVolumeInformation, which uses caching to avoid
1863 performance penalty (~2ms on 486 for local drives, 7.5ms for local
1864 cdrom drive, ~5-10ms or more for remote drives on LAN). */
1866 GetCachedVolumeInformation (char * root_dir
)
1868 volume_info_data
* info
;
1869 char default_root
[ MAX_PATH
];
1871 /* NULL for root_dir means use root from current directory. */
1872 if (root_dir
== NULL
)
1874 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
1876 parse_root (default_root
, &root_dir
);
1878 root_dir
= default_root
;
1881 /* Local fixed drives can be cached permanently. Removable drives
1882 cannot be cached permanently, since the volume name and serial
1883 number (if nothing else) can change. Remote drives should be
1884 treated as if they are removable, since there is no sure way to
1885 tell whether they are or not. Also, the UNC association of drive
1886 letters mapped to remote volumes can be changed at any time (even
1887 by other processes) without notice.
1889 As a compromise, so we can benefit from caching info for remote
1890 volumes, we use a simple expiry mechanism to invalidate cache
1891 entries that are more than ten seconds old. */
1894 /* No point doing this, because WNetGetConnection is even slower than
1895 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
1896 GetDriveType is about the only call of this type which does not
1897 involve network access, and so is extremely quick). */
1899 /* Map drive letter to UNC if remote. */
1900 if ( isalpha( root_dir
[0] ) && !fixed
[ DRIVE_INDEX( root_dir
[0] ) ] )
1902 char remote_name
[ 256 ];
1903 char drive
[3] = { root_dir
[0], ':' };
1905 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
1907 /* do something */ ;
1911 info
= lookup_volume_info (root_dir
);
1913 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
1921 /* Info is not cached, or is stale. */
1922 if (!GetVolumeInformation (root_dir
,
1923 name
, sizeof (name
),
1927 type
, sizeof (type
)))
1930 /* Cache the volume information for future use, overwriting existing
1931 entry if present. */
1934 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
1935 add_volume_info (root_dir
, info
);
1943 info
->name
= xstrdup (name
);
1944 info
->serialnum
= serialnum
;
1945 info
->maxcomp
= maxcomp
;
1946 info
->flags
= flags
;
1947 info
->type
= xstrdup (type
);
1948 info
->timestamp
= GetTickCount ();
1954 /* Get information on the volume where name is held; set path pointer to
1955 start of pathname in name (past UNC header\volume header if present). */
1957 get_volume_info (const char * name
, const char ** pPath
)
1959 char temp
[MAX_PATH
];
1960 char *rootname
= NULL
; /* default to current volume */
1961 volume_info_data
* info
;
1966 /* find the root name of the volume if given */
1967 if (isalpha (name
[0]) && name
[1] == ':')
1975 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1982 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1995 info
= GetCachedVolumeInformation (rootname
);
1998 /* Set global referenced by other functions. */
1999 volume_info
= *info
;
2005 /* Determine if volume is FAT format (ie. only supports short 8.3
2006 names); also set path pointer to start of pathname in name. */
2008 is_fat_volume (const char * name
, const char ** pPath
)
2010 if (get_volume_info (name
, pPath
))
2011 return (volume_info
.maxcomp
== 12);
2015 /* Map filename to a valid 8.3 name if necessary. */
2017 map_w32_filename (const char * name
, const char ** pPath
)
2019 static char shortname
[MAX_PATH
];
2020 char * str
= shortname
;
2023 const char * save_name
= name
;
2025 if (strlen (name
) >= MAX_PATH
)
2027 /* Return a filename which will cause callers to fail. */
2028 strcpy (shortname
, "?");
2032 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2034 register int left
= 8; /* maximum number of chars in part */
2035 register int extn
= 0; /* extension added? */
2036 register int dots
= 2; /* maximum number of dots allowed */
2039 *str
++ = *name
++; /* skip past UNC header */
2041 while ((c
= *name
++))
2048 extn
= 0; /* reset extension flags */
2049 dots
= 2; /* max 2 dots */
2050 left
= 8; /* max length 8 for main part */
2054 extn
= 0; /* reset extension flags */
2055 dots
= 2; /* max 2 dots */
2056 left
= 8; /* max length 8 for main part */
2061 /* Convert path components of the form .xxx to _xxx,
2062 but leave . and .. as they are. This allows .emacs
2063 to be read as _emacs, for example. */
2067 IS_DIRECTORY_SEP (*name
))
2082 extn
= 1; /* we've got an extension */
2083 left
= 3; /* 3 chars in extension */
2087 /* any embedded dots after the first are converted to _ */
2092 case '#': /* don't lose these, they're important */
2094 str
[-1] = c
; /* replace last character of part */
2099 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2101 dots
= 0; /* started a path component */
2110 strcpy (shortname
, name
);
2111 unixtodos_filename (shortname
);
2115 *pPath
= shortname
+ (path
- save_name
);
2121 is_exec (const char * name
)
2123 char * p
= strrchr (name
, '.');
2126 && (xstrcasecmp (p
, ".exe") == 0 ||
2127 xstrcasecmp (p
, ".com") == 0 ||
2128 xstrcasecmp (p
, ".bat") == 0 ||
2129 xstrcasecmp (p
, ".cmd") == 0));
2132 /* Emulate the Unix directory procedures opendir, closedir,
2133 and readdir. We can't use the procedures supplied in sysdep.c,
2134 so we provide them here. */
2136 struct direct dir_static
; /* simulated directory contents */
2137 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2138 static int dir_is_fat
;
2139 static char dir_pathname
[MAXPATHLEN
+1];
2140 static WIN32_FIND_DATA dir_find_data
;
2142 /* Support shares on a network resource as subdirectories of a read-only
2144 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2145 HANDLE
open_unc_volume (const char *);
2146 char *read_unc_volume (HANDLE
, char *, int);
2147 void close_unc_volume (HANDLE
);
2150 opendir (char *filename
)
2154 /* Opening is done by FindFirstFile. However, a read is inherent to
2155 this operation, so we defer the open until read time. */
2157 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2159 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2162 if (is_unc_volume (filename
))
2164 wnet_enum_handle
= open_unc_volume (filename
);
2165 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2169 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2176 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2177 dir_pathname
[MAXPATHLEN
] = '\0';
2178 dir_is_fat
= is_fat_volume (filename
, NULL
);
2184 closedir (DIR *dirp
)
2186 /* If we have a find-handle open, close it. */
2187 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2189 FindClose (dir_find_handle
);
2190 dir_find_handle
= INVALID_HANDLE_VALUE
;
2192 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2194 close_unc_volume (wnet_enum_handle
);
2195 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2197 xfree ((char *) dirp
);
2203 int downcase
= !NILP (Vw32_downcase_file_names
);
2205 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2207 if (!read_unc_volume (wnet_enum_handle
,
2208 dir_find_data
.cFileName
,
2212 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2213 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2215 char filename
[MAXNAMLEN
+ 3];
2218 strcpy (filename
, dir_pathname
);
2219 ln
= strlen (filename
) - 1;
2220 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2221 strcat (filename
, "\\");
2222 strcat (filename
, "*");
2224 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2226 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2231 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2235 /* Emacs never uses this value, so don't bother making it match
2236 value returned by stat(). */
2237 dir_static
.d_ino
= 1;
2239 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2241 /* If the file name in cFileName[] includes `?' characters, it means
2242 the original file name used characters that cannot be represented
2243 by the current ANSI codepage. To avoid total lossage, retrieve
2244 the short 8+3 alias of the long file name. */
2245 if (_mbspbrk (dir_static
.d_name
, "?"))
2247 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2248 downcase
= 1; /* 8+3 aliases are returned in all caps */
2250 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2251 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2252 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2254 /* If the file name in cFileName[] includes `?' characters, it means
2255 the original file name used characters that cannot be represented
2256 by the current ANSI codepage. To avoid total lossage, retrieve
2257 the short 8+3 alias of the long file name. */
2258 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2260 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2261 /* 8+3 aliases are returned in all caps, which could break
2262 various alists that look at filenames' extensions. */
2266 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2267 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2269 _strlwr (dir_static
.d_name
);
2273 for (p
= dir_static
.d_name
; *p
; p
++)
2274 if (*p
>= 'a' && *p
<= 'z')
2277 _strlwr (dir_static
.d_name
);
2284 open_unc_volume (const char *path
)
2290 nr
.dwScope
= RESOURCE_GLOBALNET
;
2291 nr
.dwType
= RESOURCETYPE_DISK
;
2292 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2293 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2294 nr
.lpLocalName
= NULL
;
2295 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2296 nr
.lpComment
= NULL
;
2297 nr
.lpProvider
= NULL
;
2299 result
= WNetOpenEnum(RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2300 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2302 if (result
== NO_ERROR
)
2305 return INVALID_HANDLE_VALUE
;
2309 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2313 DWORD bufsize
= 512;
2318 buffer
= alloca (bufsize
);
2319 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2320 if (result
!= NO_ERROR
)
2323 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2324 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2326 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2329 strncpy (readbuf
, ptr
, size
);
2334 close_unc_volume (HANDLE henum
)
2336 if (henum
!= INVALID_HANDLE_VALUE
)
2337 WNetCloseEnum (henum
);
2341 unc_volume_file_attributes (const char *path
)
2346 henum
= open_unc_volume (path
);
2347 if (henum
== INVALID_HANDLE_VALUE
)
2350 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2352 close_unc_volume (henum
);
2357 /* Ensure a network connection is authenticated. */
2359 logon_network_drive (const char *path
)
2361 NETRESOURCE resource
;
2362 char share
[MAX_PATH
];
2366 sprintf (drive
, "%c:\\", path
[0]);
2368 /* Only logon to networked drives. */
2369 if ((!IS_DIRECTORY_SEP (path
[0]) || !IS_DIRECTORY_SEP (path
[1]))
2370 && GetDriveType (drive
) != DRIVE_REMOTE
)
2374 strncpy (share
, path
, MAX_PATH
);
2375 /* Truncate to just server and share name. */
2376 for (i
= 2; i
< MAX_PATH
; i
++)
2378 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2385 resource
.dwType
= RESOURCETYPE_DISK
;
2386 resource
.lpLocalName
= NULL
;
2387 resource
.lpRemoteName
= share
;
2388 resource
.lpProvider
= NULL
;
2390 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2393 /* Shadow some MSVC runtime functions to map requests for long filenames
2394 to reasonable short names if necessary. This was originally added to
2395 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2399 sys_access (const char * path
, int mode
)
2403 /* MSVC implementation doesn't recognize D_OK. */
2404 path
= map_w32_filename (path
, NULL
);
2405 if (is_unc_volume (path
))
2407 attributes
= unc_volume_file_attributes (path
);
2408 if (attributes
== -1) {
2413 else if ((attributes
= GetFileAttributes (path
)) == -1)
2415 /* Should try mapping GetLastError to errno; for now just indicate
2416 that path doesn't exist. */
2420 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2425 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2430 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2439 sys_chdir (const char * path
)
2441 return _chdir (map_w32_filename (path
, NULL
));
2445 sys_chmod (const char * path
, int mode
)
2447 return _chmod (map_w32_filename (path
, NULL
), mode
);
2451 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2453 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2459 sys_creat (const char * path
, int mode
)
2461 return _creat (map_w32_filename (path
, NULL
), mode
);
2465 sys_fopen(const char * path
, const char * mode
)
2469 const char * mode_save
= mode
;
2471 /* Force all file handles to be non-inheritable. This is necessary to
2472 ensure child processes don't unwittingly inherit handles that might
2473 prevent future file access. */
2477 else if (mode
[0] == 'w' || mode
[0] == 'a')
2478 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2482 /* Only do simplistic option parsing. */
2486 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2489 else if (mode
[0] == 'b')
2494 else if (mode
[0] == 't')
2501 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2505 return _fdopen (fd
, mode_save
);
2508 /* This only works on NTFS volumes, but is useful to have. */
2510 sys_link (const char * old
, const char * new)
2514 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2516 if (old
== NULL
|| new == NULL
)
2522 strcpy (oldname
, map_w32_filename (old
, NULL
));
2523 strcpy (newname
, map_w32_filename (new, NULL
));
2525 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2526 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2527 if (fileh
!= INVALID_HANDLE_VALUE
)
2531 /* Confusingly, the "alternate" stream name field does not apply
2532 when restoring a hard link, and instead contains the actual
2533 stream data for the link (ie. the name of the link to create).
2534 The WIN32_STREAM_ID structure before the cStreamName field is
2535 the stream header, which is then immediately followed by the
2539 WIN32_STREAM_ID wid
;
2540 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2543 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2544 data
.wid
.cStreamName
, MAX_PATH
);
2547 LPVOID context
= NULL
;
2550 data
.wid
.dwStreamId
= BACKUP_LINK
;
2551 data
.wid
.dwStreamAttributes
= 0;
2552 data
.wid
.Size
.LowPart
= wlen
* sizeof(WCHAR
);
2553 data
.wid
.Size
.HighPart
= 0;
2554 data
.wid
.dwStreamNameSize
= 0;
2556 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2557 offsetof (WIN32_STREAM_ID
, cStreamName
)
2558 + data
.wid
.Size
.LowPart
,
2559 &wbytes
, FALSE
, FALSE
, &context
)
2560 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2567 /* Should try mapping GetLastError to errno; for now just
2568 indicate a general error (eg. links not supported). */
2569 errno
= EINVAL
; // perhaps EMLINK?
2573 CloseHandle (fileh
);
2582 sys_mkdir (const char * path
)
2584 return _mkdir (map_w32_filename (path
, NULL
));
2587 /* Because of long name mapping issues, we need to implement this
2588 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2589 a unique name, instead of setting the input template to an empty
2592 Standard algorithm seems to be use pid or tid with a letter on the
2593 front (in place of the 6 X's) and cycle through the letters to find a
2594 unique name. We extend that to allow any reasonable character as the
2595 first of the 6 X's. */
2597 sys_mktemp (char * template)
2601 unsigned uid
= GetCurrentThreadId ();
2602 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2604 if (template == NULL
)
2606 p
= template + strlen (template);
2608 /* replace up to the last 5 X's with uid in decimal */
2609 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2611 p
[0] = '0' + uid
% 10;
2615 if (i
< 0 && p
[0] == 'X')
2620 int save_errno
= errno
;
2621 p
[0] = first_char
[i
];
2622 if (sys_access (template, 0) < 0)
2628 while (++i
< sizeof (first_char
));
2631 /* Template is badly formed or else we can't generate a unique name,
2632 so return empty string */
2638 sys_open (const char * path
, int oflag
, int mode
)
2640 const char* mpath
= map_w32_filename (path
, NULL
);
2641 /* Try to open file without _O_CREAT, to be able to write to hidden
2642 and system files. Force all file handles to be
2644 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2647 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2651 sys_rename (const char * oldname
, const char * newname
)
2654 char temp
[MAX_PATH
];
2656 /* MoveFile on Windows 95 doesn't correctly change the short file name
2657 alias in a number of circumstances (it is not easy to predict when
2658 just by looking at oldname and newname, unfortunately). In these
2659 cases, renaming through a temporary name avoids the problem.
2661 A second problem on Windows 95 is that renaming through a temp name when
2662 newname is uppercase fails (the final long name ends up in
2663 lowercase, although the short alias might be uppercase) UNLESS the
2664 long temp name is not 8.3.
2666 So, on Windows 95 we always rename through a temp name, and we make sure
2667 the temp name has a long extension to ensure correct renaming. */
2669 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2671 if (os_subtype
== OS_WIN95
)
2677 oldname
= map_w32_filename (oldname
, NULL
);
2678 if (o
= strrchr (oldname
, '\\'))
2681 o
= (char *) oldname
;
2683 if (p
= strrchr (temp
, '\\'))
2690 /* Force temp name to require a manufactured 8.3 alias - this
2691 seems to make the second rename work properly. */
2692 sprintf (p
, "_.%s.%u", o
, i
);
2694 result
= rename (oldname
, temp
);
2696 /* This loop must surely terminate! */
2697 while (result
< 0 && errno
== EEXIST
);
2702 /* Emulate Unix behavior - newname is deleted if it already exists
2703 (at least if it is a file; don't do this for directories).
2705 Since we mustn't do this if we are just changing the case of the
2706 file name (we would end up deleting the file we are trying to
2707 rename!), we let rename detect if the destination file already
2708 exists - that way we avoid the possible pitfalls of trying to
2709 determine ourselves whether two names really refer to the same
2710 file, which is not always possible in the general case. (Consider
2711 all the permutations of shared or subst'd drives, etc.) */
2713 newname
= map_w32_filename (newname
, NULL
);
2714 result
= rename (temp
, newname
);
2718 && _chmod (newname
, 0666) == 0
2719 && _unlink (newname
) == 0)
2720 result
= rename (temp
, newname
);
2726 sys_rmdir (const char * path
)
2728 return _rmdir (map_w32_filename (path
, NULL
));
2732 sys_unlink (const char * path
)
2734 path
= map_w32_filename (path
, NULL
);
2736 /* On Unix, unlink works without write permission. */
2737 _chmod (path
, 0666);
2738 return _unlink (path
);
2741 static FILETIME utc_base_ft
;
2742 static long double utc_base
;
2743 static int init
= 0;
2746 convert_time_raw (FILETIME ft
)
2749 (long double) ft
.dwHighDateTime
2750 * 4096.0L * 1024.0L * 1024.0L + ft
.dwLowDateTime
;
2754 convert_time (FILETIME ft
)
2760 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2769 st
.wMilliseconds
= 0;
2771 SystemTimeToFileTime (&st
, &utc_base_ft
);
2772 utc_base
= (long double) utc_base_ft
.dwHighDateTime
2773 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft
.dwLowDateTime
;
2777 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2780 return (time_t) ((convert_time_raw (ft
) - utc_base
) * 1e-7L);
2785 convert_from_time_t (time_t time
, FILETIME
* pft
)
2791 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2800 st
.wMilliseconds
= 0;
2802 SystemTimeToFileTime (&st
, &utc_base_ft
);
2803 utc_base
= (long double) utc_base_ft
.dwHighDateTime
2804 * 4096 * 1024 * 1024 + utc_base_ft
.dwLowDateTime
;
2808 /* time in 100ns units since 1-Jan-1601 */
2809 tmp
= (long double) time
* 1e7
+ utc_base
;
2810 pft
->dwHighDateTime
= (DWORD
) (tmp
/ (4096.0 * 1024 * 1024));
2811 pft
->dwLowDateTime
= (DWORD
) (tmp
- (4096.0 * 1024 * 1024) * pft
->dwHighDateTime
);
2815 /* No reason to keep this; faking inode values either by hashing or even
2816 using the file index from GetInformationByHandle, is not perfect and
2817 so by default Emacs doesn't use the inode values on Windows.
2818 Instead, we now determine file-truename correctly (except for
2819 possible drive aliasing etc). */
2821 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
2823 hashval (const unsigned char * str
)
2828 h
= (h
<< 4) + *str
++;
2834 /* Return the hash value of the canonical pathname, excluding the
2835 drive/UNC header, to get a hopefully unique inode number. */
2837 generate_inode_val (const char * name
)
2839 char fullname
[ MAX_PATH
];
2843 /* Get the truly canonical filename, if it exists. (Note: this
2844 doesn't resolve aliasing due to subst commands, or recognise hard
2846 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
2849 parse_root (fullname
, &p
);
2850 /* Normal W32 filesystems are still case insensitive. */
2857 static PSECURITY_DESCRIPTOR
2858 get_file_security_desc (const char *fname
)
2860 PSECURITY_DESCRIPTOR psd
= NULL
;
2862 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
2863 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
2865 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
2867 err
= GetLastError ();
2868 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
2872 psd
= xmalloc (sd_len
);
2873 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
2885 unsigned n_subauthorities
;
2887 /* Use the last sub-authority value of the RID, the relative
2888 portion of the SID, as user/group ID. */
2889 n_subauthorities
= *get_sid_sub_authority_count (sid
);
2890 if (n_subauthorities
< 1)
2891 return 0; /* the "World" RID */
2892 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
2895 /* Caching SID and account values for faster lokup. */
2898 # define FLEXIBLE_ARRAY_MEMBER
2900 # define FLEXIBLE_ARRAY_MEMBER 1
2905 struct w32_id
*next
;
2907 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
2910 static struct w32_id
*w32_idlist
;
2913 w32_cached_id (PSID sid
, int *id
, char *name
)
2915 struct w32_id
*tail
, *found
;
2917 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
2919 if (equal_sid ((PSID
)tail
->sid
, sid
))
2928 strcpy (name
, found
->name
);
2936 w32_add_to_cache (PSID sid
, int id
, char *name
)
2939 struct w32_id
*new_entry
;
2941 /* We don't want to leave behind stale cache from when Emacs was
2945 sid_len
= get_length_sid (sid
);
2946 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
2949 new_entry
->rid
= id
;
2950 strcpy (new_entry
->name
, name
);
2951 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
2952 new_entry
->next
= w32_idlist
;
2953 w32_idlist
= new_entry
;
2962 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
2963 int *id
, char *nm
, int what
)
2966 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
2968 SID_NAME_USE ignore
;
2970 DWORD name_len
= sizeof (name
);
2972 DWORD domain_len
= sizeof(domain
);
2978 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
2979 else if (what
== GID
)
2980 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
2984 if (!result
|| !is_valid_sid (sid
))
2986 else if (!w32_cached_id (sid
, id
, nm
))
2988 /* If FNAME is a UNC, we need to lookup account on the
2989 specified machine. */
2990 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
2991 && fname
[2] != '\0')
2996 for (s
= fname
+ 2, p
= machine
;
2997 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3003 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3004 domain
, &domain_len
, &ignore
)
3005 || name_len
> UNLEN
+1)
3009 *id
= get_rid (sid
);
3011 w32_add_to_cache (sid
, *id
, name
);
3018 get_file_owner_and_group (
3019 PSECURITY_DESCRIPTOR psd
,
3023 int dflt_usr
= 0, dflt_grp
= 0;
3032 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3034 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3037 /* Consider files to belong to current user/group, if we cannot get
3038 more accurate information. */
3041 st
->st_uid
= dflt_passwd
.pw_uid
;
3042 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3046 st
->st_gid
= dflt_passwd
.pw_gid
;
3047 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3051 /* MSVC stat function can't cope with UNC names and has other bugs, so
3052 replace it with our own. This also allows us to calculate consistent
3053 inode values without hacks in the main Emacs code. */
3055 stat (const char * path
, struct stat
* buf
)
3060 WIN32_FIND_DATA wfd
;
3062 unsigned __int64 fake_inode
;
3065 int rootdir
= FALSE
;
3066 PSECURITY_DESCRIPTOR psd
= NULL
;
3068 if (path
== NULL
|| buf
== NULL
)
3074 name
= (char *) map_w32_filename (path
, &path
);
3075 /* Must be valid filename, no wild cards or other invalid
3076 characters. We use _mbspbrk to support multibyte strings that
3077 might look to strpbrk as if they included literal *, ?, and other
3078 characters mentioned below that are disallowed by Windows
3080 if (_mbspbrk (name
, "*?|<>\""))
3086 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3087 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3088 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3093 /* Remove trailing directory separator, unless name is the root
3094 directory of a drive or UNC volume in which case ensure there
3095 is a trailing separator. */
3096 len
= strlen (name
);
3097 rootdir
= (path
>= name
+ len
- 1
3098 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3099 name
= strcpy (alloca (len
+ 2), name
);
3101 if (is_unc_volume (name
))
3103 DWORD attrs
= unc_volume_file_attributes (name
);
3108 memset (&wfd
, 0, sizeof (wfd
));
3109 wfd
.dwFileAttributes
= attrs
;
3110 wfd
.ftCreationTime
= utc_base_ft
;
3111 wfd
.ftLastAccessTime
= utc_base_ft
;
3112 wfd
.ftLastWriteTime
= utc_base_ft
;
3113 strcpy (wfd
.cFileName
, name
);
3117 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3118 strcat (name
, "\\");
3119 if (GetDriveType (name
) < 2)
3124 memset (&wfd
, 0, sizeof (wfd
));
3125 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3126 wfd
.ftCreationTime
= utc_base_ft
;
3127 wfd
.ftLastAccessTime
= utc_base_ft
;
3128 wfd
.ftLastWriteTime
= utc_base_ft
;
3129 strcpy (wfd
.cFileName
, name
);
3133 if (IS_DIRECTORY_SEP (name
[len
-1]))
3136 /* (This is hacky, but helps when doing file completions on
3137 network drives.) Optimize by using information available from
3138 active readdir if possible. */
3139 len
= strlen (dir_pathname
);
3140 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3142 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3143 && strnicmp (name
, dir_pathname
, len
) == 0
3144 && IS_DIRECTORY_SEP (name
[len
])
3145 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3147 /* This was the last entry returned by readdir. */
3148 wfd
= dir_find_data
;
3152 logon_network_drive (name
);
3154 fh
= FindFirstFile (name
, &wfd
);
3155 if (fh
== INVALID_HANDLE_VALUE
)
3164 /* GetDriveType needs the root directory of NAME's drive. */
3165 if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3166 devtype
= GetDriveType (NULL
); /* use root of current diectory */
3169 strncpy (drive_root
, name
, 3);
3170 drive_root
[3] = '\0';
3171 devtype
= GetDriveType (drive_root
);
3174 if (!(NILP (Vw32_get_true_file_attributes
)
3175 || (EQ (Vw32_get_true_file_attributes
, Qlocal
)
3176 && devtype
!= DRIVE_FIXED
&& devtype
!= DRIVE_RAMDISK
))
3177 /* No access rights required to get info. */
3178 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3179 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3180 != INVALID_HANDLE_VALUE
)
3182 /* This is more accurate in terms of gettting the correct number
3183 of links, but is quite slow (it is noticeable when Emacs is
3184 making a list of file name completions). */
3185 BY_HANDLE_FILE_INFORMATION info
;
3187 if (GetFileInformationByHandle (fh
, &info
))
3189 buf
->st_nlink
= info
.nNumberOfLinks
;
3190 /* Might as well use file index to fake inode values, but this
3191 is not guaranteed to be unique unless we keep a handle open
3192 all the time (even then there are situations where it is
3193 not unique). Reputedly, there are at most 48 bits of info
3194 (on NTFS, presumably less on FAT). */
3195 fake_inode
= info
.nFileIndexHigh
;
3197 fake_inode
+= info
.nFileIndexLow
;
3205 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3207 buf
->st_mode
= S_IFDIR
;
3211 switch (GetFileType (fh
))
3213 case FILE_TYPE_DISK
:
3214 buf
->st_mode
= S_IFREG
;
3216 case FILE_TYPE_PIPE
:
3217 buf
->st_mode
= S_IFIFO
;
3219 case FILE_TYPE_CHAR
:
3220 case FILE_TYPE_UNKNOWN
:
3222 buf
->st_mode
= S_IFCHR
;
3226 psd
= get_file_security_desc (name
);
3227 get_file_owner_and_group (psd
, name
, buf
);
3231 /* Don't bother to make this information more accurate. */
3232 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3237 get_file_owner_and_group (NULL
, name
, buf
);
3242 /* Not sure if there is any point in this. */
3243 if (!NILP (Vw32_generate_fake_inodes
))
3244 fake_inode
= generate_inode_val (name
);
3245 else if (fake_inode
== 0)
3247 /* For want of something better, try to make everything unique. */
3248 static DWORD gen_num
= 0;
3249 fake_inode
= ++gen_num
;
3253 /* MSVC defines _ino_t to be short; other libc's might not. */
3254 if (sizeof (buf
->st_ino
) == 2)
3255 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3257 buf
->st_ino
= fake_inode
;
3259 /* volume_info is set indirectly by map_w32_filename */
3260 buf
->st_dev
= volume_info
.serialnum
;
3261 buf
->st_rdev
= volume_info
.serialnum
;
3264 buf
->st_size
= wfd
.nFileSizeHigh
;
3265 buf
->st_size
<<= 32;
3266 buf
->st_size
+= wfd
.nFileSizeLow
;
3268 /* Convert timestamps to Unix format. */
3269 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3270 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3271 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3272 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3273 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3275 /* determine rwx permissions */
3276 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3277 permission
= S_IREAD
;
3279 permission
= S_IREAD
| S_IWRITE
;
3281 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3282 permission
|= S_IEXEC
;
3283 else if (is_exec (name
))
3284 permission
|= S_IEXEC
;
3286 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3291 /* Provide fstat and utime as well as stat for consistent handling of
3294 fstat (int desc
, struct stat
* buf
)
3296 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3297 BY_HANDLE_FILE_INFORMATION info
;
3298 unsigned __int64 fake_inode
;
3301 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3303 case FILE_TYPE_DISK
:
3304 buf
->st_mode
= S_IFREG
;
3305 if (!GetFileInformationByHandle (fh
, &info
))
3311 case FILE_TYPE_PIPE
:
3312 buf
->st_mode
= S_IFIFO
;
3314 case FILE_TYPE_CHAR
:
3315 case FILE_TYPE_UNKNOWN
:
3317 buf
->st_mode
= S_IFCHR
;
3319 memset (&info
, 0, sizeof (info
));
3320 info
.dwFileAttributes
= 0;
3321 info
.ftCreationTime
= utc_base_ft
;
3322 info
.ftLastAccessTime
= utc_base_ft
;
3323 info
.ftLastWriteTime
= utc_base_ft
;
3326 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3327 buf
->st_mode
= S_IFDIR
;
3329 buf
->st_nlink
= info
.nNumberOfLinks
;
3330 /* Might as well use file index to fake inode values, but this
3331 is not guaranteed to be unique unless we keep a handle open
3332 all the time (even then there are situations where it is
3333 not unique). Reputedly, there are at most 48 bits of info
3334 (on NTFS, presumably less on FAT). */
3335 fake_inode
= info
.nFileIndexHigh
;
3337 fake_inode
+= info
.nFileIndexLow
;
3339 /* MSVC defines _ino_t to be short; other libc's might not. */
3340 if (sizeof (buf
->st_ino
) == 2)
3341 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3343 buf
->st_ino
= fake_inode
;
3345 /* Consider files to belong to current user.
3346 FIXME: this should use GetSecurityInfo API, but it is only
3347 available for _WIN32_WINNT >= 0x501. */
3348 buf
->st_uid
= dflt_passwd
.pw_uid
;
3349 buf
->st_gid
= dflt_passwd
.pw_gid
;
3350 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3351 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3353 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3354 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3356 buf
->st_size
= info
.nFileSizeHigh
;
3357 buf
->st_size
<<= 32;
3358 buf
->st_size
+= info
.nFileSizeLow
;
3360 /* Convert timestamps to Unix format. */
3361 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3362 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3363 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3364 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3365 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3367 /* determine rwx permissions */
3368 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3369 permission
= S_IREAD
;
3371 permission
= S_IREAD
| S_IWRITE
;
3373 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3374 permission
|= S_IEXEC
;
3377 #if 0 /* no way of knowing the filename */
3378 char * p
= strrchr (name
, '.');
3380 (xstrcasecmp (p
, ".exe") == 0 ||
3381 xstrcasecmp (p
, ".com") == 0 ||
3382 xstrcasecmp (p
, ".bat") == 0 ||
3383 xstrcasecmp (p
, ".cmd") == 0))
3384 permission
|= S_IEXEC
;
3388 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3394 utime (const char *name
, struct utimbuf
*times
)
3396 struct utimbuf deftime
;
3403 deftime
.modtime
= deftime
.actime
= time (NULL
);
3407 /* Need write access to set times. */
3408 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3409 0, OPEN_EXISTING
, 0, NULL
);
3412 convert_from_time_t (times
->actime
, &atime
);
3413 convert_from_time_t (times
->modtime
, &mtime
);
3414 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3431 /* Support for browsing other processes and their attributes. See
3432 process.c for the Lisp bindings. */
3434 /* Helper wrapper functions. */
3436 HANDLE WINAPI
create_toolhelp32_snapshot(
3440 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3442 if (g_b_init_create_toolhelp32_snapshot
== 0)
3444 g_b_init_create_toolhelp32_snapshot
= 1;
3445 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3446 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3447 "CreateToolhelp32Snapshot");
3449 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3451 return INVALID_HANDLE_VALUE
;
3453 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3456 BOOL WINAPI
process32_first(
3458 LPPROCESSENTRY32 lppe
)
3460 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3462 if (g_b_init_process32_first
== 0)
3464 g_b_init_process32_first
= 1;
3465 s_pfn_Process32_First
= (Process32First_Proc
)
3466 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3469 if (s_pfn_Process32_First
== NULL
)
3473 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3476 BOOL WINAPI
process32_next(
3478 LPPROCESSENTRY32 lppe
)
3480 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3482 if (g_b_init_process32_next
== 0)
3484 g_b_init_process32_next
= 1;
3485 s_pfn_Process32_Next
= (Process32Next_Proc
)
3486 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3489 if (s_pfn_Process32_Next
== NULL
)
3493 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3496 BOOL WINAPI
open_thread_token (
3497 HANDLE ThreadHandle
,
3498 DWORD DesiredAccess
,
3500 PHANDLE TokenHandle
)
3502 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3503 HMODULE hm_advapi32
= NULL
;
3504 if (is_windows_9x () == TRUE
)
3506 SetLastError (ERROR_NOT_SUPPORTED
);
3509 if (g_b_init_open_thread_token
== 0)
3511 g_b_init_open_thread_token
= 1;
3512 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3513 s_pfn_Open_Thread_Token
=
3514 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3516 if (s_pfn_Open_Thread_Token
== NULL
)
3518 SetLastError (ERROR_NOT_SUPPORTED
);
3522 s_pfn_Open_Thread_Token (
3530 BOOL WINAPI
impersonate_self (
3531 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3533 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3534 HMODULE hm_advapi32
= NULL
;
3535 if (is_windows_9x () == TRUE
)
3539 if (g_b_init_impersonate_self
== 0)
3541 g_b_init_impersonate_self
= 1;
3542 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3543 s_pfn_Impersonate_Self
=
3544 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3546 if (s_pfn_Impersonate_Self
== NULL
)
3550 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3553 BOOL WINAPI
revert_to_self (void)
3555 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3556 HMODULE hm_advapi32
= NULL
;
3557 if (is_windows_9x () == TRUE
)
3561 if (g_b_init_revert_to_self
== 0)
3563 g_b_init_revert_to_self
= 1;
3564 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3565 s_pfn_Revert_To_Self
=
3566 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3568 if (s_pfn_Revert_To_Self
== NULL
)
3572 return s_pfn_Revert_To_Self ();
3575 BOOL WINAPI
get_process_memory_info (
3577 PPROCESS_MEMORY_COUNTERS mem_counters
,
3580 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3581 HMODULE hm_psapi
= NULL
;
3582 if (is_windows_9x () == TRUE
)
3586 if (g_b_init_get_process_memory_info
== 0)
3588 g_b_init_get_process_memory_info
= 1;
3589 hm_psapi
= LoadLibrary ("Psapi.dll");
3591 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3592 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3594 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3598 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3601 BOOL WINAPI
get_process_working_set_size (
3606 static GetProcessWorkingSetSize_Proc
3607 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3609 if (is_windows_9x () == TRUE
)
3613 if (g_b_init_get_process_working_set_size
== 0)
3615 g_b_init_get_process_working_set_size
= 1;
3616 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3617 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3618 "GetProcessWorkingSetSize");
3620 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3624 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3627 BOOL WINAPI
global_memory_status (
3630 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3632 if (is_windows_9x () == TRUE
)
3636 if (g_b_init_global_memory_status
== 0)
3638 g_b_init_global_memory_status
= 1;
3639 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3640 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3641 "GlobalMemoryStatus");
3643 if (s_pfn_Global_Memory_Status
== NULL
)
3647 return s_pfn_Global_Memory_Status (buf
);
3650 BOOL WINAPI
global_memory_status_ex (
3651 MEMORY_STATUS_EX
*buf
)
3653 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3655 if (is_windows_9x () == TRUE
)
3659 if (g_b_init_global_memory_status_ex
== 0)
3661 g_b_init_global_memory_status_ex
= 1;
3662 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3663 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3664 "GlobalMemoryStatusEx");
3666 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3670 return s_pfn_Global_Memory_Status_Ex (buf
);
3674 list_system_processes ()
3676 struct gcpro gcpro1
;
3677 Lisp_Object proclist
= Qnil
;
3680 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3682 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3684 PROCESSENTRY32 proc_entry
;
3690 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3691 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3692 res
= process32_next (h_snapshot
, &proc_entry
))
3694 proc_id
= proc_entry
.th32ProcessID
;
3695 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3698 CloseHandle (h_snapshot
);
3700 proclist
= Fnreverse (proclist
);
3707 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3709 TOKEN_PRIVILEGES priv
;
3710 DWORD priv_size
= sizeof (priv
);
3711 DWORD opriv_size
= sizeof (*old_priv
);
3712 HANDLE h_token
= NULL
;
3713 HANDLE h_thread
= GetCurrentThread ();
3717 res
= open_thread_token (h_thread
,
3718 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3720 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3722 if (impersonate_self (SecurityImpersonation
))
3723 res
= open_thread_token (h_thread
,
3724 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3729 priv
.PrivilegeCount
= 1;
3730 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3731 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3732 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3733 old_priv
, &opriv_size
)
3734 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3738 CloseHandle (h_token
);
3744 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3746 DWORD priv_size
= sizeof (*priv
);
3747 HANDLE h_token
= NULL
;
3750 if (open_thread_token (GetCurrentThread (),
3751 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3754 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3755 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3759 CloseHandle (h_token
);
3765 ltime (time_sec
, time_usec
)
3766 long time_sec
, time_usec
;
3768 return list3 (make_number ((time_sec
>> 16) & 0xffff),
3769 make_number (time_sec
& 0xffff),
3770 make_number (time_usec
));
3774 process_times (h_proc
, ctime
, etime
, stime
, utime
, pcpu
)
3776 Lisp_Object
*ctime
, *etime
, *stime
, *utime
;
3779 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
3780 long ctime_sec
, ctime_usec
, stime_sec
, stime_usec
, utime_sec
, utime_usec
;
3781 long etime_sec
, etime_usec
;
3782 long double tem1
, tem2
, tem
;
3785 || !get_process_times_fn
3786 || !(*get_process_times_fn
)(h_proc
, &ft_creation
, &ft_exit
,
3787 &ft_kernel
, &ft_user
))
3790 GetSystemTimeAsFileTime (&ft_current
);
3792 tem1
= convert_time_raw (ft_kernel
) * 0.1L;
3793 stime_usec
= fmodl (tem1
, 1000000.0L);
3794 stime_sec
= tem1
* 0.000001L;
3795 *stime
= ltime (stime_sec
, stime_usec
);
3796 tem2
= convert_time_raw (ft_user
) * 0.1L;
3797 utime_usec
= fmodl (tem2
, 1000000.0L);
3798 utime_sec
= tem2
* 0.000001L;
3799 *utime
= ltime (utime_sec
, utime_usec
);
3800 tem
= convert_time_raw (ft_creation
);
3801 /* Process no 4 (System) returns zero creation time. */
3803 tem
= (tem
- utc_base
) * 0.1;
3804 ctime_usec
= fmodl (tem
, 1000000.0L);
3805 ctime_sec
= tem
* 0.000001L;
3806 *ctime
= ltime (ctime_sec
, ctime_usec
);
3808 tem
= (convert_time_raw (ft_current
) - utc_base
) * 0.1L - tem
;
3809 etime_usec
= fmodl (tem
, 1000000.0L);
3810 etime_sec
= tem
* 0.000001L;
3811 *etime
= ltime (etime_sec
, etime_usec
);
3815 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
3826 system_process_attributes (pid
)
3829 struct gcpro gcpro1
, gcpro2
, gcpro3
;
3830 Lisp_Object attrs
= Qnil
;
3831 Lisp_Object cmd_str
, decoded_cmd
, tem
;
3832 HANDLE h_snapshot
, h_proc
;
3835 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
3836 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
3837 DWORD glength
= sizeof (gname
);
3838 HANDLE token
= NULL
;
3839 SID_NAME_USE user_type
;
3840 unsigned char *buf
= NULL
;
3842 TOKEN_USER user_token
;
3843 TOKEN_PRIMARY_GROUP group_token
;
3847 PROCESS_MEMORY_COUNTERS mem
;
3848 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
3849 DWORD minrss
, maxrss
;
3851 MEMORY_STATUS_EX memstex
;
3852 double totphys
= 0.0;
3853 Lisp_Object ctime
, stime
, utime
, etime
;
3855 BOOL result
= FALSE
;
3857 CHECK_NUMBER_OR_FLOAT (pid
);
3858 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
3860 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3862 GCPRO3 (attrs
, decoded_cmd
, tem
);
3864 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3869 pe
.dwSize
= sizeof (PROCESSENTRY32
);
3870 for (res
= process32_first (h_snapshot
, &pe
); res
;
3871 res
= process32_next (h_snapshot
, &pe
))
3873 if (proc_id
== pe
.th32ProcessID
)
3876 decoded_cmd
= build_string ("Idle");
3879 /* Decode the command name from locale-specific
3881 cmd_str
= make_unibyte_string (pe
.szExeFile
,
3882 strlen (pe
.szExeFile
));
3884 code_convert_string_norecord (cmd_str
,
3885 Vlocale_coding_system
, 0);
3887 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
3888 attrs
= Fcons (Fcons (Qppid
,
3889 make_fixnum_or_float (pe
.th32ParentProcessID
)),
3891 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
3893 attrs
= Fcons (Fcons (Qthcount
,
3894 make_fixnum_or_float (pe
.cntThreads
)),
3901 CloseHandle (h_snapshot
);
3910 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
3912 /* If we were denied a handle to the process, try again after
3913 enabling the SeDebugPrivilege in our process. */
3916 TOKEN_PRIVILEGES priv_current
;
3918 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
3920 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
3922 restore_privilege (&priv_current
);
3928 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
3931 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
3932 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
3934 buf
= xmalloc (blen
);
3935 result
= get_token_information (token
, TokenUser
,
3936 (LPVOID
)buf
, blen
, &needed
);
3939 memcpy (&user_token
, buf
, sizeof (user_token
));
3940 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
3942 euid
= get_rid (user_token
.User
.Sid
);
3943 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
3948 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
3951 strcpy (uname
, "unknown");
3955 ulength
= strlen (uname
);
3961 /* Determine a reasonable euid and gid values. */
3962 if (xstrcasecmp ("administrator", uname
) == 0)
3964 euid
= 500; /* well-known Administrator uid */
3965 egid
= 513; /* well-known None gid */
3969 /* Get group id and name. */
3970 result
= get_token_information (token
, TokenPrimaryGroup
,
3971 (LPVOID
)buf
, blen
, &needed
);
3972 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
3974 buf
= xrealloc (buf
, blen
= needed
);
3975 result
= get_token_information (token
, TokenPrimaryGroup
,
3976 (LPVOID
)buf
, blen
, &needed
);
3980 memcpy (&group_token
, buf
, sizeof (group_token
));
3981 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
3983 egid
= get_rid (group_token
.PrimaryGroup
);
3984 dlength
= sizeof (domain
);
3986 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
3987 gname
, &glength
, NULL
, &dlength
,
3990 w32_add_to_cache (group_token
.PrimaryGroup
,
3994 strcpy (gname
, "None");
3998 glength
= strlen (gname
);
4007 if (!is_windows_9x ())
4009 /* We couldn't open the process token, presumably because of
4010 insufficient access rights. Assume this process is run
4012 strcpy (uname
, "SYSTEM");
4013 strcpy (gname
, "None");
4014 euid
= 18; /* SYSTEM */
4015 egid
= 513; /* None */
4016 glength
= strlen (gname
);
4017 ulength
= strlen (uname
);
4019 /* If we are running under Windows 9X, where security calls are
4020 not supported, we assume all processes are run by the current
4022 else if (GetUserName (uname
, &ulength
))
4024 if (xstrcasecmp ("administrator", uname
) == 0)
4029 strcpy (gname
, "None");
4030 glength
= strlen (gname
);
4031 ulength
= strlen (uname
);
4037 strcpy (uname
, "administrator");
4038 ulength
= strlen (uname
);
4039 strcpy (gname
, "None");
4040 glength
= strlen (gname
);
4043 CloseHandle (token
);
4046 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4047 tem
= make_unibyte_string (uname
, ulength
);
4048 attrs
= Fcons (Fcons (Quser
,
4049 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4051 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4052 tem
= make_unibyte_string (gname
, glength
);
4053 attrs
= Fcons (Fcons (Qgroup
,
4054 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4057 if (global_memory_status_ex (&memstex
))
4058 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4059 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4061 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4062 double, so we need to do this for it... */
4064 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4065 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4066 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4068 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4070 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4071 else if (global_memory_status (&memst
))
4072 totphys
= memst
.dwTotalPhys
/ 1024.0;
4075 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4078 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4080 attrs
= Fcons (Fcons (Qmajflt
,
4081 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4083 attrs
= Fcons (Fcons (Qvsize
,
4084 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4086 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4088 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4091 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4093 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4095 attrs
= Fcons (Fcons (Qmajflt
,
4096 make_fixnum_or_float (mem
.PageFaultCount
)),
4098 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4100 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4103 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4105 DWORD rss
= maxrss
/ 1024;
4107 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4109 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4112 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &pcpu
))
4114 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4115 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4116 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4117 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4118 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4121 /* FIXME: Retrieve command line by walking the PEB of the process. */
4124 CloseHandle (h_proc
);
4132 /* Wrappers for winsock functions to map between our file descriptors
4133 and winsock's handles; also set h_errno for convenience.
4135 To allow Emacs to run on systems which don't have winsock support
4136 installed, we dynamically link to winsock on startup if present, and
4137 otherwise provide the minimum necessary functionality
4138 (eg. gethostname). */
4140 /* function pointers for relevant socket functions */
4141 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4142 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4143 int (PASCAL
*pfn_WSAGetLastError
) (void);
4144 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4145 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4146 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4147 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4148 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4149 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4150 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4151 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4152 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4153 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4154 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4155 int (PASCAL
*pfn_WSACleanup
) (void);
4157 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4158 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4159 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4160 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4161 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4162 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4163 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4164 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4165 const char * optval
, int optlen
);
4166 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4167 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4169 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4170 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4171 struct sockaddr
* from
, int * fromlen
);
4172 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4173 const struct sockaddr
* to
, int tolen
);
4175 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4176 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4177 #ifndef HANDLE_FLAG_INHERIT
4178 #define HANDLE_FLAG_INHERIT 1
4182 static int winsock_inuse
;
4187 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4189 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4190 after WSAStartup returns successfully, but it seems reasonable
4191 to allow unloading winsock anyway in that case. */
4192 if (pfn_WSACleanup () == 0 ||
4193 pfn_WSAGetLastError () == WSAENETDOWN
)
4195 if (FreeLibrary (winsock_lib
))
4204 init_winsock (int load_now
)
4206 WSADATA winsockData
;
4208 if (winsock_lib
!= NULL
)
4211 pfn_SetHandleInformation
= NULL
;
4212 pfn_SetHandleInformation
4213 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4214 "SetHandleInformation");
4216 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4218 if (winsock_lib
!= NULL
)
4220 /* dynamically link to socket functions */
4222 #define LOAD_PROC(fn) \
4223 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4226 LOAD_PROC( WSAStartup
);
4227 LOAD_PROC( WSASetLastError
);
4228 LOAD_PROC( WSAGetLastError
);
4229 LOAD_PROC( WSAEventSelect
);
4230 LOAD_PROC( WSACreateEvent
);
4231 LOAD_PROC( WSACloseEvent
);
4232 LOAD_PROC( socket
);
4234 LOAD_PROC( connect
);
4235 LOAD_PROC( ioctlsocket
);
4238 LOAD_PROC( closesocket
);
4239 LOAD_PROC( shutdown
);
4242 LOAD_PROC( inet_addr
);
4243 LOAD_PROC( gethostname
);
4244 LOAD_PROC( gethostbyname
);
4245 LOAD_PROC( getservbyname
);
4246 LOAD_PROC( getpeername
);
4247 LOAD_PROC( WSACleanup
);
4248 LOAD_PROC( setsockopt
);
4249 LOAD_PROC( listen
);
4250 LOAD_PROC( getsockname
);
4251 LOAD_PROC( accept
);
4252 LOAD_PROC( recvfrom
);
4253 LOAD_PROC( sendto
);
4256 /* specify version 1.1 of winsock */
4257 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4259 if (winsockData
.wVersion
!= 0x101)
4264 /* Report that winsock exists and is usable, but leave
4265 socket functions disabled. I am assuming that calling
4266 WSAStartup does not require any network interaction,
4267 and in particular does not cause or require a dial-up
4268 connection to be established. */
4271 FreeLibrary (winsock_lib
);
4279 FreeLibrary (winsock_lib
);
4289 /* function to set h_errno for compatibility; map winsock error codes to
4290 normal system codes where they overlap (non-overlapping definitions
4291 are already in <sys/socket.h> */
4295 if (winsock_lib
== NULL
)
4298 h_errno
= pfn_WSAGetLastError ();
4302 case WSAEACCES
: h_errno
= EACCES
; break;
4303 case WSAEBADF
: h_errno
= EBADF
; break;
4304 case WSAEFAULT
: h_errno
= EFAULT
; break;
4305 case WSAEINTR
: h_errno
= EINTR
; break;
4306 case WSAEINVAL
: h_errno
= EINVAL
; break;
4307 case WSAEMFILE
: h_errno
= EMFILE
; break;
4308 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4309 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4317 if (h_errno
== 0 && winsock_lib
!= NULL
)
4318 pfn_WSASetLastError (0);
4321 /* Extend strerror to handle the winsock-specific error codes. */
4325 } _wsa_errlist
[] = {
4326 WSAEINTR
, "Interrupted function call",
4327 WSAEBADF
, "Bad file descriptor",
4328 WSAEACCES
, "Permission denied",
4329 WSAEFAULT
, "Bad address",
4330 WSAEINVAL
, "Invalid argument",
4331 WSAEMFILE
, "Too many open files",
4333 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
4334 WSAEINPROGRESS
, "Operation now in progress",
4335 WSAEALREADY
, "Operation already in progress",
4336 WSAENOTSOCK
, "Socket operation on non-socket",
4337 WSAEDESTADDRREQ
, "Destination address required",
4338 WSAEMSGSIZE
, "Message too long",
4339 WSAEPROTOTYPE
, "Protocol wrong type for socket",
4340 WSAENOPROTOOPT
, "Bad protocol option",
4341 WSAEPROTONOSUPPORT
, "Protocol not supported",
4342 WSAESOCKTNOSUPPORT
, "Socket type not supported",
4343 WSAEOPNOTSUPP
, "Operation not supported",
4344 WSAEPFNOSUPPORT
, "Protocol family not supported",
4345 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
4346 WSAEADDRINUSE
, "Address already in use",
4347 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
4348 WSAENETDOWN
, "Network is down",
4349 WSAENETUNREACH
, "Network is unreachable",
4350 WSAENETRESET
, "Network dropped connection on reset",
4351 WSAECONNABORTED
, "Software caused connection abort",
4352 WSAECONNRESET
, "Connection reset by peer",
4353 WSAENOBUFS
, "No buffer space available",
4354 WSAEISCONN
, "Socket is already connected",
4355 WSAENOTCONN
, "Socket is not connected",
4356 WSAESHUTDOWN
, "Cannot send after socket shutdown",
4357 WSAETOOMANYREFS
, "Too many references", /* not sure */
4358 WSAETIMEDOUT
, "Connection timed out",
4359 WSAECONNREFUSED
, "Connection refused",
4360 WSAELOOP
, "Network loop", /* not sure */
4361 WSAENAMETOOLONG
, "Name is too long",
4362 WSAEHOSTDOWN
, "Host is down",
4363 WSAEHOSTUNREACH
, "No route to host",
4364 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
4365 WSAEPROCLIM
, "Too many processes",
4366 WSAEUSERS
, "Too many users", /* not sure */
4367 WSAEDQUOT
, "Double quote in host name", /* really not sure */
4368 WSAESTALE
, "Data is stale", /* not sure */
4369 WSAEREMOTE
, "Remote error", /* not sure */
4371 WSASYSNOTREADY
, "Network subsystem is unavailable",
4372 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
4373 WSANOTINITIALISED
, "Winsock not initialized successfully",
4374 WSAEDISCON
, "Graceful shutdown in progress",
4376 WSAENOMORE
, "No more operations allowed", /* not sure */
4377 WSAECANCELLED
, "Operation cancelled", /* not sure */
4378 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
4379 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
4380 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
4381 WSASYSCALLFAILURE
, "System call failure",
4382 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
4383 WSATYPE_NOT_FOUND
, "Class type not found",
4384 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
4385 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
4386 WSAEREFUSED
, "Operation refused", /* not sure */
4389 WSAHOST_NOT_FOUND
, "Host not found",
4390 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
4391 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
4392 WSANO_DATA
, "Valid name, no data record of requested type",
4398 sys_strerror(int error_no
)
4401 static char unknown_msg
[40];
4403 if (error_no
>= 0 && error_no
< sys_nerr
)
4404 return sys_errlist
[error_no
];
4406 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4407 if (_wsa_errlist
[i
].errnum
== error_no
)
4408 return _wsa_errlist
[i
].msg
;
4410 sprintf(unknown_msg
, "Unidentified error: %d", error_no
);
4414 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4415 but I believe the method of keeping the socket handle separate (and
4416 insuring it is not inheritable) is the correct one. */
4418 //#define SOCK_REPLACE_HANDLE
4420 #ifdef SOCK_REPLACE_HANDLE
4421 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
4423 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4426 int socket_to_fd (SOCKET s
);
4429 sys_socket(int af
, int type
, int protocol
)
4433 if (winsock_lib
== NULL
)
4436 return INVALID_SOCKET
;
4441 /* call the real socket function */
4442 s
= pfn_socket (af
, type
, protocol
);
4444 if (s
!= INVALID_SOCKET
)
4445 return socket_to_fd (s
);
4451 /* Convert a SOCKET to a file descriptor. */
4453 socket_to_fd (SOCKET s
)
4458 /* Although under NT 3.5 _open_osfhandle will accept a socket
4459 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4460 that does not work under NT 3.1. However, we can get the same
4461 effect by using a backdoor function to replace an existing
4462 descriptor handle with the one we want. */
4464 /* allocate a file descriptor (with appropriate flags) */
4465 fd
= _open ("NUL:", _O_RDWR
);
4468 #ifdef SOCK_REPLACE_HANDLE
4469 /* now replace handle to NUL with our socket handle */
4470 CloseHandle ((HANDLE
) _get_osfhandle (fd
));
4472 _set_osfhnd (fd
, s
);
4473 /* setmode (fd, _O_BINARY); */
4475 /* Make a non-inheritable copy of the socket handle. Note
4476 that it is possible that sockets aren't actually kernel
4477 handles, which appears to be the case on Windows 9x when
4478 the MS Proxy winsock client is installed. */
4480 /* Apparently there is a bug in NT 3.51 with some service
4481 packs, which prevents using DuplicateHandle to make a
4482 socket handle non-inheritable (causes WSACleanup to
4483 hang). The work-around is to use SetHandleInformation
4484 instead if it is available and implemented. */
4485 if (pfn_SetHandleInformation
)
4487 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4491 HANDLE parent
= GetCurrentProcess ();
4492 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4494 if (DuplicateHandle (parent
,
4500 DUPLICATE_SAME_ACCESS
))
4502 /* It is possible that DuplicateHandle succeeds even
4503 though the socket wasn't really a kernel handle,
4504 because a real handle has the same value. So
4505 test whether the new handle really is a socket. */
4506 long nonblocking
= 0;
4507 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4509 pfn_closesocket (s
);
4514 CloseHandle (new_s
);
4519 fd_info
[fd
].hnd
= (HANDLE
) s
;
4522 /* set our own internal flags */
4523 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4529 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4531 /* attach child_process to fd_info */
4532 if (fd_info
[ fd
].cp
!= NULL
)
4534 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4538 fd_info
[ fd
].cp
= cp
;
4541 winsock_inuse
++; /* count open sockets */
4548 pfn_closesocket (s
);
4555 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4557 if (winsock_lib
== NULL
)
4560 return SOCKET_ERROR
;
4564 if (fd_info
[s
].flags
& FILE_SOCKET
)
4566 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4567 if (rc
== SOCKET_ERROR
)
4572 return SOCKET_ERROR
;
4577 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4579 if (winsock_lib
== NULL
)
4582 return SOCKET_ERROR
;
4586 if (fd_info
[s
].flags
& FILE_SOCKET
)
4588 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4589 if (rc
== SOCKET_ERROR
)
4594 return SOCKET_ERROR
;
4598 sys_htons (u_short hostshort
)
4600 return (winsock_lib
!= NULL
) ?
4601 pfn_htons (hostshort
) : hostshort
;
4605 sys_ntohs (u_short netshort
)
4607 return (winsock_lib
!= NULL
) ?
4608 pfn_ntohs (netshort
) : netshort
;
4612 sys_inet_addr (const char * cp
)
4614 return (winsock_lib
!= NULL
) ?
4615 pfn_inet_addr (cp
) : INADDR_NONE
;
4619 sys_gethostname (char * name
, int namelen
)
4621 if (winsock_lib
!= NULL
)
4622 return pfn_gethostname (name
, namelen
);
4624 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4625 return !GetComputerName (name
, (DWORD
*)&namelen
);
4628 return SOCKET_ERROR
;
4632 sys_gethostbyname(const char * name
)
4634 struct hostent
* host
;
4636 if (winsock_lib
== NULL
)
4643 host
= pfn_gethostbyname (name
);
4650 sys_getservbyname(const char * name
, const char * proto
)
4652 struct servent
* serv
;
4654 if (winsock_lib
== NULL
)
4661 serv
= pfn_getservbyname (name
, proto
);
4668 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4670 if (winsock_lib
== NULL
)
4673 return SOCKET_ERROR
;
4677 if (fd_info
[s
].flags
& FILE_SOCKET
)
4679 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4680 if (rc
== SOCKET_ERROR
)
4685 return SOCKET_ERROR
;
4690 sys_shutdown (int s
, int how
)
4692 if (winsock_lib
== NULL
)
4695 return SOCKET_ERROR
;
4699 if (fd_info
[s
].flags
& FILE_SOCKET
)
4701 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4702 if (rc
== SOCKET_ERROR
)
4707 return SOCKET_ERROR
;
4711 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4713 if (winsock_lib
== NULL
)
4716 return SOCKET_ERROR
;
4720 if (fd_info
[s
].flags
& FILE_SOCKET
)
4722 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4723 (const char *)optval
, optlen
);
4724 if (rc
== SOCKET_ERROR
)
4729 return SOCKET_ERROR
;
4733 sys_listen (int s
, int backlog
)
4735 if (winsock_lib
== NULL
)
4738 return SOCKET_ERROR
;
4742 if (fd_info
[s
].flags
& FILE_SOCKET
)
4744 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4745 if (rc
== SOCKET_ERROR
)
4748 fd_info
[s
].flags
|= FILE_LISTEN
;
4752 return SOCKET_ERROR
;
4756 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4758 if (winsock_lib
== NULL
)
4761 return SOCKET_ERROR
;
4765 if (fd_info
[s
].flags
& FILE_SOCKET
)
4767 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4768 if (rc
== SOCKET_ERROR
)
4773 return SOCKET_ERROR
;
4777 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
4779 if (winsock_lib
== NULL
)
4786 if (fd_info
[s
].flags
& FILE_LISTEN
)
4788 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
4790 if (t
== INVALID_SOCKET
)
4793 fd
= socket_to_fd (t
);
4795 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4796 ResetEvent (fd_info
[s
].cp
->char_avail
);
4804 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
4805 struct sockaddr
* from
, int * fromlen
)
4807 if (winsock_lib
== NULL
)
4810 return SOCKET_ERROR
;
4814 if (fd_info
[s
].flags
& FILE_SOCKET
)
4816 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
4817 if (rc
== SOCKET_ERROR
)
4822 return SOCKET_ERROR
;
4826 sys_sendto (int s
, const char * buf
, int len
, int flags
,
4827 const struct sockaddr
* to
, int tolen
)
4829 if (winsock_lib
== NULL
)
4832 return SOCKET_ERROR
;
4836 if (fd_info
[s
].flags
& FILE_SOCKET
)
4838 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
4839 if (rc
== SOCKET_ERROR
)
4844 return SOCKET_ERROR
;
4847 /* Windows does not have an fcntl function. Provide an implementation
4848 solely for making sockets non-blocking. */
4850 fcntl (int s
, int cmd
, int options
)
4852 if (winsock_lib
== NULL
)
4859 if (fd_info
[s
].flags
& FILE_SOCKET
)
4861 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
4863 unsigned long nblock
= 1;
4864 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
4865 if (rc
== SOCKET_ERROR
)
4867 /* Keep track of the fact that we set this to non-blocking. */
4868 fd_info
[s
].flags
|= FILE_NDELAY
;
4874 return SOCKET_ERROR
;
4878 return SOCKET_ERROR
;
4881 #endif /* HAVE_SOCKETS */
4884 /* Shadow main io functions: we need to handle pipes and sockets more
4885 intelligently, and implement non-blocking mode as well. */
4898 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
4900 child_process
* cp
= fd_info
[fd
].cp
;
4902 fd_info
[fd
].cp
= NULL
;
4904 if (CHILD_ACTIVE (cp
))
4906 /* if last descriptor to active child_process then cleanup */
4908 for (i
= 0; i
< MAXDESC
; i
++)
4912 if (fd_info
[i
].cp
== cp
)
4918 if (fd_info
[fd
].flags
& FILE_SOCKET
)
4920 #ifndef SOCK_REPLACE_HANDLE
4921 if (winsock_lib
== NULL
) abort ();
4923 pfn_shutdown (SOCK_HANDLE (fd
), 2);
4924 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
4926 winsock_inuse
--; /* count open sockets */
4934 /* Note that sockets do not need special treatment here (at least on
4935 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
4936 closesocket is equivalent to CloseHandle, which is to be expected
4937 because socket handles are fully fledged kernel handles. */
4940 if (rc
== 0 && fd
< MAXDESC
)
4941 fd_info
[fd
].flags
= 0;
4952 if (new_fd
>= 0 && new_fd
< MAXDESC
)
4954 /* duplicate our internal info as well */
4955 fd_info
[new_fd
] = fd_info
[fd
];
4962 sys_dup2 (int src
, int dst
)
4966 if (dst
< 0 || dst
>= MAXDESC
)
4972 /* make sure we close the destination first if it's a pipe or socket */
4973 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
4976 rc
= _dup2 (src
, dst
);
4979 /* duplicate our internal info as well */
4980 fd_info
[dst
] = fd_info
[src
];
4985 /* Unix pipe() has only one arg */
4987 sys_pipe (int * phandles
)
4992 /* make pipe handles non-inheritable; when we spawn a child, we
4993 replace the relevant handle with an inheritable one. Also put
4994 pipes into binary mode; we will do text mode translation ourselves
4996 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5000 /* Protect against overflow, since Windows can open more handles than
5001 our fd_info array has room for. */
5002 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5004 _close (phandles
[0]);
5005 _close (phandles
[1]);
5010 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5011 fd_info
[phandles
[0]].flags
= flags
;
5013 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5014 fd_info
[phandles
[1]].flags
= flags
;
5022 extern int w32_pipe_read_delay
;
5024 /* Function to do blocking read of one byte, needed to implement
5025 select. It is only allowed on sockets and pipes. */
5027 _sys_read_ahead (int fd
)
5032 if (fd
< 0 || fd
>= MAXDESC
)
5033 return STATUS_READ_ERROR
;
5035 cp
= fd_info
[fd
].cp
;
5037 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5038 return STATUS_READ_ERROR
;
5040 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5041 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5043 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5047 cp
->status
= STATUS_READ_IN_PROGRESS
;
5049 if (fd_info
[fd
].flags
& FILE_PIPE
)
5051 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5053 /* Give subprocess time to buffer some more output for us before
5054 reporting that input is available; we need this because Windows 95
5055 connects DOS programs to pipes by making the pipe appear to be
5056 the normal console stdout - as a result most DOS programs will
5057 write to stdout without buffering, ie. one character at a
5058 time. Even some W32 programs do this - "dir" in a command
5059 shell on NT is very slow if we don't do this. */
5062 int wait
= w32_pipe_read_delay
;
5068 /* Yield remainder of our time slice, effectively giving a
5069 temporary priority boost to the child process. */
5073 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5075 HANDLE hnd
= fd_info
[fd
].hnd
;
5076 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5079 /* Configure timeouts for blocking read. */
5080 if (!GetCommTimeouts (hnd
, &ct
))
5081 return STATUS_READ_ERROR
;
5082 ct
.ReadIntervalTimeout
= 0;
5083 ct
.ReadTotalTimeoutMultiplier
= 0;
5084 ct
.ReadTotalTimeoutConstant
= 0;
5085 if (!SetCommTimeouts (hnd
, &ct
))
5086 return STATUS_READ_ERROR
;
5088 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5090 if (GetLastError () != ERROR_IO_PENDING
)
5091 return STATUS_READ_ERROR
;
5092 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5093 return STATUS_READ_ERROR
;
5097 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5099 unsigned long nblock
= 0;
5100 /* We always want this to block, so temporarily disable NDELAY. */
5101 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5102 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5104 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5106 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5109 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5114 if (rc
== sizeof (char))
5115 cp
->status
= STATUS_READ_SUCCEEDED
;
5117 cp
->status
= STATUS_READ_FAILED
;
5123 _sys_wait_accept (int fd
)
5129 if (fd
< 0 || fd
>= MAXDESC
)
5130 return STATUS_READ_ERROR
;
5132 cp
= fd_info
[fd
].cp
;
5134 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5135 return STATUS_READ_ERROR
;
5137 cp
->status
= STATUS_READ_FAILED
;
5139 hEv
= pfn_WSACreateEvent ();
5140 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5141 if (rc
!= SOCKET_ERROR
)
5143 rc
= WaitForSingleObject (hEv
, INFINITE
);
5144 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5145 if (rc
== WAIT_OBJECT_0
)
5146 cp
->status
= STATUS_READ_SUCCEEDED
;
5148 pfn_WSACloseEvent (hEv
);
5154 sys_read (int fd
, char * buffer
, unsigned int count
)
5159 char * orig_buffer
= buffer
;
5167 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5169 child_process
*cp
= fd_info
[fd
].cp
;
5171 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5179 /* re-read CR carried over from last read */
5180 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5182 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5186 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5189 /* presence of a child_process structure means we are operating in
5190 non-blocking mode - otherwise we just call _read directly.
5191 Note that the child_process structure might be missing because
5192 reap_subprocess has been called; in this case the pipe is
5193 already broken, so calling _read on it is okay. */
5196 int current_status
= cp
->status
;
5198 switch (current_status
)
5200 case STATUS_READ_FAILED
:
5201 case STATUS_READ_ERROR
:
5202 /* report normal EOF if nothing in buffer */
5204 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5207 case STATUS_READ_READY
:
5208 case STATUS_READ_IN_PROGRESS
:
5209 DebPrint (("sys_read called when read is in progress\n"));
5210 errno
= EWOULDBLOCK
;
5213 case STATUS_READ_SUCCEEDED
:
5214 /* consume read-ahead char */
5215 *buffer
++ = cp
->chr
;
5218 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5219 ResetEvent (cp
->char_avail
);
5221 case STATUS_READ_ACKNOWLEDGED
:
5225 DebPrint (("sys_read: bad status %d\n", current_status
));
5230 if (fd_info
[fd
].flags
& FILE_PIPE
)
5232 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5233 to_read
= min (waiting
, (DWORD
) count
);
5236 nchars
+= _read (fd
, buffer
, to_read
);
5238 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5240 HANDLE hnd
= fd_info
[fd
].hnd
;
5241 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5248 /* Configure timeouts for non-blocking read. */
5249 if (!GetCommTimeouts (hnd
, &ct
))
5254 ct
.ReadIntervalTimeout
= MAXDWORD
;
5255 ct
.ReadTotalTimeoutMultiplier
= 0;
5256 ct
.ReadTotalTimeoutConstant
= 0;
5257 if (!SetCommTimeouts (hnd
, &ct
))
5263 if (!ResetEvent (ovl
->hEvent
))
5268 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5270 if (GetLastError () != ERROR_IO_PENDING
)
5275 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5285 else /* FILE_SOCKET */
5287 if (winsock_lib
== NULL
) abort ();
5289 /* do the equivalent of a non-blocking read */
5290 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5291 if (waiting
== 0 && nchars
== 0)
5293 h_errno
= errno
= EWOULDBLOCK
;
5299 /* always use binary mode for sockets */
5300 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5301 if (res
== SOCKET_ERROR
)
5303 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
5304 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5315 int nread
= _read (fd
, buffer
, count
);
5318 else if (nchars
== 0)
5323 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5324 /* Perform text mode translation if required. */
5325 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5327 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5328 /* If buffer contains only CR, return that. To be absolutely
5329 sure we should attempt to read the next char, but in
5330 practice a CR to be followed by LF would not appear by
5331 itself in the buffer. */
5332 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5334 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5340 nchars
= _read (fd
, buffer
, count
);
5345 /* From w32xfns.c */
5346 extern HANDLE interrupt_handle
;
5348 /* For now, don't bother with a non-blocking mode */
5350 sys_write (int fd
, const void * buffer
, unsigned int count
)
5360 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5362 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5368 /* Perform text mode translation if required. */
5369 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5371 char * tmpbuf
= alloca (count
* 2);
5372 unsigned char * src
= (void *)buffer
;
5373 unsigned char * dst
= tmpbuf
;
5378 unsigned char *next
;
5379 /* copy next line or remaining bytes */
5380 next
= _memccpy (dst
, src
, '\n', nbytes
);
5383 /* copied one line ending with '\n' */
5384 int copied
= next
- dst
;
5387 /* insert '\r' before '\n' */
5394 /* copied remaining partial line -> now finished */
5401 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5403 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5404 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5405 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5408 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5410 if (GetLastError () != ERROR_IO_PENDING
)
5415 if (detect_input_pending ())
5416 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5419 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5420 if (active
== WAIT_OBJECT_0
)
5421 { /* User pressed C-g, cancel write, then leave. Don't bother
5422 cleaning up as we may only get stuck in buggy drivers. */
5423 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5428 if (active
== WAIT_OBJECT_0
+ 1
5429 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5438 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5440 unsigned long nblock
= 0;
5441 if (winsock_lib
== NULL
) abort ();
5443 /* TODO: implement select() properly so non-blocking I/O works. */
5444 /* For now, make sure the write blocks. */
5445 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5446 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5448 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5450 /* Set the socket back to non-blocking if it was before,
5451 for other operations that support it. */
5452 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5455 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5458 if (nchars
== SOCKET_ERROR
)
5460 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
5461 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5467 nchars
= _write (fd
, buffer
, count
);
5473 check_windows_init_file ()
5475 extern int noninteractive
, inhibit_window_system
;
5477 /* A common indication that Emacs is not installed properly is when
5478 it cannot find the Windows installation file. If this file does
5479 not exist in the expected place, tell the user. */
5481 if (!noninteractive
&& !inhibit_window_system
)
5483 extern Lisp_Object Vwindow_system
, Vload_path
, Qfile_exists_p
;
5484 Lisp_Object objs
[2];
5485 Lisp_Object full_load_path
;
5486 Lisp_Object init_file
;
5489 objs
[0] = Vload_path
;
5490 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5491 full_load_path
= Fappend (2, objs
);
5492 init_file
= build_string ("term/w32-win");
5493 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5496 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5497 char *init_file_name
= SDATA (init_file
);
5498 char *load_path
= SDATA (load_path_print
);
5499 char *buffer
= alloca (1024
5500 + strlen (init_file_name
)
5501 + strlen (load_path
));
5504 "The Emacs Windows initialization file \"%s.el\" "
5505 "could not be found in your Emacs installation. "
5506 "Emacs checked the following directories for this file:\n"
5508 "When Emacs cannot find this file, it usually means that it "
5509 "was not installed properly, or its distribution file was "
5510 "not unpacked properly.\nSee the README.W32 file in the "
5511 "top-level Emacs directory for more information.",
5512 init_file_name
, load_path
);
5515 "Emacs Abort Dialog",
5516 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5517 /* Use the low-level Emacs abort. */
5532 /* shutdown the socket interface if necessary */
5543 /* Initialise the socket interface now if available and requested by
5544 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5545 delayed until open-network-stream is called (w32-has-winsock can
5546 also be used to dynamically load or reload winsock).
5548 Conveniently, init_environment is called before us, so
5549 PRELOAD_WINSOCK can be set in the registry. */
5551 /* Always initialize this correctly. */
5554 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5555 init_winsock (TRUE
);
5558 /* Initial preparation for subprocess support: replace our standard
5559 handles with non-inheritable versions. */
5562 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5563 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5564 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5566 parent
= GetCurrentProcess ();
5568 /* ignore errors when duplicating and closing; typically the
5569 handles will be invalid when running as a gui program. */
5570 DuplicateHandle (parent
,
5571 GetStdHandle (STD_INPUT_HANDLE
),
5576 DUPLICATE_SAME_ACCESS
);
5578 DuplicateHandle (parent
,
5579 GetStdHandle (STD_OUTPUT_HANDLE
),
5584 DUPLICATE_SAME_ACCESS
);
5586 DuplicateHandle (parent
,
5587 GetStdHandle (STD_ERROR_HANDLE
),
5592 DUPLICATE_SAME_ACCESS
);
5598 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5599 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5601 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5604 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5605 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5607 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5610 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5611 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5613 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5617 /* unfortunately, atexit depends on implementation of malloc */
5618 /* atexit (term_ntproc); */
5619 signal (SIGABRT
, term_ntproc
);
5621 /* determine which drives are fixed, for GetCachedVolumeInformation */
5623 /* GetDriveType must have trailing backslash. */
5624 char drive
[] = "A:\\";
5626 /* Loop over all possible drive letters */
5627 while (*drive
<= 'Z')
5629 /* Record if this drive letter refers to a fixed drive. */
5630 fixed_drives
[DRIVE_INDEX (*drive
)] =
5631 (GetDriveType (drive
) == DRIVE_FIXED
);
5636 /* Reset the volume info cache. */
5637 volume_cache
= NULL
;
5640 /* Check to see if Emacs has been installed correctly. */
5641 check_windows_init_file ();
5645 shutdown_handler ensures that buffers' autosave files are
5646 up to date when the user logs off, or the system shuts down.
5648 BOOL WINAPI
shutdown_handler(DWORD type
)
5650 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5651 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5652 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5653 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5655 /* Shut down cleanly, making sure autosave files are up to date. */
5656 shut_down_emacs (0, 0, Qnil
);
5659 /* Allow other handlers to handle this signal. */
5664 globals_of_w32 is used to initialize those global variables that
5665 must always be initialized on startup even when the global variable
5666 initialized is non zero (see the function main in emacs.c).
5671 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5673 get_process_times_fn
= (GetProcessTimes_Proc
)
5674 GetProcAddress (kernel32
, "GetProcessTimes");
5676 g_b_init_is_windows_9x
= 0;
5677 g_b_init_open_process_token
= 0;
5678 g_b_init_get_token_information
= 0;
5679 g_b_init_lookup_account_sid
= 0;
5680 g_b_init_get_sid_identifier_authority
= 0;
5681 g_b_init_get_sid_sub_authority
= 0;
5682 g_b_init_get_sid_sub_authority_count
= 0;
5683 g_b_init_get_file_security
= 0;
5684 g_b_init_get_security_descriptor_owner
= 0;
5685 g_b_init_get_security_descriptor_group
= 0;
5686 g_b_init_is_valid_sid
= 0;
5687 g_b_init_create_toolhelp32_snapshot
= 0;
5688 g_b_init_process32_first
= 0;
5689 g_b_init_process32_next
= 0;
5690 g_b_init_open_thread_token
= 0;
5691 g_b_init_impersonate_self
= 0;
5692 g_b_init_revert_to_self
= 0;
5693 g_b_init_get_process_memory_info
= 0;
5694 g_b_init_get_process_working_set_size
= 0;
5695 g_b_init_global_memory_status
= 0;
5696 g_b_init_global_memory_status_ex
= 0;
5697 g_b_init_equal_sid
= 0;
5698 g_b_init_copy_sid
= 0;
5699 g_b_init_get_length_sid
= 0;
5700 /* The following sets a handler for shutdown notifications for
5701 console apps. This actually applies to Emacs in both console and
5702 GUI modes, since we had to fool windows into thinking emacs is a
5703 console application to get console mode to work. */
5704 SetConsoleCtrlHandler(shutdown_handler
, TRUE
);
5706 /* "None" is the default group name on standalone workstations. */
5707 strcpy (dflt_group_name
, "None");
5710 /* For make-serial-process */
5711 int serial_open (char *port
)
5717 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5718 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5719 if (hnd
== INVALID_HANDLE_VALUE
)
5720 error ("Could not open %s", port
);
5721 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5723 error ("Could not open %s", port
);
5727 error ("Could not create child process");
5729 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5730 fd_info
[ fd
].hnd
= hnd
;
5731 fd_info
[ fd
].flags
|=
5732 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5733 if (fd_info
[ fd
].cp
!= NULL
)
5735 error ("fd_info[fd = %d] is already in use", fd
);
5737 fd_info
[ fd
].cp
= cp
;
5738 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5739 if (cp
->ovl_read
.hEvent
== NULL
)
5740 error ("Could not create read event");
5741 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5742 if (cp
->ovl_write
.hEvent
== NULL
)
5743 error ("Could not create write event");
5748 /* For serial-process-configure */
5750 serial_configure (struct Lisp_Process
*p
,
5751 Lisp_Object contact
)
5753 Lisp_Object childp2
= Qnil
;
5754 Lisp_Object tem
= Qnil
;
5758 char summary
[4] = "???"; /* This usually becomes "8N1". */
5760 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
5761 error ("Not a serial process");
5762 hnd
= fd_info
[ p
->outfd
].hnd
;
5764 childp2
= Fcopy_sequence (p
->childp
);
5766 /* Initialize timeouts for blocking read and blocking write. */
5767 if (!GetCommTimeouts (hnd
, &ct
))
5768 error ("GetCommTimeouts() failed");
5769 ct
.ReadIntervalTimeout
= 0;
5770 ct
.ReadTotalTimeoutMultiplier
= 0;
5771 ct
.ReadTotalTimeoutConstant
= 0;
5772 ct
.WriteTotalTimeoutMultiplier
= 0;
5773 ct
.WriteTotalTimeoutConstant
= 0;
5774 if (!SetCommTimeouts (hnd
, &ct
))
5775 error ("SetCommTimeouts() failed");
5776 /* Read port attributes and prepare default configuration. */
5777 memset (&dcb
, 0, sizeof (dcb
));
5778 dcb
.DCBlength
= sizeof (DCB
);
5779 if (!GetCommState (hnd
, &dcb
))
5780 error ("GetCommState() failed");
5783 dcb
.fAbortOnError
= FALSE
;
5784 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
5789 /* Configure speed. */
5790 if (!NILP (Fplist_member (contact
, QCspeed
)))
5791 tem
= Fplist_get (contact
, QCspeed
);
5793 tem
= Fplist_get (p
->childp
, QCspeed
);
5795 dcb
.BaudRate
= XINT (tem
);
5796 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
5798 /* Configure bytesize. */
5799 if (!NILP (Fplist_member (contact
, QCbytesize
)))
5800 tem
= Fplist_get (contact
, QCbytesize
);
5802 tem
= Fplist_get (p
->childp
, QCbytesize
);
5804 tem
= make_number (8);
5806 if (XINT (tem
) != 7 && XINT (tem
) != 8)
5807 error (":bytesize must be nil (8), 7, or 8");
5808 dcb
.ByteSize
= XINT (tem
);
5809 summary
[0] = XINT (tem
) + '0';
5810 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
5812 /* Configure parity. */
5813 if (!NILP (Fplist_member (contact
, QCparity
)))
5814 tem
= Fplist_get (contact
, QCparity
);
5816 tem
= Fplist_get (p
->childp
, QCparity
);
5817 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
5818 error (":parity must be nil (no parity), `even', or `odd'");
5819 dcb
.fParity
= FALSE
;
5820 dcb
.Parity
= NOPARITY
;
5821 dcb
.fErrorChar
= FALSE
;
5826 else if (EQ (tem
, Qeven
))
5830 dcb
.Parity
= EVENPARITY
;
5831 dcb
.fErrorChar
= TRUE
;
5833 else if (EQ (tem
, Qodd
))
5837 dcb
.Parity
= ODDPARITY
;
5838 dcb
.fErrorChar
= TRUE
;
5840 childp2
= Fplist_put (childp2
, QCparity
, tem
);
5842 /* Configure stopbits. */
5843 if (!NILP (Fplist_member (contact
, QCstopbits
)))
5844 tem
= Fplist_get (contact
, QCstopbits
);
5846 tem
= Fplist_get (p
->childp
, QCstopbits
);
5848 tem
= make_number (1);
5850 if (XINT (tem
) != 1 && XINT (tem
) != 2)
5851 error (":stopbits must be nil (1 stopbit), 1, or 2");
5852 summary
[2] = XINT (tem
) + '0';
5853 if (XINT (tem
) == 1)
5854 dcb
.StopBits
= ONESTOPBIT
;
5855 else if (XINT (tem
) == 2)
5856 dcb
.StopBits
= TWOSTOPBITS
;
5857 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
5859 /* Configure flowcontrol. */
5860 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
5861 tem
= Fplist_get (contact
, QCflowcontrol
);
5863 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
5864 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
5865 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
5866 dcb
.fOutxCtsFlow
= FALSE
;
5867 dcb
.fOutxDsrFlow
= FALSE
;
5868 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
5869 dcb
.fDsrSensitivity
= FALSE
;
5870 dcb
.fTXContinueOnXoff
= FALSE
;
5873 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
5874 dcb
.XonChar
= 17; /* Control-Q */
5875 dcb
.XoffChar
= 19; /* Control-S */
5878 /* Already configured. */
5880 else if (EQ (tem
, Qhw
))
5882 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
5883 dcb
.fOutxCtsFlow
= TRUE
;
5885 else if (EQ (tem
, Qsw
))
5890 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
5892 /* Activate configuration. */
5893 if (!SetCommState (hnd
, &dcb
))
5894 error ("SetCommState() failed");
5896 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
5897 p
->childp
= childp2
;
5902 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
5903 (do not change this comment) */