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 /* This is guarded by a higher value of _WIN32_WINNT than what we use. */
77 typedef struct _MEMORYSTATUSEX
{
80 DWORDLONG ullTotalPhys
;
81 DWORDLONG ullAvailPhys
;
82 DWORDLONG ullTotalPageFile
;
83 DWORDLONG ullAvailPageFile
;
84 DWORDLONG ullTotalVirtual
;
85 DWORDLONG ullAvailVirtual
;
86 DWORDLONG ullAvailExtendedVirtual
;
87 } MEMORYSTATUSEX
,*LPMEMORYSTATUSEX
;
94 /* This either is not in psapi.h or guarded by higher value of
95 _WIN32_WINNT than what we use. */
96 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
99 DWORD PeakWorkingSetSize
;
100 DWORD WorkingSetSize
;
101 DWORD QuotaPeakPagedPoolUsage
;
102 DWORD QuotaPagedPoolUsage
;
103 DWORD QuotaPeakNonPagedPoolUsage
;
104 DWORD QuotaNonPagedPoolUsage
;
106 DWORD PeakPagefileUsage
;
108 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
110 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
111 #include <sys/socket.h>
135 #include "dispextern.h" /* for xstrcasecmp */
136 #include "coding.h" /* for Vlocale_coding_system */
138 /* For serial_configure and serial_open. */
141 extern Lisp_Object QCport
, QCspeed
, QCprocess
;
142 extern Lisp_Object QCbytesize
, QCstopbits
, QCparity
, Qodd
, Qeven
;
143 extern Lisp_Object QCflowcontrol
, Qhw
, Qsw
, QCsummary
;
145 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
146 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
148 void globals_of_w32 ();
149 static DWORD
get_rid (PSID
);
151 extern Lisp_Object Vw32_downcase_file_names
;
152 extern Lisp_Object Vw32_generate_fake_inodes
;
153 extern Lisp_Object Vw32_get_true_file_attributes
;
154 /* Defined in process.c for its own purpose. */
155 extern Lisp_Object Qlocal
;
157 extern int w32_num_mouse_buttons
;
160 /* Initialization states.
162 WARNING: If you add any more such variables for additional APIs,
163 you MUST add initialization for them to globals_of_w32
164 below. This is because these variables might get set
165 to non-NULL values during dumping, but the dumped Emacs
166 cannot reuse those values, because it could be run on a
167 different version of the OS, where API addresses are
169 static BOOL g_b_init_is_windows_9x
;
170 static BOOL g_b_init_open_process_token
;
171 static BOOL g_b_init_get_token_information
;
172 static BOOL g_b_init_lookup_account_sid
;
173 static BOOL g_b_init_get_sid_identifier_authority
;
174 static BOOL g_b_init_get_sid_sub_authority
;
175 static BOOL g_b_init_get_sid_sub_authority_count
;
176 static BOOL g_b_init_get_file_security
;
177 static BOOL g_b_init_get_security_descriptor_owner
;
178 static BOOL g_b_init_get_security_descriptor_group
;
179 static BOOL g_b_init_is_valid_sid
;
180 static BOOL g_b_init_create_toolhelp32_snapshot
;
181 static BOOL g_b_init_process32_first
;
182 static BOOL g_b_init_process32_next
;
183 static BOOL g_b_init_open_thread_token
;
184 static BOOL g_b_init_impersonate_self
;
185 static BOOL g_b_init_revert_to_self
;
186 static BOOL g_b_init_get_process_memory_info
;
187 static BOOL g_b_init_get_process_working_set_size
;
188 static BOOL g_b_init_global_memory_status
;
189 static BOOL g_b_init_global_memory_status_ex
;
192 BEGIN: Wrapper functions around OpenProcessToken
193 and other functions in advapi32.dll that are only
194 supported in Windows NT / 2k / XP
196 /* ** Function pointer typedefs ** */
197 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
198 HANDLE ProcessHandle
,
200 PHANDLE TokenHandle
);
201 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
203 TOKEN_INFORMATION_CLASS TokenInformationClass
,
204 LPVOID TokenInformation
,
205 DWORD TokenInformationLength
,
206 PDWORD ReturnLength
);
207 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
208 HANDLE process_handle
,
209 LPFILETIME creation_time
,
210 LPFILETIME exit_time
,
211 LPFILETIME kernel_time
,
212 LPFILETIME user_time
);
214 GetProcessTimes_Proc get_process_times_fn
= NULL
;
217 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
218 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
220 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
221 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
223 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
224 LPCTSTR lpSystemName
,
229 LPDWORD cbDomainName
,
230 PSID_NAME_USE peUse
);
231 typedef PSID_IDENTIFIER_AUTHORITY (WINAPI
* GetSidIdentifierAuthority_Proc
) (
233 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
236 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
238 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
240 SECURITY_INFORMATION RequestedInformation
,
241 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
243 LPDWORD lpnLengthNeeded
);
244 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
245 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
247 LPBOOL lpbOwnerDefaulted
);
248 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
249 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
251 LPBOOL lpbGroupDefaulted
);
252 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
254 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
256 DWORD th32ProcessID
);
257 typedef BOOL (WINAPI
* Process32First_Proc
) (
259 LPPROCESSENTRY32 lppe
);
260 typedef BOOL (WINAPI
* Process32Next_Proc
) (
262 LPPROCESSENTRY32 lppe
);
263 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
267 PHANDLE TokenHandle
);
268 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
269 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
270 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
271 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
273 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
275 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
277 DWORD
* lpMinimumWorkingSetSize
,
278 DWORD
* lpMaximumWorkingSetSize
);
279 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
280 LPMEMORYSTATUS lpBuffer
);
281 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
282 LPMEMORYSTATUSEX lpBuffer
);
284 /* ** A utility function ** */
288 static BOOL s_b_ret
=0;
289 OSVERSIONINFO os_ver
;
290 if (g_b_init_is_windows_9x
== 0)
292 g_b_init_is_windows_9x
= 1;
293 ZeroMemory(&os_ver
, sizeof(OSVERSIONINFO
));
294 os_ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
295 if (GetVersionEx (&os_ver
))
297 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
303 /* Get total user and system times for get-internal-run-time.
304 Returns a list of three integers if the times are provided by the OS
305 (NT derivatives), otherwise it returns the result of current-time. */
307 w32_get_internal_run_time ()
309 if (get_process_times_fn
)
311 FILETIME create
, exit
, kernel
, user
;
312 HANDLE proc
= GetCurrentProcess();
313 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
315 LARGE_INTEGER user_int
, kernel_int
, total
;
317 user_int
.LowPart
= user
.dwLowDateTime
;
318 user_int
.HighPart
= user
.dwHighDateTime
;
319 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
320 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
321 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
322 /* FILETIME is 100 nanosecond increments, Emacs only wants
323 microsecond resolution. */
324 total
.QuadPart
/= 10;
325 microseconds
= total
.QuadPart
% 1000000;
326 total
.QuadPart
/= 1000000;
328 /* Sanity check to make sure we can represent the result. */
329 if (total
.HighPart
== 0)
331 int secs
= total
.LowPart
;
333 return list3 (make_number ((secs
>> 16) & 0xffff),
334 make_number (secs
& 0xffff),
335 make_number (microseconds
));
340 return Fcurrent_time ();
343 /* ** The wrapper functions ** */
345 BOOL WINAPI
open_process_token (
346 HANDLE ProcessHandle
,
350 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
351 HMODULE hm_advapi32
= NULL
;
352 if (is_windows_9x () == TRUE
)
356 if (g_b_init_open_process_token
== 0)
358 g_b_init_open_process_token
= 1;
359 hm_advapi32
= LoadLibrary ("Advapi32.dll");
360 s_pfn_Open_Process_Token
=
361 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
363 if (s_pfn_Open_Process_Token
== NULL
)
368 s_pfn_Open_Process_Token (
375 BOOL WINAPI
get_token_information (
377 TOKEN_INFORMATION_CLASS TokenInformationClass
,
378 LPVOID TokenInformation
,
379 DWORD TokenInformationLength
,
382 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
383 HMODULE hm_advapi32
= NULL
;
384 if (is_windows_9x () == TRUE
)
388 if (g_b_init_get_token_information
== 0)
390 g_b_init_get_token_information
= 1;
391 hm_advapi32
= LoadLibrary ("Advapi32.dll");
392 s_pfn_Get_Token_Information
=
393 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
395 if (s_pfn_Get_Token_Information
== NULL
)
400 s_pfn_Get_Token_Information (
402 TokenInformationClass
,
404 TokenInformationLength
,
409 BOOL WINAPI
lookup_account_sid (
410 LPCTSTR lpSystemName
,
415 LPDWORD cbDomainName
,
418 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
419 HMODULE hm_advapi32
= NULL
;
420 if (is_windows_9x () == TRUE
)
424 if (g_b_init_lookup_account_sid
== 0)
426 g_b_init_lookup_account_sid
= 1;
427 hm_advapi32
= LoadLibrary ("Advapi32.dll");
428 s_pfn_Lookup_Account_Sid
=
429 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
431 if (s_pfn_Lookup_Account_Sid
== NULL
)
436 s_pfn_Lookup_Account_Sid (
447 PSID_IDENTIFIER_AUTHORITY WINAPI
get_sid_identifier_authority (
450 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority
= NULL
;
451 HMODULE hm_advapi32
= NULL
;
452 if (is_windows_9x () == TRUE
)
456 if (g_b_init_get_sid_identifier_authority
== 0)
458 g_b_init_get_sid_identifier_authority
= 1;
459 hm_advapi32
= LoadLibrary ("Advapi32.dll");
460 s_pfn_Get_Sid_Identifier_Authority
=
461 (GetSidIdentifierAuthority_Proc
) GetProcAddress (
462 hm_advapi32
, "GetSidIdentifierAuthority");
464 if (s_pfn_Get_Sid_Identifier_Authority
== NULL
)
468 return (s_pfn_Get_Sid_Identifier_Authority (pSid
));
471 PDWORD WINAPI
get_sid_sub_authority (
475 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
476 static DWORD zero
= 0U;
477 HMODULE hm_advapi32
= NULL
;
478 if (is_windows_9x () == TRUE
)
482 if (g_b_init_get_sid_sub_authority
== 0)
484 g_b_init_get_sid_sub_authority
= 1;
485 hm_advapi32
= LoadLibrary ("Advapi32.dll");
486 s_pfn_Get_Sid_Sub_Authority
=
487 (GetSidSubAuthority_Proc
) GetProcAddress (
488 hm_advapi32
, "GetSidSubAuthority");
490 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
494 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
497 PUCHAR WINAPI
get_sid_sub_authority_count (
500 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
501 static UCHAR zero
= 0U;
502 HMODULE hm_advapi32
= NULL
;
503 if (is_windows_9x () == TRUE
)
507 if (g_b_init_get_sid_sub_authority_count
== 0)
509 g_b_init_get_sid_sub_authority_count
= 1;
510 hm_advapi32
= LoadLibrary ("Advapi32.dll");
511 s_pfn_Get_Sid_Sub_Authority_Count
=
512 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
513 hm_advapi32
, "GetSidSubAuthorityCount");
515 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
519 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
522 BOOL WINAPI
get_file_security (
524 SECURITY_INFORMATION RequestedInformation
,
525 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
527 LPDWORD lpnLengthNeeded
)
529 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
530 HMODULE hm_advapi32
= NULL
;
531 if (is_windows_9x () == TRUE
)
535 if (g_b_init_get_file_security
== 0)
537 g_b_init_get_file_security
= 1;
538 hm_advapi32
= LoadLibrary ("Advapi32.dll");
539 s_pfn_Get_File_Security
=
540 (GetFileSecurity_Proc
) GetProcAddress (
541 hm_advapi32
, GetFileSecurity_Name
);
543 if (s_pfn_Get_File_Security
== NULL
)
547 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
548 pSecurityDescriptor
, nLength
,
552 BOOL WINAPI
get_security_descriptor_owner (
553 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
555 LPBOOL lpbOwnerDefaulted
)
557 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
558 HMODULE hm_advapi32
= NULL
;
559 if (is_windows_9x () == TRUE
)
563 if (g_b_init_get_security_descriptor_owner
== 0)
565 g_b_init_get_security_descriptor_owner
= 1;
566 hm_advapi32
= LoadLibrary ("Advapi32.dll");
567 s_pfn_Get_Security_Descriptor_Owner
=
568 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
569 hm_advapi32
, "GetSecurityDescriptorOwner");
571 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
575 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
579 BOOL WINAPI
get_security_descriptor_group (
580 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
582 LPBOOL lpbGroupDefaulted
)
584 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
585 HMODULE hm_advapi32
= NULL
;
586 if (is_windows_9x () == TRUE
)
590 if (g_b_init_get_security_descriptor_group
== 0)
592 g_b_init_get_security_descriptor_group
= 1;
593 hm_advapi32
= LoadLibrary ("Advapi32.dll");
594 s_pfn_Get_Security_Descriptor_Group
=
595 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
596 hm_advapi32
, "GetSecurityDescriptorGroup");
598 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
602 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
606 BOOL WINAPI
is_valid_sid (
609 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
610 HMODULE hm_advapi32
= NULL
;
611 if (is_windows_9x () == TRUE
)
615 if (g_b_init_is_valid_sid
== 0)
617 g_b_init_is_valid_sid
= 1;
618 hm_advapi32
= LoadLibrary ("Advapi32.dll");
620 (IsValidSid_Proc
) GetProcAddress (
621 hm_advapi32
, "IsValidSid");
623 if (s_pfn_Is_Valid_Sid
== NULL
)
627 return (s_pfn_Is_Valid_Sid (sid
));
631 END: Wrapper functions around OpenProcessToken
632 and other functions in advapi32.dll that are only
633 supported in Windows NT / 2k / XP
637 /* Equivalent of strerror for W32 error codes. */
639 w32_strerror (int error_no
)
641 static char buf
[500];
644 error_no
= GetLastError ();
647 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
649 0, /* choose most suitable language */
650 buf
, sizeof (buf
), NULL
))
651 sprintf (buf
, "w32 error %u", error_no
);
655 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
656 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
658 This is called from alloc.c:valid_pointer_p. */
660 w32_valid_pointer_p (void *p
, int size
)
663 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
667 unsigned char *buf
= alloca (size
);
668 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
677 static char startup_dir
[MAXPATHLEN
];
679 /* Get the current working directory. */
684 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
688 /* Emacs doesn't actually change directory itself, and we want to
689 force our real wd to be where emacs.exe is to avoid unnecessary
690 conflicts when trying to rename or delete directories. */
691 strcpy (dir
, startup_dir
);
697 /* Emulate gethostname. */
699 gethostname (char *buffer
, int size
)
701 /* NT only allows small host names, so the buffer is
702 certainly large enough. */
703 return !GetComputerName (buffer
, &size
);
705 #endif /* HAVE_SOCKETS */
707 /* Emulate getloadavg. */
709 getloadavg (double loadavg
[], int nelem
)
713 /* A faithful emulation is going to have to be saved for a rainy day. */
714 for (i
= 0; i
< nelem
; i
++)
721 /* Emulate getpwuid, getpwnam and others. */
723 #define PASSWD_FIELD_SIZE 256
725 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
726 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
727 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
728 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
729 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
731 static struct passwd dflt_passwd
=
743 static char dflt_group_name
[GNLEN
+1];
745 static struct group dflt_group
=
747 /* When group information is not available, we return this as the
748 group for all files. */
756 return dflt_passwd
.pw_uid
;
762 /* I could imagine arguing for checking to see whether the user is
763 in the Administrators group and returning a UID of 0 for that
764 case, but I don't know how wise that would be in the long run. */
771 return dflt_passwd
.pw_gid
;
783 if (uid
== dflt_passwd
.pw_uid
)
795 getpwnam (char *name
)
799 pw
= getpwuid (getuid ());
803 if (xstrcasecmp (name
, pw
->pw_name
))
812 /* Find the user's real name by opening the process token and
813 looking up the name associated with the user-sid in that token.
815 Use the relative portion of the identifier authority value from
816 the user-sid as the user id value (same for group id using the
817 primary group sid from the process token). */
819 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
820 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), trash
;
821 DWORD glength
= sizeof (gname
);
823 SID_NAME_USE user_type
;
824 unsigned char buf
[1024];
825 TOKEN_USER user_token
;
826 TOKEN_PRIMARY_GROUP group_token
;
828 if (open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
)
829 && get_token_information (token
, TokenUser
,
830 (PVOID
)buf
, sizeof (buf
), &trash
)
831 && (memcpy (&user_token
, buf
, sizeof (user_token
)),
832 lookup_account_sid (NULL
, user_token
.User
.Sid
, uname
, &ulength
,
833 domain
, &dlength
, &user_type
)))
835 strcpy (dflt_passwd
.pw_name
, uname
);
836 /* Determine a reasonable uid value. */
837 if (xstrcasecmp ("administrator", uname
) == 0)
839 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
840 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
844 /* Use the last sub-authority value of the RID, the relative
845 portion of the SID, as user/group ID. */
846 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
848 /* Get group id and name. */
849 if (get_token_information (token
, TokenPrimaryGroup
,
850 (PVOID
)buf
, sizeof (buf
), &trash
))
852 memcpy (&group_token
, buf
, sizeof (group_token
));
853 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
854 dlength
= sizeof (domain
);
855 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
856 gname
, &glength
, NULL
, &dlength
,
858 strcpy (dflt_group_name
, gname
);
861 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
864 /* If security calls are not supported (presumably because we
865 are running under Windows 95), fallback to this. */
866 else if (GetUserName (uname
, &ulength
))
868 strcpy (dflt_passwd
.pw_name
, uname
);
869 if (xstrcasecmp ("administrator", uname
) == 0)
870 dflt_passwd
.pw_uid
= 0;
872 dflt_passwd
.pw_uid
= 123;
873 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
877 strcpy (dflt_passwd
.pw_name
, "unknown");
878 dflt_passwd
.pw_uid
= 123;
879 dflt_passwd
.pw_gid
= 123;
881 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
883 /* Ensure HOME and SHELL are defined. */
884 if (getenv ("HOME") == NULL
)
886 if (getenv ("SHELL") == NULL
)
889 /* Set dir and shell from environment variables. */
890 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
891 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
900 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
901 return ((rand () << 15) | rand ());
911 /* Normalize filename by converting all path separators to
912 the specified separator. Also conditionally convert upper
913 case path name components to lower case. */
916 normalize_filename (fp
, path_sep
)
923 /* Always lower-case drive letters a-z, even if the filesystem
924 preserves case in filenames.
925 This is so filenames can be compared by string comparison
926 functions that are case-sensitive. Even case-preserving filesystems
927 do not distinguish case in drive letters. */
928 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
934 if (NILP (Vw32_downcase_file_names
))
938 if (*fp
== '/' || *fp
== '\\')
945 sep
= path_sep
; /* convert to this path separator */
946 elem
= fp
; /* start of current path element */
949 if (*fp
>= 'a' && *fp
<= 'z')
950 elem
= 0; /* don't convert this element */
952 if (*fp
== 0 || *fp
== ':')
954 sep
= *fp
; /* restore current separator (or 0) */
955 *fp
= '/'; /* after conversion of this element */
958 if (*fp
== '/' || *fp
== '\\')
960 if (elem
&& elem
!= fp
)
962 *fp
= 0; /* temporary end of string */
963 _strlwr (elem
); /* while we convert to lower case */
965 *fp
= sep
; /* convert (or restore) path separator */
966 elem
= fp
+ 1; /* next element starts after separator */
972 /* Destructively turn backslashes into slashes. */
974 dostounix_filename (p
)
977 normalize_filename (p
, '/');
980 /* Destructively turn slashes into backslashes. */
982 unixtodos_filename (p
)
985 normalize_filename (p
, '\\');
988 /* Remove all CR's that are followed by a LF.
989 (From msdos.c...probably should figure out a way to share it,
990 although this code isn't going to ever change.) */
994 register unsigned char *buf
;
996 unsigned char *np
= buf
;
997 unsigned char *startp
= buf
;
998 unsigned char *endp
= buf
+ n
;
1002 while (buf
< endp
- 1)
1006 if (*(++buf
) != 0x0a)
1017 /* Parse the root part of file name, if present. Return length and
1018 optionally store pointer to char after root. */
1020 parse_root (char * name
, char ** pPath
)
1022 char * start
= name
;
1027 /* find the root name of the volume if given */
1028 if (isalpha (name
[0]) && name
[1] == ':')
1030 /* skip past drive specifier */
1032 if (IS_DIRECTORY_SEP (name
[0]))
1035 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1041 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1046 if (IS_DIRECTORY_SEP (name
[0]))
1053 return name
- start
;
1056 /* Get long base name for name; name is assumed to be absolute. */
1058 get_long_basename (char * name
, char * buf
, int size
)
1060 WIN32_FIND_DATA find_data
;
1064 /* must be valid filename, no wild cards or other invalid characters */
1065 if (_mbspbrk (name
, "*?|<>\""))
1068 dir_handle
= FindFirstFile (name
, &find_data
);
1069 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1071 if ((len
= strlen (find_data
.cFileName
)) < size
)
1072 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1075 FindClose (dir_handle
);
1080 /* Get long name for file, if possible (assumed to be absolute). */
1082 w32_get_long_filename (char * name
, char * buf
, int size
)
1087 char full
[ MAX_PATH
];
1090 len
= strlen (name
);
1091 if (len
>= MAX_PATH
)
1094 /* Use local copy for destructive modification. */
1095 memcpy (full
, name
, len
+1);
1096 unixtodos_filename (full
);
1098 /* Copy root part verbatim. */
1099 len
= parse_root (full
, &p
);
1100 memcpy (o
, full
, len
);
1105 while (p
!= NULL
&& *p
)
1108 p
= strchr (q
, '\\');
1110 len
= get_long_basename (full
, o
, size
);
1133 is_unc_volume (const char *filename
)
1135 const char *ptr
= filename
;
1137 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1140 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1146 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1149 sigsetmask (int signal_mask
)
1167 sigunblock (int sig
)
1173 setpgrp (int pid
, int gid
)
1184 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1187 w32_get_resource (key
, lpdwtype
)
1192 HKEY hrootkey
= NULL
;
1195 /* Check both the current user and the local machine to see if
1196 we have any resources. */
1198 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1202 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1203 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1204 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1206 RegCloseKey (hrootkey
);
1212 RegCloseKey (hrootkey
);
1215 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1219 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1220 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1221 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1223 RegCloseKey (hrootkey
);
1229 RegCloseKey (hrootkey
);
1235 char *get_emacs_configuration (void);
1236 extern Lisp_Object Vsystem_configuration
;
1239 init_environment (char ** argv
)
1241 static const char * const tempdirs
[] = {
1242 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1247 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1249 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1250 temporary files and assume "/tmp" if $TMPDIR is unset, which
1251 will break on DOS/Windows. Refuse to work if we cannot find
1252 a directory, not even "c:/", usable for that purpose. */
1253 for (i
= 0; i
< imax
; i
++)
1255 const char *tmp
= tempdirs
[i
];
1258 tmp
= getenv (tmp
+ 1);
1259 /* Note that `access' can lie to us if the directory resides on a
1260 read-only filesystem, like CD-ROM or a write-protected floppy.
1261 The only way to be really sure is to actually create a file and
1262 see if it succeeds. But I think that's too much to ask. */
1263 if (tmp
&& _access (tmp
, D_OK
) == 0)
1265 char * var
= alloca (strlen (tmp
) + 8);
1266 sprintf (var
, "TMPDIR=%s", tmp
);
1267 _putenv (strdup (var
));
1274 Fcons (build_string ("no usable temporary directories found!!"),
1276 "While setting TMPDIR: ");
1278 /* Check for environment variables and use registry settings if they
1279 don't exist. Fallback on default values where applicable. */
1284 char locale_name
[32];
1285 struct stat ignored
;
1286 char default_home
[MAX_PATH
];
1288 static const struct env_entry
1295 {"PRELOAD_WINSOCK", NULL
},
1296 {"emacs_dir", "C:/emacs"},
1297 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1298 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1299 {"EMACSDATA", "%emacs_dir%/etc"},
1300 {"EMACSPATH", "%emacs_dir%/bin"},
1301 /* We no longer set INFOPATH because Info-default-directory-list
1303 /* {"INFOPATH", "%emacs_dir%/info"}, */
1304 {"EMACSDOC", "%emacs_dir%/etc"},
1309 #define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1311 /* We need to copy dflt_envvars[] and work on the copy because we
1312 don't want the dumped Emacs to inherit the values of
1313 environment variables we saw during dumping (which could be on
1314 a different system). The defaults above must be left intact. */
1315 struct env_entry env_vars
[N_ENV_VARS
];
1317 for (i
= 0; i
< N_ENV_VARS
; i
++)
1318 env_vars
[i
] = dflt_envvars
[i
];
1320 /* For backwards compatibility, check if a .emacs file exists in C:/
1321 If not, then we can try to default to the appdata directory under the
1322 user's profile, which is more likely to be writable. */
1323 if (stat ("C:/.emacs", &ignored
) < 0)
1325 HRESULT profile_result
;
1326 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1327 of Windows 95 and NT4 that have not been updated to include
1328 MSIE 5. Also we don't link with shell32.dll by default. */
1329 HMODULE shell32_dll
;
1330 ShGetFolderPath_fn get_folder_path
;
1331 shell32_dll
= GetModuleHandle ("shell32.dll");
1332 get_folder_path
= (ShGetFolderPath_fn
)
1333 GetProcAddress (shell32_dll
, "SHGetFolderPathA");
1335 if (get_folder_path
!= NULL
)
1337 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1340 /* If we can't get the appdata dir, revert to old behavior. */
1341 if (profile_result
== S_OK
)
1342 env_vars
[0].def_value
= default_home
;
1345 /* Unload shell32.dll, it is not needed anymore. */
1346 FreeLibrary (shell32_dll
);
1349 /* Get default locale info and use it for LANG. */
1350 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1351 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1352 locale_name
, sizeof (locale_name
)))
1354 for (i
= 0; i
< N_ENV_VARS
; i
++)
1356 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1358 env_vars
[i
].def_value
= locale_name
;
1364 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1366 /* Treat emacs_dir specially: set it unconditionally based on our
1367 location, if it appears that we are running from the bin subdir
1368 of a standard installation. */
1371 char modname
[MAX_PATH
];
1373 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1375 if ((p
= strrchr (modname
, '\\')) == NULL
)
1379 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1381 char buf
[SET_ENV_BUF_SIZE
];
1384 for (p
= modname
; *p
; p
++)
1385 if (*p
== '\\') *p
= '/';
1387 _snprintf (buf
, sizeof(buf
)-1, "emacs_dir=%s", modname
);
1388 _putenv (strdup (buf
));
1390 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1392 /* FIXME: should use substring of get_emacs_configuration ().
1393 But I don't think the Windows build supports alpha, mips etc
1394 anymore, so have taken the easy option for now. */
1395 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1398 p
= strrchr (modname
, '\\');
1402 p
= strrchr (modname
, '\\');
1403 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1405 char buf
[SET_ENV_BUF_SIZE
];
1408 for (p
= modname
; *p
; p
++)
1409 if (*p
== '\\') *p
= '/';
1411 _snprintf (buf
, sizeof(buf
)-1, "emacs_dir=%s", modname
);
1412 _putenv (strdup (buf
));
1418 for (i
= 0; i
< N_ENV_VARS
; i
++)
1420 if (!getenv (env_vars
[i
].name
))
1424 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1425 /* Also ignore empty environment variables. */
1429 lpval
= env_vars
[i
].def_value
;
1430 dwType
= REG_EXPAND_SZ
;
1436 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1438 if (dwType
== REG_EXPAND_SZ
)
1439 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof(buf1
));
1440 else if (dwType
== REG_SZ
)
1441 strcpy (buf1
, lpval
);
1442 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1444 _snprintf (buf2
, sizeof(buf2
)-1, "%s=%s", env_vars
[i
].name
,
1446 _putenv (strdup (buf2
));
1456 /* Rebuild system configuration to reflect invoking system. */
1457 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1459 /* Another special case: on NT, the PATH variable is actually named
1460 "Path" although cmd.exe (perhaps NT itself) arranges for
1461 environment variable lookup and setting to be case insensitive.
1462 However, Emacs assumes a fully case sensitive environment, so we
1463 need to change "Path" to "PATH" to match the expectations of
1464 various elisp packages. We do this by the sneaky method of
1465 modifying the string in the C runtime environ entry.
1467 The same applies to COMSPEC. */
1471 for (envp
= environ
; *envp
; envp
++)
1472 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1473 memcpy (*envp
, "PATH=", 5);
1474 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1475 memcpy (*envp
, "COMSPEC=", 8);
1478 /* Remember the initial working directory for getwd, then make the
1479 real wd be the location of emacs.exe to avoid conflicts when
1480 renaming or deleting directories. (We also don't call chdir when
1481 running subprocesses for the same reason.) */
1482 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1487 static char modname
[MAX_PATH
];
1489 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1491 if ((p
= strrchr (modname
, '\\')) == NULL
)
1495 SetCurrentDirectory (modname
);
1497 /* Ensure argv[0] has the full path to Emacs. */
1502 /* Determine if there is a middle mouse button, to allow parse_button
1503 to decide whether right mouse events should be mouse-2 or
1505 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1511 emacs_root_dir (void)
1513 static char root_dir
[FILENAME_MAX
];
1516 p
= getenv ("emacs_dir");
1519 strcpy (root_dir
, p
);
1520 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1521 dostounix_filename (root_dir
);
1525 /* We don't have scripts to automatically determine the system configuration
1526 for Emacs before it's compiled, and we don't want to have to make the
1527 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1531 get_emacs_configuration (void)
1533 char *arch
, *oem
, *os
;
1535 static char configuration_buffer
[32];
1537 /* Determine the processor type. */
1538 switch (get_processor_type ())
1541 #ifdef PROCESSOR_INTEL_386
1542 case PROCESSOR_INTEL_386
:
1543 case PROCESSOR_INTEL_486
:
1544 case PROCESSOR_INTEL_PENTIUM
:
1549 #ifdef PROCESSOR_MIPS_R2000
1550 case PROCESSOR_MIPS_R2000
:
1551 case PROCESSOR_MIPS_R3000
:
1552 case PROCESSOR_MIPS_R4000
:
1557 #ifdef PROCESSOR_ALPHA_21064
1558 case PROCESSOR_ALPHA_21064
:
1568 /* Use the OEM field to reflect the compiler/library combination. */
1570 #define COMPILER_NAME "msvc"
1573 #define COMPILER_NAME "mingw"
1575 #define COMPILER_NAME "unknown"
1578 oem
= COMPILER_NAME
;
1580 switch (osinfo_cache
.dwPlatformId
) {
1581 case VER_PLATFORM_WIN32_NT
:
1583 build_num
= osinfo_cache
.dwBuildNumber
;
1585 case VER_PLATFORM_WIN32_WINDOWS
:
1586 if (osinfo_cache
.dwMinorVersion
== 0) {
1591 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1593 case VER_PLATFORM_WIN32s
:
1594 /* Not supported, should not happen. */
1596 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1604 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1605 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1606 get_w32_major_version (), get_w32_minor_version (), build_num
);
1608 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1611 return configuration_buffer
;
1615 get_emacs_configuration_options (void)
1617 static char options_buffer
[256];
1619 /* Work out the effective configure options for this build. */
1621 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1624 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1626 #define COMPILER_VERSION ""
1630 sprintf (options_buffer
, COMPILER_VERSION
);
1632 strcat (options_buffer
, " --no-opt");
1635 strcat (options_buffer
, " --cflags");
1636 strcat (options_buffer
, USER_CFLAGS
);
1639 strcat (options_buffer
, " --ldflags");
1640 strcat (options_buffer
, USER_LDFLAGS
);
1642 return options_buffer
;
1646 #include <sys/timeb.h>
1648 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1650 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1655 tv
->tv_sec
= tb
.time
;
1656 tv
->tv_usec
= tb
.millitm
* 1000L;
1659 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1660 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1664 /* ------------------------------------------------------------------------- */
1665 /* IO support and wrapper functions for W32 API. */
1666 /* ------------------------------------------------------------------------- */
1668 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1669 on network directories, so we handle that case here.
1670 (Ulrich Leodolter, 1/11/95). */
1672 sys_ctime (const time_t *t
)
1674 char *str
= (char *) ctime (t
);
1675 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1678 /* Emulate sleep...we could have done this with a define, but that
1679 would necessitate including windows.h in the files that used it.
1680 This is much easier. */
1682 sys_sleep (int seconds
)
1684 Sleep (seconds
* 1000);
1687 /* Internal MSVC functions for low-level descriptor munging */
1688 extern int __cdecl
_set_osfhnd (int fd
, long h
);
1689 extern int __cdecl
_free_osfhnd (int fd
);
1691 /* parallel array of private info on file handles */
1692 filedesc fd_info
[ MAXDESC
];
1694 typedef struct volume_info_data
{
1695 struct volume_info_data
* next
;
1697 /* time when info was obtained */
1700 /* actual volume info */
1709 /* Global referenced by various functions. */
1710 static volume_info_data volume_info
;
1712 /* Vector to indicate which drives are local and fixed (for which cached
1713 data never expires). */
1714 static BOOL fixed_drives
[26];
1716 /* Consider cached volume information to be stale if older than 10s,
1717 at least for non-local drives. Info for fixed drives is never stale. */
1718 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
1719 #define VOLINFO_STILL_VALID( root_dir, info ) \
1720 ( ( isalpha (root_dir[0]) && \
1721 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
1722 || GetTickCount () - info->timestamp < 10000 )
1724 /* Cache support functions. */
1726 /* Simple linked list with linear search is sufficient. */
1727 static volume_info_data
*volume_cache
= NULL
;
1729 static volume_info_data
*
1730 lookup_volume_info (char * root_dir
)
1732 volume_info_data
* info
;
1734 for (info
= volume_cache
; info
; info
= info
->next
)
1735 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
1741 add_volume_info (char * root_dir
, volume_info_data
* info
)
1743 info
->root_dir
= xstrdup (root_dir
);
1744 info
->next
= volume_cache
;
1745 volume_cache
= info
;
1749 /* Wrapper for GetVolumeInformation, which uses caching to avoid
1750 performance penalty (~2ms on 486 for local drives, 7.5ms for local
1751 cdrom drive, ~5-10ms or more for remote drives on LAN). */
1753 GetCachedVolumeInformation (char * root_dir
)
1755 volume_info_data
* info
;
1756 char default_root
[ MAX_PATH
];
1758 /* NULL for root_dir means use root from current directory. */
1759 if (root_dir
== NULL
)
1761 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
1763 parse_root (default_root
, &root_dir
);
1765 root_dir
= default_root
;
1768 /* Local fixed drives can be cached permanently. Removable drives
1769 cannot be cached permanently, since the volume name and serial
1770 number (if nothing else) can change. Remote drives should be
1771 treated as if they are removable, since there is no sure way to
1772 tell whether they are or not. Also, the UNC association of drive
1773 letters mapped to remote volumes can be changed at any time (even
1774 by other processes) without notice.
1776 As a compromise, so we can benefit from caching info for remote
1777 volumes, we use a simple expiry mechanism to invalidate cache
1778 entries that are more than ten seconds old. */
1781 /* No point doing this, because WNetGetConnection is even slower than
1782 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
1783 GetDriveType is about the only call of this type which does not
1784 involve network access, and so is extremely quick). */
1786 /* Map drive letter to UNC if remote. */
1787 if ( isalpha( root_dir
[0] ) && !fixed
[ DRIVE_INDEX( root_dir
[0] ) ] )
1789 char remote_name
[ 256 ];
1790 char drive
[3] = { root_dir
[0], ':' };
1792 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
1794 /* do something */ ;
1798 info
= lookup_volume_info (root_dir
);
1800 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
1808 /* Info is not cached, or is stale. */
1809 if (!GetVolumeInformation (root_dir
,
1810 name
, sizeof (name
),
1814 type
, sizeof (type
)))
1817 /* Cache the volume information for future use, overwriting existing
1818 entry if present. */
1821 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
1822 add_volume_info (root_dir
, info
);
1830 info
->name
= xstrdup (name
);
1831 info
->serialnum
= serialnum
;
1832 info
->maxcomp
= maxcomp
;
1833 info
->flags
= flags
;
1834 info
->type
= xstrdup (type
);
1835 info
->timestamp
= GetTickCount ();
1841 /* Get information on the volume where name is held; set path pointer to
1842 start of pathname in name (past UNC header\volume header if present). */
1844 get_volume_info (const char * name
, const char ** pPath
)
1846 char temp
[MAX_PATH
];
1847 char *rootname
= NULL
; /* default to current volume */
1848 volume_info_data
* info
;
1853 /* find the root name of the volume if given */
1854 if (isalpha (name
[0]) && name
[1] == ':')
1862 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1869 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1882 info
= GetCachedVolumeInformation (rootname
);
1885 /* Set global referenced by other functions. */
1886 volume_info
= *info
;
1892 /* Determine if volume is FAT format (ie. only supports short 8.3
1893 names); also set path pointer to start of pathname in name. */
1895 is_fat_volume (const char * name
, const char ** pPath
)
1897 if (get_volume_info (name
, pPath
))
1898 return (volume_info
.maxcomp
== 12);
1902 /* Map filename to a valid 8.3 name if necessary. */
1904 map_w32_filename (const char * name
, const char ** pPath
)
1906 static char shortname
[MAX_PATH
];
1907 char * str
= shortname
;
1910 const char * save_name
= name
;
1912 if (strlen (name
) >= MAX_PATH
)
1914 /* Return a filename which will cause callers to fail. */
1915 strcpy (shortname
, "?");
1919 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
1921 register int left
= 8; /* maximum number of chars in part */
1922 register int extn
= 0; /* extension added? */
1923 register int dots
= 2; /* maximum number of dots allowed */
1926 *str
++ = *name
++; /* skip past UNC header */
1928 while ((c
= *name
++))
1935 extn
= 0; /* reset extension flags */
1936 dots
= 2; /* max 2 dots */
1937 left
= 8; /* max length 8 for main part */
1941 extn
= 0; /* reset extension flags */
1942 dots
= 2; /* max 2 dots */
1943 left
= 8; /* max length 8 for main part */
1948 /* Convert path components of the form .xxx to _xxx,
1949 but leave . and .. as they are. This allows .emacs
1950 to be read as _emacs, for example. */
1954 IS_DIRECTORY_SEP (*name
))
1969 extn
= 1; /* we've got an extension */
1970 left
= 3; /* 3 chars in extension */
1974 /* any embedded dots after the first are converted to _ */
1979 case '#': /* don't lose these, they're important */
1981 str
[-1] = c
; /* replace last character of part */
1986 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
1988 dots
= 0; /* started a path component */
1997 strcpy (shortname
, name
);
1998 unixtodos_filename (shortname
);
2002 *pPath
= shortname
+ (path
- save_name
);
2008 is_exec (const char * name
)
2010 char * p
= strrchr (name
, '.');
2013 && (xstrcasecmp (p
, ".exe") == 0 ||
2014 xstrcasecmp (p
, ".com") == 0 ||
2015 xstrcasecmp (p
, ".bat") == 0 ||
2016 xstrcasecmp (p
, ".cmd") == 0));
2019 /* Emulate the Unix directory procedures opendir, closedir,
2020 and readdir. We can't use the procedures supplied in sysdep.c,
2021 so we provide them here. */
2023 struct direct dir_static
; /* simulated directory contents */
2024 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2025 static int dir_is_fat
;
2026 static char dir_pathname
[MAXPATHLEN
+1];
2027 static WIN32_FIND_DATA dir_find_data
;
2029 /* Support shares on a network resource as subdirectories of a read-only
2031 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2032 HANDLE
open_unc_volume (const char *);
2033 char *read_unc_volume (HANDLE
, char *, int);
2034 void close_unc_volume (HANDLE
);
2037 opendir (char *filename
)
2041 /* Opening is done by FindFirstFile. However, a read is inherent to
2042 this operation, so we defer the open until read time. */
2044 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2046 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2049 if (is_unc_volume (filename
))
2051 wnet_enum_handle
= open_unc_volume (filename
);
2052 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2056 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2063 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2064 dir_pathname
[MAXPATHLEN
] = '\0';
2065 dir_is_fat
= is_fat_volume (filename
, NULL
);
2071 closedir (DIR *dirp
)
2073 /* If we have a find-handle open, close it. */
2074 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2076 FindClose (dir_find_handle
);
2077 dir_find_handle
= INVALID_HANDLE_VALUE
;
2079 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2081 close_unc_volume (wnet_enum_handle
);
2082 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2084 xfree ((char *) dirp
);
2090 int downcase
= !NILP (Vw32_downcase_file_names
);
2092 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2094 if (!read_unc_volume (wnet_enum_handle
,
2095 dir_find_data
.cFileName
,
2099 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2100 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2102 char filename
[MAXNAMLEN
+ 3];
2105 strcpy (filename
, dir_pathname
);
2106 ln
= strlen (filename
) - 1;
2107 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2108 strcat (filename
, "\\");
2109 strcat (filename
, "*");
2111 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2113 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2118 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2122 /* Emacs never uses this value, so don't bother making it match
2123 value returned by stat(). */
2124 dir_static
.d_ino
= 1;
2126 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2128 /* If the file name in cFileName[] includes `?' characters, it means
2129 the original file name used characters that cannot be represented
2130 by the current ANSI codepage. To avoid total lossage, retrieve
2131 the short 8+3 alias of the long file name. */
2132 if (_mbspbrk (dir_static
.d_name
, "?"))
2134 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2135 downcase
= 1; /* 8+3 aliases are returned in all caps */
2137 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2138 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2139 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2141 /* If the file name in cFileName[] includes `?' characters, it means
2142 the original file name used characters that cannot be represented
2143 by the current ANSI codepage. To avoid total lossage, retrieve
2144 the short 8+3 alias of the long file name. */
2145 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2147 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2148 /* 8+3 aliases are returned in all caps, which could break
2149 various alists that look at filenames' extensions. */
2153 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2154 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2156 _strlwr (dir_static
.d_name
);
2160 for (p
= dir_static
.d_name
; *p
; p
++)
2161 if (*p
>= 'a' && *p
<= 'z')
2164 _strlwr (dir_static
.d_name
);
2171 open_unc_volume (const char *path
)
2177 nr
.dwScope
= RESOURCE_GLOBALNET
;
2178 nr
.dwType
= RESOURCETYPE_DISK
;
2179 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2180 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2181 nr
.lpLocalName
= NULL
;
2182 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2183 nr
.lpComment
= NULL
;
2184 nr
.lpProvider
= NULL
;
2186 result
= WNetOpenEnum(RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2187 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2189 if (result
== NO_ERROR
)
2192 return INVALID_HANDLE_VALUE
;
2196 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2200 DWORD bufsize
= 512;
2205 buffer
= alloca (bufsize
);
2206 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2207 if (result
!= NO_ERROR
)
2210 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2211 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2213 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2216 strncpy (readbuf
, ptr
, size
);
2221 close_unc_volume (HANDLE henum
)
2223 if (henum
!= INVALID_HANDLE_VALUE
)
2224 WNetCloseEnum (henum
);
2228 unc_volume_file_attributes (const char *path
)
2233 henum
= open_unc_volume (path
);
2234 if (henum
== INVALID_HANDLE_VALUE
)
2237 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2239 close_unc_volume (henum
);
2244 /* Ensure a network connection is authenticated. */
2246 logon_network_drive (const char *path
)
2248 NETRESOURCE resource
;
2249 char share
[MAX_PATH
];
2253 sprintf (drive
, "%c:\\", path
[0]);
2255 /* Only logon to networked drives. */
2256 if ((!IS_DIRECTORY_SEP (path
[0]) || !IS_DIRECTORY_SEP (path
[1]))
2257 && GetDriveType (drive
) != DRIVE_REMOTE
)
2261 strncpy (share
, path
, MAX_PATH
);
2262 /* Truncate to just server and share name. */
2263 for (i
= 2; i
< MAX_PATH
; i
++)
2265 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2272 resource
.dwType
= RESOURCETYPE_DISK
;
2273 resource
.lpLocalName
= NULL
;
2274 resource
.lpRemoteName
= share
;
2275 resource
.lpProvider
= NULL
;
2277 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2280 /* Shadow some MSVC runtime functions to map requests for long filenames
2281 to reasonable short names if necessary. This was originally added to
2282 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2286 sys_access (const char * path
, int mode
)
2290 /* MSVC implementation doesn't recognize D_OK. */
2291 path
= map_w32_filename (path
, NULL
);
2292 if (is_unc_volume (path
))
2294 attributes
= unc_volume_file_attributes (path
);
2295 if (attributes
== -1) {
2300 else if ((attributes
= GetFileAttributes (path
)) == -1)
2302 /* Should try mapping GetLastError to errno; for now just indicate
2303 that path doesn't exist. */
2307 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2312 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2317 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2326 sys_chdir (const char * path
)
2328 return _chdir (map_w32_filename (path
, NULL
));
2332 sys_chmod (const char * path
, int mode
)
2334 return _chmod (map_w32_filename (path
, NULL
), mode
);
2338 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2340 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2346 sys_creat (const char * path
, int mode
)
2348 return _creat (map_w32_filename (path
, NULL
), mode
);
2352 sys_fopen(const char * path
, const char * mode
)
2356 const char * mode_save
= mode
;
2358 /* Force all file handles to be non-inheritable. This is necessary to
2359 ensure child processes don't unwittingly inherit handles that might
2360 prevent future file access. */
2364 else if (mode
[0] == 'w' || mode
[0] == 'a')
2365 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2369 /* Only do simplistic option parsing. */
2373 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2376 else if (mode
[0] == 'b')
2381 else if (mode
[0] == 't')
2388 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2392 return _fdopen (fd
, mode_save
);
2395 /* This only works on NTFS volumes, but is useful to have. */
2397 sys_link (const char * old
, const char * new)
2401 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2403 if (old
== NULL
|| new == NULL
)
2409 strcpy (oldname
, map_w32_filename (old
, NULL
));
2410 strcpy (newname
, map_w32_filename (new, NULL
));
2412 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2413 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2414 if (fileh
!= INVALID_HANDLE_VALUE
)
2418 /* Confusingly, the "alternate" stream name field does not apply
2419 when restoring a hard link, and instead contains the actual
2420 stream data for the link (ie. the name of the link to create).
2421 The WIN32_STREAM_ID structure before the cStreamName field is
2422 the stream header, which is then immediately followed by the
2426 WIN32_STREAM_ID wid
;
2427 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2430 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2431 data
.wid
.cStreamName
, MAX_PATH
);
2434 LPVOID context
= NULL
;
2437 data
.wid
.dwStreamId
= BACKUP_LINK
;
2438 data
.wid
.dwStreamAttributes
= 0;
2439 data
.wid
.Size
.LowPart
= wlen
* sizeof(WCHAR
);
2440 data
.wid
.Size
.HighPart
= 0;
2441 data
.wid
.dwStreamNameSize
= 0;
2443 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2444 offsetof (WIN32_STREAM_ID
, cStreamName
)
2445 + data
.wid
.Size
.LowPart
,
2446 &wbytes
, FALSE
, FALSE
, &context
)
2447 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2454 /* Should try mapping GetLastError to errno; for now just
2455 indicate a general error (eg. links not supported). */
2456 errno
= EINVAL
; // perhaps EMLINK?
2460 CloseHandle (fileh
);
2469 sys_mkdir (const char * path
)
2471 return _mkdir (map_w32_filename (path
, NULL
));
2474 /* Because of long name mapping issues, we need to implement this
2475 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2476 a unique name, instead of setting the input template to an empty
2479 Standard algorithm seems to be use pid or tid with a letter on the
2480 front (in place of the 6 X's) and cycle through the letters to find a
2481 unique name. We extend that to allow any reasonable character as the
2482 first of the 6 X's. */
2484 sys_mktemp (char * template)
2488 unsigned uid
= GetCurrentThreadId ();
2489 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2491 if (template == NULL
)
2493 p
= template + strlen (template);
2495 /* replace up to the last 5 X's with uid in decimal */
2496 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2498 p
[0] = '0' + uid
% 10;
2502 if (i
< 0 && p
[0] == 'X')
2507 int save_errno
= errno
;
2508 p
[0] = first_char
[i
];
2509 if (sys_access (template, 0) < 0)
2515 while (++i
< sizeof (first_char
));
2518 /* Template is badly formed or else we can't generate a unique name,
2519 so return empty string */
2525 sys_open (const char * path
, int oflag
, int mode
)
2527 const char* mpath
= map_w32_filename (path
, NULL
);
2528 /* Try to open file without _O_CREAT, to be able to write to hidden
2529 and system files. Force all file handles to be
2531 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2534 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2538 sys_rename (const char * oldname
, const char * newname
)
2541 char temp
[MAX_PATH
];
2543 /* MoveFile on Windows 95 doesn't correctly change the short file name
2544 alias in a number of circumstances (it is not easy to predict when
2545 just by looking at oldname and newname, unfortunately). In these
2546 cases, renaming through a temporary name avoids the problem.
2548 A second problem on Windows 95 is that renaming through a temp name when
2549 newname is uppercase fails (the final long name ends up in
2550 lowercase, although the short alias might be uppercase) UNLESS the
2551 long temp name is not 8.3.
2553 So, on Windows 95 we always rename through a temp name, and we make sure
2554 the temp name has a long extension to ensure correct renaming. */
2556 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2558 if (os_subtype
== OS_WIN95
)
2564 oldname
= map_w32_filename (oldname
, NULL
);
2565 if (o
= strrchr (oldname
, '\\'))
2568 o
= (char *) oldname
;
2570 if (p
= strrchr (temp
, '\\'))
2577 /* Force temp name to require a manufactured 8.3 alias - this
2578 seems to make the second rename work properly. */
2579 sprintf (p
, "_.%s.%u", o
, i
);
2581 result
= rename (oldname
, temp
);
2583 /* This loop must surely terminate! */
2584 while (result
< 0 && errno
== EEXIST
);
2589 /* Emulate Unix behavior - newname is deleted if it already exists
2590 (at least if it is a file; don't do this for directories).
2592 Since we mustn't do this if we are just changing the case of the
2593 file name (we would end up deleting the file we are trying to
2594 rename!), we let rename detect if the destination file already
2595 exists - that way we avoid the possible pitfalls of trying to
2596 determine ourselves whether two names really refer to the same
2597 file, which is not always possible in the general case. (Consider
2598 all the permutations of shared or subst'd drives, etc.) */
2600 newname
= map_w32_filename (newname
, NULL
);
2601 result
= rename (temp
, newname
);
2605 && _chmod (newname
, 0666) == 0
2606 && _unlink (newname
) == 0)
2607 result
= rename (temp
, newname
);
2613 sys_rmdir (const char * path
)
2615 return _rmdir (map_w32_filename (path
, NULL
));
2619 sys_unlink (const char * path
)
2621 path
= map_w32_filename (path
, NULL
);
2623 /* On Unix, unlink works without write permission. */
2624 _chmod (path
, 0666);
2625 return _unlink (path
);
2628 static FILETIME utc_base_ft
;
2629 static long double utc_base
;
2630 static int init
= 0;
2633 convert_time_raw (FILETIME ft
)
2636 (long double) ft
.dwHighDateTime
2637 * 4096.0L * 1024.0L * 1024.0L + ft
.dwLowDateTime
;
2641 convert_time (FILETIME ft
)
2647 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2656 st
.wMilliseconds
= 0;
2658 SystemTimeToFileTime (&st
, &utc_base_ft
);
2659 utc_base
= (long double) utc_base_ft
.dwHighDateTime
2660 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft
.dwLowDateTime
;
2664 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2667 return (time_t) ((convert_time_raw (ft
) - utc_base
) * 1e-7L);
2672 convert_from_time_t (time_t time
, FILETIME
* pft
)
2678 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2687 st
.wMilliseconds
= 0;
2689 SystemTimeToFileTime (&st
, &utc_base_ft
);
2690 utc_base
= (long double) utc_base_ft
.dwHighDateTime
2691 * 4096 * 1024 * 1024 + utc_base_ft
.dwLowDateTime
;
2695 /* time in 100ns units since 1-Jan-1601 */
2696 tmp
= (long double) time
* 1e7
+ utc_base
;
2697 pft
->dwHighDateTime
= (DWORD
) (tmp
/ (4096.0 * 1024 * 1024));
2698 pft
->dwLowDateTime
= (DWORD
) (tmp
- (4096.0 * 1024 * 1024) * pft
->dwHighDateTime
);
2702 /* No reason to keep this; faking inode values either by hashing or even
2703 using the file index from GetInformationByHandle, is not perfect and
2704 so by default Emacs doesn't use the inode values on Windows.
2705 Instead, we now determine file-truename correctly (except for
2706 possible drive aliasing etc). */
2708 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
2710 hashval (const unsigned char * str
)
2715 h
= (h
<< 4) + *str
++;
2721 /* Return the hash value of the canonical pathname, excluding the
2722 drive/UNC header, to get a hopefully unique inode number. */
2724 generate_inode_val (const char * name
)
2726 char fullname
[ MAX_PATH
];
2730 /* Get the truly canonical filename, if it exists. (Note: this
2731 doesn't resolve aliasing due to subst commands, or recognise hard
2733 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
2736 parse_root (fullname
, &p
);
2737 /* Normal W32 filesystems are still case insensitive. */
2744 static PSECURITY_DESCRIPTOR
2745 get_file_security_desc (const char *fname
)
2747 PSECURITY_DESCRIPTOR psd
= NULL
;
2749 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
2750 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
2752 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
2754 err
= GetLastError ();
2755 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
2759 psd
= xmalloc (sd_len
);
2760 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
2772 unsigned n_subauthorities
;
2774 /* Use the last sub-authority value of the RID, the relative
2775 portion of the SID, as user/group ID. */
2776 n_subauthorities
= *get_sid_sub_authority_count (sid
);
2777 if (n_subauthorities
< 1)
2778 return 0; /* the "World" RID */
2779 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
2786 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
2787 int *id
, char *nm
, int what
)
2790 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
2792 SID_NAME_USE ignore
;
2794 DWORD name_len
= sizeof (name
);
2796 DWORD domain_len
= sizeof(domain
);
2802 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
2803 else if (what
== GID
)
2804 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
2808 if (!result
|| !is_valid_sid (sid
))
2812 /* If FNAME is a UNC, we need to lookup account on the
2813 specified machine. */
2814 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
2815 && fname
[2] != '\0')
2820 for (s
= fname
+ 2, p
= machine
;
2821 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
2827 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
2828 domain
, &domain_len
, &ignore
)
2829 || name_len
> UNLEN
+1)
2833 *id
= get_rid (sid
);
2841 get_file_owner_and_group (
2842 PSECURITY_DESCRIPTOR psd
,
2846 int dflt_usr
= 0, dflt_grp
= 0;
2855 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
2857 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
2860 /* Consider files to belong to current user/group, if we cannot get
2861 more accurate information. */
2864 st
->st_uid
= dflt_passwd
.pw_uid
;
2865 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
2869 st
->st_gid
= dflt_passwd
.pw_gid
;
2870 strcpy (st
->st_gname
, dflt_group
.gr_name
);
2874 /* MSVC stat function can't cope with UNC names and has other bugs, so
2875 replace it with our own. This also allows us to calculate consistent
2876 inode values without hacks in the main Emacs code. */
2878 stat (const char * path
, struct stat
* buf
)
2881 WIN32_FIND_DATA wfd
;
2883 unsigned __int64 fake_inode
;
2886 int rootdir
= FALSE
;
2887 PSECURITY_DESCRIPTOR psd
= NULL
;
2889 if (path
== NULL
|| buf
== NULL
)
2895 name
= (char *) map_w32_filename (path
, &path
);
2896 /* Must be valid filename, no wild cards or other invalid
2897 characters. We use _mbspbrk to support multibyte strings that
2898 might look to strpbrk as if they included literal *, ?, and other
2899 characters mentioned below that are disallowed by Windows
2901 if (_mbspbrk (name
, "*?|<>\""))
2907 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
2908 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
2909 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
2914 /* Remove trailing directory separator, unless name is the root
2915 directory of a drive or UNC volume in which case ensure there
2916 is a trailing separator. */
2917 len
= strlen (name
);
2918 rootdir
= (path
>= name
+ len
- 1
2919 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
2920 name
= strcpy (alloca (len
+ 2), name
);
2922 if (is_unc_volume (name
))
2924 DWORD attrs
= unc_volume_file_attributes (name
);
2929 memset (&wfd
, 0, sizeof (wfd
));
2930 wfd
.dwFileAttributes
= attrs
;
2931 wfd
.ftCreationTime
= utc_base_ft
;
2932 wfd
.ftLastAccessTime
= utc_base_ft
;
2933 wfd
.ftLastWriteTime
= utc_base_ft
;
2934 strcpy (wfd
.cFileName
, name
);
2938 if (!IS_DIRECTORY_SEP (name
[len
-1]))
2939 strcat (name
, "\\");
2940 if (GetDriveType (name
) < 2)
2945 memset (&wfd
, 0, sizeof (wfd
));
2946 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
2947 wfd
.ftCreationTime
= utc_base_ft
;
2948 wfd
.ftLastAccessTime
= utc_base_ft
;
2949 wfd
.ftLastWriteTime
= utc_base_ft
;
2950 strcpy (wfd
.cFileName
, name
);
2954 if (IS_DIRECTORY_SEP (name
[len
-1]))
2957 /* (This is hacky, but helps when doing file completions on
2958 network drives.) Optimize by using information available from
2959 active readdir if possible. */
2960 len
= strlen (dir_pathname
);
2961 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
2963 if (dir_find_handle
!= INVALID_HANDLE_VALUE
2964 && strnicmp (name
, dir_pathname
, len
) == 0
2965 && IS_DIRECTORY_SEP (name
[len
])
2966 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
2968 /* This was the last entry returned by readdir. */
2969 wfd
= dir_find_data
;
2973 logon_network_drive (name
);
2975 fh
= FindFirstFile (name
, &wfd
);
2976 if (fh
== INVALID_HANDLE_VALUE
)
2985 if (!(NILP (Vw32_get_true_file_attributes
)
2986 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) &&
2987 GetDriveType (name
) != DRIVE_FIXED
))
2988 /* No access rights required to get info. */
2989 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
2990 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
2991 != INVALID_HANDLE_VALUE
)
2993 /* This is more accurate in terms of gettting the correct number
2994 of links, but is quite slow (it is noticeable when Emacs is
2995 making a list of file name completions). */
2996 BY_HANDLE_FILE_INFORMATION info
;
2998 if (GetFileInformationByHandle (fh
, &info
))
3000 buf
->st_nlink
= info
.nNumberOfLinks
;
3001 /* Might as well use file index to fake inode values, but this
3002 is not guaranteed to be unique unless we keep a handle open
3003 all the time (even then there are situations where it is
3004 not unique). Reputedly, there are at most 48 bits of info
3005 (on NTFS, presumably less on FAT). */
3006 fake_inode
= info
.nFileIndexHigh
;
3008 fake_inode
+= info
.nFileIndexLow
;
3016 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3018 buf
->st_mode
= S_IFDIR
;
3022 switch (GetFileType (fh
))
3024 case FILE_TYPE_DISK
:
3025 buf
->st_mode
= S_IFREG
;
3027 case FILE_TYPE_PIPE
:
3028 buf
->st_mode
= S_IFIFO
;
3030 case FILE_TYPE_CHAR
:
3031 case FILE_TYPE_UNKNOWN
:
3033 buf
->st_mode
= S_IFCHR
;
3037 psd
= get_file_security_desc (name
);
3038 get_file_owner_and_group (psd
, name
, buf
);
3042 /* Don't bother to make this information more accurate. */
3043 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3048 get_file_owner_and_group (NULL
, name
, buf
);
3053 /* Not sure if there is any point in this. */
3054 if (!NILP (Vw32_generate_fake_inodes
))
3055 fake_inode
= generate_inode_val (name
);
3056 else if (fake_inode
== 0)
3058 /* For want of something better, try to make everything unique. */
3059 static DWORD gen_num
= 0;
3060 fake_inode
= ++gen_num
;
3064 /* MSVC defines _ino_t to be short; other libc's might not. */
3065 if (sizeof (buf
->st_ino
) == 2)
3066 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3068 buf
->st_ino
= fake_inode
;
3070 /* volume_info is set indirectly by map_w32_filename */
3071 buf
->st_dev
= volume_info
.serialnum
;
3072 buf
->st_rdev
= volume_info
.serialnum
;
3075 buf
->st_size
= wfd
.nFileSizeHigh
;
3076 buf
->st_size
<<= 32;
3077 buf
->st_size
+= wfd
.nFileSizeLow
;
3079 /* Convert timestamps to Unix format. */
3080 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3081 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3082 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3083 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3084 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3086 /* determine rwx permissions */
3087 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3088 permission
= S_IREAD
;
3090 permission
= S_IREAD
| S_IWRITE
;
3092 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3093 permission
|= S_IEXEC
;
3094 else if (is_exec (name
))
3095 permission
|= S_IEXEC
;
3097 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3102 /* Provide fstat and utime as well as stat for consistent handling of
3105 fstat (int desc
, struct stat
* buf
)
3107 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3108 BY_HANDLE_FILE_INFORMATION info
;
3109 unsigned __int64 fake_inode
;
3112 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3114 case FILE_TYPE_DISK
:
3115 buf
->st_mode
= S_IFREG
;
3116 if (!GetFileInformationByHandle (fh
, &info
))
3122 case FILE_TYPE_PIPE
:
3123 buf
->st_mode
= S_IFIFO
;
3125 case FILE_TYPE_CHAR
:
3126 case FILE_TYPE_UNKNOWN
:
3128 buf
->st_mode
= S_IFCHR
;
3130 memset (&info
, 0, sizeof (info
));
3131 info
.dwFileAttributes
= 0;
3132 info
.ftCreationTime
= utc_base_ft
;
3133 info
.ftLastAccessTime
= utc_base_ft
;
3134 info
.ftLastWriteTime
= utc_base_ft
;
3137 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3138 buf
->st_mode
= S_IFDIR
;
3140 buf
->st_nlink
= info
.nNumberOfLinks
;
3141 /* Might as well use file index to fake inode values, but this
3142 is not guaranteed to be unique unless we keep a handle open
3143 all the time (even then there are situations where it is
3144 not unique). Reputedly, there are at most 48 bits of info
3145 (on NTFS, presumably less on FAT). */
3146 fake_inode
= info
.nFileIndexHigh
;
3148 fake_inode
+= info
.nFileIndexLow
;
3150 /* MSVC defines _ino_t to be short; other libc's might not. */
3151 if (sizeof (buf
->st_ino
) == 2)
3152 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3154 buf
->st_ino
= fake_inode
;
3156 /* Consider files to belong to current user.
3157 FIXME: this should use GetSecurityInfo API, but it is only
3158 available for _WIN32_WINNT >= 0x501. */
3159 buf
->st_uid
= dflt_passwd
.pw_uid
;
3160 buf
->st_gid
= dflt_passwd
.pw_gid
;
3161 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3162 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3164 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3165 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3167 buf
->st_size
= info
.nFileSizeHigh
;
3168 buf
->st_size
<<= 32;
3169 buf
->st_size
+= info
.nFileSizeLow
;
3171 /* Convert timestamps to Unix format. */
3172 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3173 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3174 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3175 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3176 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3178 /* determine rwx permissions */
3179 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3180 permission
= S_IREAD
;
3182 permission
= S_IREAD
| S_IWRITE
;
3184 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3185 permission
|= S_IEXEC
;
3188 #if 0 /* no way of knowing the filename */
3189 char * p
= strrchr (name
, '.');
3191 (xstrcasecmp (p
, ".exe") == 0 ||
3192 xstrcasecmp (p
, ".com") == 0 ||
3193 xstrcasecmp (p
, ".bat") == 0 ||
3194 xstrcasecmp (p
, ".cmd") == 0))
3195 permission
|= S_IEXEC
;
3199 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3205 utime (const char *name
, struct utimbuf
*times
)
3207 struct utimbuf deftime
;
3214 deftime
.modtime
= deftime
.actime
= time (NULL
);
3218 /* Need write access to set times. */
3219 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3220 0, OPEN_EXISTING
, 0, NULL
);
3223 convert_from_time_t (times
->actime
, &atime
);
3224 convert_from_time_t (times
->modtime
, &mtime
);
3225 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3242 /* Support for browsing other processes and their attributes. See
3243 process.c for the Lisp bindings. */
3245 /* Helper wrapper functions. */
3247 HANDLE WINAPI
create_toolhelp32_snapshot(
3251 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3253 if (g_b_init_create_toolhelp32_snapshot
== 0)
3255 g_b_init_create_toolhelp32_snapshot
= 1;
3256 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3257 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3258 "CreateToolhelp32Snapshot");
3260 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3262 return INVALID_HANDLE_VALUE
;
3264 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3267 BOOL WINAPI
process32_first(
3269 LPPROCESSENTRY32 lppe
)
3271 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3273 if (g_b_init_process32_first
== 0)
3275 g_b_init_process32_first
= 1;
3276 s_pfn_Process32_First
= (Process32First_Proc
)
3277 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3280 if (s_pfn_Process32_First
== NULL
)
3284 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3287 BOOL WINAPI
process32_next(
3289 LPPROCESSENTRY32 lppe
)
3291 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3293 if (g_b_init_process32_next
== 0)
3295 g_b_init_process32_next
= 1;
3296 s_pfn_Process32_Next
= (Process32Next_Proc
)
3297 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3300 if (s_pfn_Process32_Next
== NULL
)
3304 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3307 BOOL WINAPI
open_thread_token (
3308 HANDLE ThreadHandle
,
3309 DWORD DesiredAccess
,
3311 PHANDLE TokenHandle
)
3313 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3314 HMODULE hm_advapi32
= NULL
;
3315 if (is_windows_9x () == TRUE
)
3317 SetLastError (ERROR_NOT_SUPPORTED
);
3320 if (g_b_init_open_thread_token
== 0)
3322 g_b_init_open_thread_token
= 1;
3323 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3324 s_pfn_Open_Thread_Token
=
3325 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3327 if (s_pfn_Open_Thread_Token
== NULL
)
3329 SetLastError (ERROR_NOT_SUPPORTED
);
3333 s_pfn_Open_Thread_Token (
3341 BOOL WINAPI
impersonate_self (
3342 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3344 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3345 HMODULE hm_advapi32
= NULL
;
3346 if (is_windows_9x () == TRUE
)
3350 if (g_b_init_impersonate_self
== 0)
3352 g_b_init_impersonate_self
= 1;
3353 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3354 s_pfn_Impersonate_Self
=
3355 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3357 if (s_pfn_Impersonate_Self
== NULL
)
3361 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3364 BOOL WINAPI
revert_to_self (void)
3366 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3367 HMODULE hm_advapi32
= NULL
;
3368 if (is_windows_9x () == TRUE
)
3372 if (g_b_init_revert_to_self
== 0)
3374 g_b_init_revert_to_self
= 1;
3375 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3376 s_pfn_Revert_To_Self
=
3377 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3379 if (s_pfn_Revert_To_Self
== NULL
)
3383 return s_pfn_Revert_To_Self ();
3386 BOOL WINAPI
get_process_memory_info (
3388 PPROCESS_MEMORY_COUNTERS mem_counters
,
3391 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3392 HMODULE hm_psapi
= NULL
;
3393 if (is_windows_9x () == TRUE
)
3397 if (g_b_init_get_process_memory_info
== 0)
3399 g_b_init_get_process_memory_info
= 1;
3400 hm_psapi
= LoadLibrary ("Psapi.dll");
3402 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3403 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3405 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3409 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3412 BOOL WINAPI
get_process_working_set_size (
3417 static GetProcessWorkingSetSize_Proc
3418 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3420 if (is_windows_9x () == TRUE
)
3424 if (g_b_init_get_process_working_set_size
== 0)
3426 g_b_init_get_process_working_set_size
= 1;
3427 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3428 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3429 "GetProcessWorkingSetSize");
3431 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3435 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3438 BOOL WINAPI
global_memory_status (
3441 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3443 if (is_windows_9x () == TRUE
)
3447 if (g_b_init_global_memory_status
== 0)
3449 g_b_init_global_memory_status
= 1;
3450 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3451 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3452 "GlobalMemoryStatus");
3454 if (s_pfn_Global_Memory_Status
== NULL
)
3458 return s_pfn_Global_Memory_Status (buf
);
3461 BOOL WINAPI
global_memory_status_ex (
3462 MEMORYSTATUSEX
*buf
)
3464 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3466 if (is_windows_9x () == TRUE
)
3470 if (g_b_init_global_memory_status_ex
== 0)
3472 g_b_init_global_memory_status_ex
= 1;
3473 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3474 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3475 "GlobalMemoryStatusEx");
3477 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3481 return s_pfn_Global_Memory_Status_Ex (buf
);
3485 w32_list_system_processes ()
3487 struct gcpro gcpro1
;
3488 Lisp_Object proclist
= Qnil
;
3491 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3493 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3495 PROCESSENTRY32 proc_entry
;
3501 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3502 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3503 res
= process32_next (h_snapshot
, &proc_entry
))
3505 proc_id
= proc_entry
.th32ProcessID
;
3506 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3509 CloseHandle (h_snapshot
);
3511 proclist
= Fnreverse (proclist
);
3518 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3520 TOKEN_PRIVILEGES priv
;
3521 DWORD priv_size
= sizeof (priv
);
3522 DWORD opriv_size
= sizeof (*old_priv
);
3523 HANDLE h_token
= NULL
;
3524 HANDLE h_thread
= GetCurrentThread ();
3528 res
= open_thread_token (h_thread
,
3529 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3531 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3533 if (impersonate_self (SecurityImpersonation
))
3534 res
= open_thread_token (h_thread
,
3535 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3540 priv
.PrivilegeCount
= 1;
3541 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3542 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3543 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3544 old_priv
, &opriv_size
)
3545 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3549 CloseHandle (h_token
);
3555 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3557 DWORD priv_size
= sizeof (*priv
);
3558 HANDLE h_token
= NULL
;
3561 if (open_thread_token (GetCurrentThread (),
3562 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3565 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3566 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3570 CloseHandle (h_token
);
3576 ltime (time_sec
, time_usec
)
3577 long time_sec
, time_usec
;
3579 return list3 (make_number ((time_sec
>> 16) & 0xffff),
3580 make_number (time_sec
& 0xffff),
3581 make_number (time_usec
));
3585 process_times (h_proc
, ctime
, etime
, stime
, utime
, pcpu
)
3587 Lisp_Object
*ctime
, *etime
, *stime
, *utime
;
3590 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
3591 long ctime_sec
, ctime_usec
, stime_sec
, stime_usec
, utime_sec
, utime_usec
;
3592 long etime_sec
, etime_usec
;
3593 long double tem1
, tem2
, tem
;
3596 || !get_process_times_fn
3597 || !(*get_process_times_fn
)(h_proc
, &ft_creation
, &ft_exit
,
3598 &ft_kernel
, &ft_user
))
3601 GetSystemTimeAsFileTime (&ft_current
);
3603 tem1
= convert_time_raw (ft_kernel
) * 0.1L;
3604 stime_usec
= fmodl (tem1
, 1000000.0L);
3605 stime_sec
= tem1
* 0.000001L;
3606 *stime
= ltime (stime_sec
, stime_usec
);
3607 tem2
= convert_time_raw (ft_user
) * 0.1L;
3608 utime_usec
= fmodl (tem2
, 1000000.0L);
3609 utime_sec
= tem2
* 0.000001L;
3610 *utime
= ltime (utime_sec
, utime_usec
);
3611 tem
= convert_time_raw (ft_creation
);
3612 /* Process no 4 (System) returns zero creation time. */
3614 tem
= (tem
- utc_base
) * 0.1;
3615 ctime_usec
= fmodl (tem
, 1000000.0L);
3616 ctime_sec
= tem
* 0.000001L;
3617 *ctime
= ltime (ctime_sec
, ctime_usec
);
3619 tem
= (convert_time_raw (ft_current
) - utc_base
) * 0.1L - tem
;
3620 etime_usec
= fmodl (tem
, 1000000.0L);
3621 etime_sec
= tem
* 0.000001L;
3622 *etime
= ltime (etime_sec
, etime_usec
);
3626 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
3637 w32_system_process_attributes (pid
)
3640 struct gcpro gcpro1
, gcpro2
, gcpro3
;
3641 Lisp_Object attrs
= Qnil
;
3642 Lisp_Object cmd_str
, decoded_cmd
, tem
;
3643 HANDLE h_snapshot
, h_proc
;
3646 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
3647 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), trash
;
3648 DWORD glength
= sizeof (gname
);
3649 HANDLE token
= NULL
;
3650 SID_NAME_USE user_type
;
3651 unsigned char buf
[1024];
3652 TOKEN_USER user_token
;
3653 TOKEN_PRIMARY_GROUP group_token
;
3657 PROCESS_MEMORY_COUNTERS mem
;
3658 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
3659 DWORD minrss
, maxrss
;
3661 MEMORYSTATUSEX memstex
;
3662 double totphys
= 0.0;
3663 Lisp_Object ctime
, stime
, utime
, etime
;
3666 CHECK_NUMBER_OR_FLOAT (pid
);
3667 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
3669 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3671 GCPRO3 (attrs
, decoded_cmd
, tem
);
3673 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3678 pe
.dwSize
= sizeof (PROCESSENTRY32
);
3679 for (res
= process32_first (h_snapshot
, &pe
); res
;
3680 res
= process32_next (h_snapshot
, &pe
))
3682 if (proc_id
== pe
.th32ProcessID
)
3685 decoded_cmd
= build_string ("Idle");
3688 /* Decode the command name from locale-specific
3690 cmd_str
= make_unibyte_string (pe
.szExeFile
,
3691 strlen (pe
.szExeFile
));
3693 code_convert_string_norecord (cmd_str
,
3694 Vlocale_coding_system
, 0);
3696 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
3697 attrs
= Fcons (Fcons (Qppid
,
3698 make_fixnum_or_float (pe
.th32ParentProcessID
)),
3700 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
3702 attrs
= Fcons (Fcons (Qthcount
,
3703 make_fixnum_or_float (pe
.cntThreads
)),
3710 CloseHandle (h_snapshot
);
3719 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
3721 /* If we were denied a handle to the process, try again after
3722 enabling the SeDebugPrivilege in our process. */
3725 TOKEN_PRIVILEGES priv_current
;
3727 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
3729 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
3731 restore_privilege (&priv_current
);
3736 && open_process_token (h_proc
, TOKEN_QUERY
, &token
)
3737 && get_token_information (token
, TokenUser
,
3738 (PVOID
)buf
, sizeof (buf
), &trash
)
3739 && (memcpy (&user_token
, buf
, sizeof (user_token
)),
3740 lookup_account_sid (NULL
, user_token
.User
.Sid
, uname
, &ulength
,
3741 domain
, &dlength
, &user_type
)))
3743 /* Determine a reasonable euid and gid values. */
3744 if (xstrcasecmp ("administrator", uname
) == 0)
3746 euid
= 500; /* well-known Administrator uid */
3747 egid
= 513; /* well-known None gid */
3751 /* Use the last sub-authority value of the RID, the relative
3752 portion of the SID, as user/group ID. */
3753 euid
= get_rid (user_token
.User
.Sid
);
3755 /* Get group id and name. */
3756 if (get_token_information (token
, TokenPrimaryGroup
,
3757 (PVOID
)buf
, sizeof (buf
), &trash
))
3759 memcpy (&group_token
, buf
, sizeof (group_token
));
3760 egid
= get_rid (group_token
.PrimaryGroup
);
3761 dlength
= sizeof (domain
);
3762 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
3763 gname
, &glength
, NULL
, &dlength
,
3770 else if (!is_windows_9x ())
3772 /* We couldn't open the process token, presumably because of
3773 insufficient access rights. Assume this process is run by
3775 strcpy (uname
, "SYSTEM");
3776 strcpy (gname
, "None");
3777 euid
= 18; /* SYSTEM */
3778 egid
= 513; /* None */
3779 glength
= strlen (gname
);
3780 ulength
= strlen (uname
);
3782 /* If we are running under Windows 9X, where security calls are not
3783 supported, we assume all processes are run by the current
3785 else if (GetUserName (uname
, &ulength
))
3787 if (xstrcasecmp ("administrator", uname
) == 0)
3792 strcpy (gname
, "None");
3793 glength
= strlen (gname
);
3794 ulength
= strlen (uname
);
3800 strcpy (uname
, "administrator");
3801 ulength
= strlen (uname
);
3802 strcpy (gname
, "None");
3803 glength
= strlen (gname
);
3806 CloseHandle (token
);
3808 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
3809 tem
= make_unibyte_string (uname
, ulength
);
3810 attrs
= Fcons (Fcons (Quser
,
3811 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
3813 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
3814 tem
= make_unibyte_string (gname
, glength
);
3815 attrs
= Fcons (Fcons (Qgroup
,
3816 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
3819 if (global_memory_status_ex (&memstex
))
3820 totphys
= memstex
.ullTotalPhys
/ 1024.0;
3821 else if (global_memory_status (&memst
))
3822 totphys
= memst
.dwTotalPhys
/ 1024.0;
3825 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
3828 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
3830 attrs
= Fcons (Fcons (Qmajflt
,
3831 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
3833 attrs
= Fcons (Fcons (Qvsize
,
3834 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
3836 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
3838 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
3841 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
3843 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
3845 attrs
= Fcons (Fcons (Qmajflt
,
3846 make_fixnum_or_float (mem
.PageFaultCount
)),
3848 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
3850 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
3853 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
3855 DWORD rss
= maxrss
/ 1024;
3857 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
3859 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
3862 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &pcpu
))
3864 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
3865 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
3866 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
3867 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
3868 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
3871 /* FIXME: Retrieve command line by walking the PEB of the process. */
3874 CloseHandle (h_proc
);
3882 /* Wrappers for winsock functions to map between our file descriptors
3883 and winsock's handles; also set h_errno for convenience.
3885 To allow Emacs to run on systems which don't have winsock support
3886 installed, we dynamically link to winsock on startup if present, and
3887 otherwise provide the minimum necessary functionality
3888 (eg. gethostname). */
3890 /* function pointers for relevant socket functions */
3891 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
3892 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
3893 int (PASCAL
*pfn_WSAGetLastError
) (void);
3894 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
3895 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
3896 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
3897 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
3898 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
3899 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
3900 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
3901 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
3902 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
3903 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
3904 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
3905 int (PASCAL
*pfn_WSACleanup
) (void);
3907 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
3908 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
3909 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
3910 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
3911 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
3912 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
3913 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
3914 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
3915 const char * optval
, int optlen
);
3916 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
3917 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
3919 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
3920 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
3921 struct sockaddr
* from
, int * fromlen
);
3922 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
3923 const struct sockaddr
* to
, int tolen
);
3925 /* SetHandleInformation is only needed to make sockets non-inheritable. */
3926 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
3927 #ifndef HANDLE_FLAG_INHERIT
3928 #define HANDLE_FLAG_INHERIT 1
3932 static int winsock_inuse
;
3937 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
3939 /* Not sure what would cause WSAENETDOWN, or even if it can happen
3940 after WSAStartup returns successfully, but it seems reasonable
3941 to allow unloading winsock anyway in that case. */
3942 if (pfn_WSACleanup () == 0 ||
3943 pfn_WSAGetLastError () == WSAENETDOWN
)
3945 if (FreeLibrary (winsock_lib
))
3954 init_winsock (int load_now
)
3956 WSADATA winsockData
;
3958 if (winsock_lib
!= NULL
)
3961 pfn_SetHandleInformation
= NULL
;
3962 pfn_SetHandleInformation
3963 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
3964 "SetHandleInformation");
3966 winsock_lib
= LoadLibrary ("Ws2_32.dll");
3968 if (winsock_lib
!= NULL
)
3970 /* dynamically link to socket functions */
3972 #define LOAD_PROC(fn) \
3973 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
3976 LOAD_PROC( WSAStartup
);
3977 LOAD_PROC( WSASetLastError
);
3978 LOAD_PROC( WSAGetLastError
);
3979 LOAD_PROC( WSAEventSelect
);
3980 LOAD_PROC( WSACreateEvent
);
3981 LOAD_PROC( WSACloseEvent
);
3982 LOAD_PROC( socket
);
3984 LOAD_PROC( connect
);
3985 LOAD_PROC( ioctlsocket
);
3988 LOAD_PROC( closesocket
);
3989 LOAD_PROC( shutdown
);
3992 LOAD_PROC( inet_addr
);
3993 LOAD_PROC( gethostname
);
3994 LOAD_PROC( gethostbyname
);
3995 LOAD_PROC( getservbyname
);
3996 LOAD_PROC( getpeername
);
3997 LOAD_PROC( WSACleanup
);
3998 LOAD_PROC( setsockopt
);
3999 LOAD_PROC( listen
);
4000 LOAD_PROC( getsockname
);
4001 LOAD_PROC( accept
);
4002 LOAD_PROC( recvfrom
);
4003 LOAD_PROC( sendto
);
4006 /* specify version 1.1 of winsock */
4007 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4009 if (winsockData
.wVersion
!= 0x101)
4014 /* Report that winsock exists and is usable, but leave
4015 socket functions disabled. I am assuming that calling
4016 WSAStartup does not require any network interaction,
4017 and in particular does not cause or require a dial-up
4018 connection to be established. */
4021 FreeLibrary (winsock_lib
);
4029 FreeLibrary (winsock_lib
);
4039 /* function to set h_errno for compatibility; map winsock error codes to
4040 normal system codes where they overlap (non-overlapping definitions
4041 are already in <sys/socket.h> */
4045 if (winsock_lib
== NULL
)
4048 h_errno
= pfn_WSAGetLastError ();
4052 case WSAEACCES
: h_errno
= EACCES
; break;
4053 case WSAEBADF
: h_errno
= EBADF
; break;
4054 case WSAEFAULT
: h_errno
= EFAULT
; break;
4055 case WSAEINTR
: h_errno
= EINTR
; break;
4056 case WSAEINVAL
: h_errno
= EINVAL
; break;
4057 case WSAEMFILE
: h_errno
= EMFILE
; break;
4058 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4059 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4067 if (h_errno
== 0 && winsock_lib
!= NULL
)
4068 pfn_WSASetLastError (0);
4071 /* Extend strerror to handle the winsock-specific error codes. */
4075 } _wsa_errlist
[] = {
4076 WSAEINTR
, "Interrupted function call",
4077 WSAEBADF
, "Bad file descriptor",
4078 WSAEACCES
, "Permission denied",
4079 WSAEFAULT
, "Bad address",
4080 WSAEINVAL
, "Invalid argument",
4081 WSAEMFILE
, "Too many open files",
4083 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
4084 WSAEINPROGRESS
, "Operation now in progress",
4085 WSAEALREADY
, "Operation already in progress",
4086 WSAENOTSOCK
, "Socket operation on non-socket",
4087 WSAEDESTADDRREQ
, "Destination address required",
4088 WSAEMSGSIZE
, "Message too long",
4089 WSAEPROTOTYPE
, "Protocol wrong type for socket",
4090 WSAENOPROTOOPT
, "Bad protocol option",
4091 WSAEPROTONOSUPPORT
, "Protocol not supported",
4092 WSAESOCKTNOSUPPORT
, "Socket type not supported",
4093 WSAEOPNOTSUPP
, "Operation not supported",
4094 WSAEPFNOSUPPORT
, "Protocol family not supported",
4095 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
4096 WSAEADDRINUSE
, "Address already in use",
4097 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
4098 WSAENETDOWN
, "Network is down",
4099 WSAENETUNREACH
, "Network is unreachable",
4100 WSAENETRESET
, "Network dropped connection on reset",
4101 WSAECONNABORTED
, "Software caused connection abort",
4102 WSAECONNRESET
, "Connection reset by peer",
4103 WSAENOBUFS
, "No buffer space available",
4104 WSAEISCONN
, "Socket is already connected",
4105 WSAENOTCONN
, "Socket is not connected",
4106 WSAESHUTDOWN
, "Cannot send after socket shutdown",
4107 WSAETOOMANYREFS
, "Too many references", /* not sure */
4108 WSAETIMEDOUT
, "Connection timed out",
4109 WSAECONNREFUSED
, "Connection refused",
4110 WSAELOOP
, "Network loop", /* not sure */
4111 WSAENAMETOOLONG
, "Name is too long",
4112 WSAEHOSTDOWN
, "Host is down",
4113 WSAEHOSTUNREACH
, "No route to host",
4114 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
4115 WSAEPROCLIM
, "Too many processes",
4116 WSAEUSERS
, "Too many users", /* not sure */
4117 WSAEDQUOT
, "Double quote in host name", /* really not sure */
4118 WSAESTALE
, "Data is stale", /* not sure */
4119 WSAEREMOTE
, "Remote error", /* not sure */
4121 WSASYSNOTREADY
, "Network subsystem is unavailable",
4122 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
4123 WSANOTINITIALISED
, "Winsock not initialized successfully",
4124 WSAEDISCON
, "Graceful shutdown in progress",
4126 WSAENOMORE
, "No more operations allowed", /* not sure */
4127 WSAECANCELLED
, "Operation cancelled", /* not sure */
4128 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
4129 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
4130 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
4131 WSASYSCALLFAILURE
, "System call failure",
4132 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
4133 WSATYPE_NOT_FOUND
, "Class type not found",
4134 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
4135 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
4136 WSAEREFUSED
, "Operation refused", /* not sure */
4139 WSAHOST_NOT_FOUND
, "Host not found",
4140 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
4141 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
4142 WSANO_DATA
, "Valid name, no data record of requested type",
4148 sys_strerror(int error_no
)
4151 static char unknown_msg
[40];
4153 if (error_no
>= 0 && error_no
< sys_nerr
)
4154 return sys_errlist
[error_no
];
4156 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4157 if (_wsa_errlist
[i
].errnum
== error_no
)
4158 return _wsa_errlist
[i
].msg
;
4160 sprintf(unknown_msg
, "Unidentified error: %d", error_no
);
4164 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4165 but I believe the method of keeping the socket handle separate (and
4166 insuring it is not inheritable) is the correct one. */
4168 //#define SOCK_REPLACE_HANDLE
4170 #ifdef SOCK_REPLACE_HANDLE
4171 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
4173 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4176 int socket_to_fd (SOCKET s
);
4179 sys_socket(int af
, int type
, int protocol
)
4183 if (winsock_lib
== NULL
)
4186 return INVALID_SOCKET
;
4191 /* call the real socket function */
4192 s
= pfn_socket (af
, type
, protocol
);
4194 if (s
!= INVALID_SOCKET
)
4195 return socket_to_fd (s
);
4201 /* Convert a SOCKET to a file descriptor. */
4203 socket_to_fd (SOCKET s
)
4208 /* Although under NT 3.5 _open_osfhandle will accept a socket
4209 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4210 that does not work under NT 3.1. However, we can get the same
4211 effect by using a backdoor function to replace an existing
4212 descriptor handle with the one we want. */
4214 /* allocate a file descriptor (with appropriate flags) */
4215 fd
= _open ("NUL:", _O_RDWR
);
4218 #ifdef SOCK_REPLACE_HANDLE
4219 /* now replace handle to NUL with our socket handle */
4220 CloseHandle ((HANDLE
) _get_osfhandle (fd
));
4222 _set_osfhnd (fd
, s
);
4223 /* setmode (fd, _O_BINARY); */
4225 /* Make a non-inheritable copy of the socket handle. Note
4226 that it is possible that sockets aren't actually kernel
4227 handles, which appears to be the case on Windows 9x when
4228 the MS Proxy winsock client is installed. */
4230 /* Apparently there is a bug in NT 3.51 with some service
4231 packs, which prevents using DuplicateHandle to make a
4232 socket handle non-inheritable (causes WSACleanup to
4233 hang). The work-around is to use SetHandleInformation
4234 instead if it is available and implemented. */
4235 if (pfn_SetHandleInformation
)
4237 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4241 HANDLE parent
= GetCurrentProcess ();
4242 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4244 if (DuplicateHandle (parent
,
4250 DUPLICATE_SAME_ACCESS
))
4252 /* It is possible that DuplicateHandle succeeds even
4253 though the socket wasn't really a kernel handle,
4254 because a real handle has the same value. So
4255 test whether the new handle really is a socket. */
4256 long nonblocking
= 0;
4257 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4259 pfn_closesocket (s
);
4264 CloseHandle (new_s
);
4269 fd_info
[fd
].hnd
= (HANDLE
) s
;
4272 /* set our own internal flags */
4273 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4279 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4281 /* attach child_process to fd_info */
4282 if (fd_info
[ fd
].cp
!= NULL
)
4284 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4288 fd_info
[ fd
].cp
= cp
;
4291 winsock_inuse
++; /* count open sockets */
4298 pfn_closesocket (s
);
4305 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4307 if (winsock_lib
== NULL
)
4310 return SOCKET_ERROR
;
4314 if (fd_info
[s
].flags
& FILE_SOCKET
)
4316 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4317 if (rc
== SOCKET_ERROR
)
4322 return SOCKET_ERROR
;
4327 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4329 if (winsock_lib
== NULL
)
4332 return SOCKET_ERROR
;
4336 if (fd_info
[s
].flags
& FILE_SOCKET
)
4338 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4339 if (rc
== SOCKET_ERROR
)
4344 return SOCKET_ERROR
;
4348 sys_htons (u_short hostshort
)
4350 return (winsock_lib
!= NULL
) ?
4351 pfn_htons (hostshort
) : hostshort
;
4355 sys_ntohs (u_short netshort
)
4357 return (winsock_lib
!= NULL
) ?
4358 pfn_ntohs (netshort
) : netshort
;
4362 sys_inet_addr (const char * cp
)
4364 return (winsock_lib
!= NULL
) ?
4365 pfn_inet_addr (cp
) : INADDR_NONE
;
4369 sys_gethostname (char * name
, int namelen
)
4371 if (winsock_lib
!= NULL
)
4372 return pfn_gethostname (name
, namelen
);
4374 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4375 return !GetComputerName (name
, (DWORD
*)&namelen
);
4378 return SOCKET_ERROR
;
4382 sys_gethostbyname(const char * name
)
4384 struct hostent
* host
;
4386 if (winsock_lib
== NULL
)
4393 host
= pfn_gethostbyname (name
);
4400 sys_getservbyname(const char * name
, const char * proto
)
4402 struct servent
* serv
;
4404 if (winsock_lib
== NULL
)
4411 serv
= pfn_getservbyname (name
, proto
);
4418 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4420 if (winsock_lib
== NULL
)
4423 return SOCKET_ERROR
;
4427 if (fd_info
[s
].flags
& FILE_SOCKET
)
4429 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4430 if (rc
== SOCKET_ERROR
)
4435 return SOCKET_ERROR
;
4440 sys_shutdown (int s
, int how
)
4442 if (winsock_lib
== NULL
)
4445 return SOCKET_ERROR
;
4449 if (fd_info
[s
].flags
& FILE_SOCKET
)
4451 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4452 if (rc
== SOCKET_ERROR
)
4457 return SOCKET_ERROR
;
4461 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4463 if (winsock_lib
== NULL
)
4466 return SOCKET_ERROR
;
4470 if (fd_info
[s
].flags
& FILE_SOCKET
)
4472 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4473 (const char *)optval
, optlen
);
4474 if (rc
== SOCKET_ERROR
)
4479 return SOCKET_ERROR
;
4483 sys_listen (int s
, int backlog
)
4485 if (winsock_lib
== NULL
)
4488 return SOCKET_ERROR
;
4492 if (fd_info
[s
].flags
& FILE_SOCKET
)
4494 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4495 if (rc
== SOCKET_ERROR
)
4498 fd_info
[s
].flags
|= FILE_LISTEN
;
4502 return SOCKET_ERROR
;
4506 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4508 if (winsock_lib
== NULL
)
4511 return SOCKET_ERROR
;
4515 if (fd_info
[s
].flags
& FILE_SOCKET
)
4517 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4518 if (rc
== SOCKET_ERROR
)
4523 return SOCKET_ERROR
;
4527 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
4529 if (winsock_lib
== NULL
)
4536 if (fd_info
[s
].flags
& FILE_LISTEN
)
4538 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
4540 if (t
== INVALID_SOCKET
)
4543 fd
= socket_to_fd (t
);
4545 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4546 ResetEvent (fd_info
[s
].cp
->char_avail
);
4554 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
4555 struct sockaddr
* from
, int * fromlen
)
4557 if (winsock_lib
== NULL
)
4560 return SOCKET_ERROR
;
4564 if (fd_info
[s
].flags
& FILE_SOCKET
)
4566 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
4567 if (rc
== SOCKET_ERROR
)
4572 return SOCKET_ERROR
;
4576 sys_sendto (int s
, const char * buf
, int len
, int flags
,
4577 const struct sockaddr
* to
, int tolen
)
4579 if (winsock_lib
== NULL
)
4582 return SOCKET_ERROR
;
4586 if (fd_info
[s
].flags
& FILE_SOCKET
)
4588 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
4589 if (rc
== SOCKET_ERROR
)
4594 return SOCKET_ERROR
;
4597 /* Windows does not have an fcntl function. Provide an implementation
4598 solely for making sockets non-blocking. */
4600 fcntl (int s
, int cmd
, int options
)
4602 if (winsock_lib
== NULL
)
4609 if (fd_info
[s
].flags
& FILE_SOCKET
)
4611 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
4613 unsigned long nblock
= 1;
4614 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
4615 if (rc
== SOCKET_ERROR
)
4617 /* Keep track of the fact that we set this to non-blocking. */
4618 fd_info
[s
].flags
|= FILE_NDELAY
;
4624 return SOCKET_ERROR
;
4628 return SOCKET_ERROR
;
4631 #endif /* HAVE_SOCKETS */
4634 /* Shadow main io functions: we need to handle pipes and sockets more
4635 intelligently, and implement non-blocking mode as well. */
4648 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
4650 child_process
* cp
= fd_info
[fd
].cp
;
4652 fd_info
[fd
].cp
= NULL
;
4654 if (CHILD_ACTIVE (cp
))
4656 /* if last descriptor to active child_process then cleanup */
4658 for (i
= 0; i
< MAXDESC
; i
++)
4662 if (fd_info
[i
].cp
== cp
)
4668 if (fd_info
[fd
].flags
& FILE_SOCKET
)
4670 #ifndef SOCK_REPLACE_HANDLE
4671 if (winsock_lib
== NULL
) abort ();
4673 pfn_shutdown (SOCK_HANDLE (fd
), 2);
4674 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
4676 winsock_inuse
--; /* count open sockets */
4684 /* Note that sockets do not need special treatment here (at least on
4685 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
4686 closesocket is equivalent to CloseHandle, which is to be expected
4687 because socket handles are fully fledged kernel handles. */
4690 if (rc
== 0 && fd
< MAXDESC
)
4691 fd_info
[fd
].flags
= 0;
4702 if (new_fd
>= 0 && new_fd
< MAXDESC
)
4704 /* duplicate our internal info as well */
4705 fd_info
[new_fd
] = fd_info
[fd
];
4712 sys_dup2 (int src
, int dst
)
4716 if (dst
< 0 || dst
>= MAXDESC
)
4722 /* make sure we close the destination first if it's a pipe or socket */
4723 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
4726 rc
= _dup2 (src
, dst
);
4729 /* duplicate our internal info as well */
4730 fd_info
[dst
] = fd_info
[src
];
4735 /* Unix pipe() has only one arg */
4737 sys_pipe (int * phandles
)
4742 /* make pipe handles non-inheritable; when we spawn a child, we
4743 replace the relevant handle with an inheritable one. Also put
4744 pipes into binary mode; we will do text mode translation ourselves
4746 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
4750 /* Protect against overflow, since Windows can open more handles than
4751 our fd_info array has room for. */
4752 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
4754 _close (phandles
[0]);
4755 _close (phandles
[1]);
4760 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
4761 fd_info
[phandles
[0]].flags
= flags
;
4763 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
4764 fd_info
[phandles
[1]].flags
= flags
;
4772 extern int w32_pipe_read_delay
;
4774 /* Function to do blocking read of one byte, needed to implement
4775 select. It is only allowed on sockets and pipes. */
4777 _sys_read_ahead (int fd
)
4782 if (fd
< 0 || fd
>= MAXDESC
)
4783 return STATUS_READ_ERROR
;
4785 cp
= fd_info
[fd
].cp
;
4787 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
4788 return STATUS_READ_ERROR
;
4790 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
4791 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
4793 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
4797 cp
->status
= STATUS_READ_IN_PROGRESS
;
4799 if (fd_info
[fd
].flags
& FILE_PIPE
)
4801 rc
= _read (fd
, &cp
->chr
, sizeof (char));
4803 /* Give subprocess time to buffer some more output for us before
4804 reporting that input is available; we need this because Windows 95
4805 connects DOS programs to pipes by making the pipe appear to be
4806 the normal console stdout - as a result most DOS programs will
4807 write to stdout without buffering, ie. one character at a
4808 time. Even some W32 programs do this - "dir" in a command
4809 shell on NT is very slow if we don't do this. */
4812 int wait
= w32_pipe_read_delay
;
4818 /* Yield remainder of our time slice, effectively giving a
4819 temporary priority boost to the child process. */
4823 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
4825 HANDLE hnd
= fd_info
[fd
].hnd
;
4826 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
4829 /* Configure timeouts for blocking read. */
4830 if (!GetCommTimeouts (hnd
, &ct
))
4831 return STATUS_READ_ERROR
;
4832 ct
.ReadIntervalTimeout
= 0;
4833 ct
.ReadTotalTimeoutMultiplier
= 0;
4834 ct
.ReadTotalTimeoutConstant
= 0;
4835 if (!SetCommTimeouts (hnd
, &ct
))
4836 return STATUS_READ_ERROR
;
4838 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
4840 if (GetLastError () != ERROR_IO_PENDING
)
4841 return STATUS_READ_ERROR
;
4842 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
4843 return STATUS_READ_ERROR
;
4847 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
4849 unsigned long nblock
= 0;
4850 /* We always want this to block, so temporarily disable NDELAY. */
4851 if (fd_info
[fd
].flags
& FILE_NDELAY
)
4852 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
4854 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
4856 if (fd_info
[fd
].flags
& FILE_NDELAY
)
4859 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
4864 if (rc
== sizeof (char))
4865 cp
->status
= STATUS_READ_SUCCEEDED
;
4867 cp
->status
= STATUS_READ_FAILED
;
4873 _sys_wait_accept (int fd
)
4879 if (fd
< 0 || fd
>= MAXDESC
)
4880 return STATUS_READ_ERROR
;
4882 cp
= fd_info
[fd
].cp
;
4884 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
4885 return STATUS_READ_ERROR
;
4887 cp
->status
= STATUS_READ_FAILED
;
4889 hEv
= pfn_WSACreateEvent ();
4890 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
4891 if (rc
!= SOCKET_ERROR
)
4893 rc
= WaitForSingleObject (hEv
, INFINITE
);
4894 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
4895 if (rc
== WAIT_OBJECT_0
)
4896 cp
->status
= STATUS_READ_SUCCEEDED
;
4898 pfn_WSACloseEvent (hEv
);
4904 sys_read (int fd
, char * buffer
, unsigned int count
)
4909 char * orig_buffer
= buffer
;
4917 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
4919 child_process
*cp
= fd_info
[fd
].cp
;
4921 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
4929 /* re-read CR carried over from last read */
4930 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
4932 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
4936 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
4939 /* presence of a child_process structure means we are operating in
4940 non-blocking mode - otherwise we just call _read directly.
4941 Note that the child_process structure might be missing because
4942 reap_subprocess has been called; in this case the pipe is
4943 already broken, so calling _read on it is okay. */
4946 int current_status
= cp
->status
;
4948 switch (current_status
)
4950 case STATUS_READ_FAILED
:
4951 case STATUS_READ_ERROR
:
4952 /* report normal EOF if nothing in buffer */
4954 fd_info
[fd
].flags
|= FILE_AT_EOF
;
4957 case STATUS_READ_READY
:
4958 case STATUS_READ_IN_PROGRESS
:
4959 DebPrint (("sys_read called when read is in progress\n"));
4960 errno
= EWOULDBLOCK
;
4963 case STATUS_READ_SUCCEEDED
:
4964 /* consume read-ahead char */
4965 *buffer
++ = cp
->chr
;
4968 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4969 ResetEvent (cp
->char_avail
);
4971 case STATUS_READ_ACKNOWLEDGED
:
4975 DebPrint (("sys_read: bad status %d\n", current_status
));
4980 if (fd_info
[fd
].flags
& FILE_PIPE
)
4982 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
4983 to_read
= min (waiting
, (DWORD
) count
);
4986 nchars
+= _read (fd
, buffer
, to_read
);
4988 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
4990 HANDLE hnd
= fd_info
[fd
].hnd
;
4991 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
4998 /* Configure timeouts for non-blocking read. */
4999 if (!GetCommTimeouts (hnd
, &ct
))
5004 ct
.ReadIntervalTimeout
= MAXDWORD
;
5005 ct
.ReadTotalTimeoutMultiplier
= 0;
5006 ct
.ReadTotalTimeoutConstant
= 0;
5007 if (!SetCommTimeouts (hnd
, &ct
))
5013 if (!ResetEvent (ovl
->hEvent
))
5018 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5020 if (GetLastError () != ERROR_IO_PENDING
)
5025 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5035 else /* FILE_SOCKET */
5037 if (winsock_lib
== NULL
) abort ();
5039 /* do the equivalent of a non-blocking read */
5040 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5041 if (waiting
== 0 && nchars
== 0)
5043 h_errno
= errno
= EWOULDBLOCK
;
5049 /* always use binary mode for sockets */
5050 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5051 if (res
== SOCKET_ERROR
)
5053 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
5054 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5065 int nread
= _read (fd
, buffer
, count
);
5068 else if (nchars
== 0)
5073 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5074 /* Perform text mode translation if required. */
5075 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5077 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5078 /* If buffer contains only CR, return that. To be absolutely
5079 sure we should attempt to read the next char, but in
5080 practice a CR to be followed by LF would not appear by
5081 itself in the buffer. */
5082 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5084 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5090 nchars
= _read (fd
, buffer
, count
);
5095 /* From w32xfns.c */
5096 extern HANDLE interrupt_handle
;
5098 /* For now, don't bother with a non-blocking mode */
5100 sys_write (int fd
, const void * buffer
, unsigned int count
)
5110 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5112 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5118 /* Perform text mode translation if required. */
5119 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5121 char * tmpbuf
= alloca (count
* 2);
5122 unsigned char * src
= (void *)buffer
;
5123 unsigned char * dst
= tmpbuf
;
5128 unsigned char *next
;
5129 /* copy next line or remaining bytes */
5130 next
= _memccpy (dst
, src
, '\n', nbytes
);
5133 /* copied one line ending with '\n' */
5134 int copied
= next
- dst
;
5137 /* insert '\r' before '\n' */
5144 /* copied remaining partial line -> now finished */
5151 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5153 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5154 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5155 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5158 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5160 if (GetLastError () != ERROR_IO_PENDING
)
5165 if (detect_input_pending ())
5166 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5169 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5170 if (active
== WAIT_OBJECT_0
)
5171 { /* User pressed C-g, cancel write, then leave. Don't bother
5172 cleaning up as we may only get stuck in buggy drivers. */
5173 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5178 if (active
== WAIT_OBJECT_0
+ 1
5179 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5188 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5190 unsigned long nblock
= 0;
5191 if (winsock_lib
== NULL
) abort ();
5193 /* TODO: implement select() properly so non-blocking I/O works. */
5194 /* For now, make sure the write blocks. */
5195 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5196 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5198 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5200 /* Set the socket back to non-blocking if it was before,
5201 for other operations that support it. */
5202 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5205 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5208 if (nchars
== SOCKET_ERROR
)
5210 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
5211 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5217 nchars
= _write (fd
, buffer
, count
);
5223 check_windows_init_file ()
5225 extern int noninteractive
, inhibit_window_system
;
5227 /* A common indication that Emacs is not installed properly is when
5228 it cannot find the Windows installation file. If this file does
5229 not exist in the expected place, tell the user. */
5231 if (!noninteractive
&& !inhibit_window_system
)
5233 extern Lisp_Object Vwindow_system
, Vload_path
, Qfile_exists_p
;
5234 Lisp_Object objs
[2];
5235 Lisp_Object full_load_path
;
5236 Lisp_Object init_file
;
5239 objs
[0] = Vload_path
;
5240 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5241 full_load_path
= Fappend (2, objs
);
5242 init_file
= build_string ("term/w32-win");
5243 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5246 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5247 char *init_file_name
= SDATA (init_file
);
5248 char *load_path
= SDATA (load_path_print
);
5249 char *buffer
= alloca (1024
5250 + strlen (init_file_name
)
5251 + strlen (load_path
));
5254 "The Emacs Windows initialization file \"%s.el\" "
5255 "could not be found in your Emacs installation. "
5256 "Emacs checked the following directories for this file:\n"
5258 "When Emacs cannot find this file, it usually means that it "
5259 "was not installed properly, or its distribution file was "
5260 "not unpacked properly.\nSee the README.W32 file in the "
5261 "top-level Emacs directory for more information.",
5262 init_file_name
, load_path
);
5265 "Emacs Abort Dialog",
5266 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5267 /* Use the low-level Emacs abort. */
5282 /* shutdown the socket interface if necessary */
5293 /* Initialise the socket interface now if available and requested by
5294 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5295 delayed until open-network-stream is called (w32-has-winsock can
5296 also be used to dynamically load or reload winsock).
5298 Conveniently, init_environment is called before us, so
5299 PRELOAD_WINSOCK can be set in the registry. */
5301 /* Always initialize this correctly. */
5304 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5305 init_winsock (TRUE
);
5308 /* Initial preparation for subprocess support: replace our standard
5309 handles with non-inheritable versions. */
5312 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5313 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5314 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5316 parent
= GetCurrentProcess ();
5318 /* ignore errors when duplicating and closing; typically the
5319 handles will be invalid when running as a gui program. */
5320 DuplicateHandle (parent
,
5321 GetStdHandle (STD_INPUT_HANDLE
),
5326 DUPLICATE_SAME_ACCESS
);
5328 DuplicateHandle (parent
,
5329 GetStdHandle (STD_OUTPUT_HANDLE
),
5334 DUPLICATE_SAME_ACCESS
);
5336 DuplicateHandle (parent
,
5337 GetStdHandle (STD_ERROR_HANDLE
),
5342 DUPLICATE_SAME_ACCESS
);
5348 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5349 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5351 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5354 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5355 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5357 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5360 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5361 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5363 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5367 /* unfortunately, atexit depends on implementation of malloc */
5368 /* atexit (term_ntproc); */
5369 signal (SIGABRT
, term_ntproc
);
5371 /* determine which drives are fixed, for GetCachedVolumeInformation */
5373 /* GetDriveType must have trailing backslash. */
5374 char drive
[] = "A:\\";
5376 /* Loop over all possible drive letters */
5377 while (*drive
<= 'Z')
5379 /* Record if this drive letter refers to a fixed drive. */
5380 fixed_drives
[DRIVE_INDEX (*drive
)] =
5381 (GetDriveType (drive
) == DRIVE_FIXED
);
5386 /* Reset the volume info cache. */
5387 volume_cache
= NULL
;
5390 /* Check to see if Emacs has been installed correctly. */
5391 check_windows_init_file ();
5395 shutdown_handler ensures that buffers' autosave files are
5396 up to date when the user logs off, or the system shuts down.
5398 BOOL WINAPI
shutdown_handler(DWORD type
)
5400 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5401 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5402 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5403 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5405 /* Shut down cleanly, making sure autosave files are up to date. */
5406 shut_down_emacs (0, 0, Qnil
);
5409 /* Allow other handlers to handle this signal. */
5414 globals_of_w32 is used to initialize those global variables that
5415 must always be initialized on startup even when the global variable
5416 initialized is non zero (see the function main in emacs.c).
5421 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5423 get_process_times_fn
= (GetProcessTimes_Proc
)
5424 GetProcAddress (kernel32
, "GetProcessTimes");
5426 g_b_init_is_windows_9x
= 0;
5427 g_b_init_open_process_token
= 0;
5428 g_b_init_get_token_information
= 0;
5429 g_b_init_lookup_account_sid
= 0;
5430 g_b_init_get_sid_identifier_authority
= 0;
5431 g_b_init_get_sid_sub_authority
= 0;
5432 g_b_init_get_sid_sub_authority_count
= 0;
5433 g_b_init_get_file_security
= 0;
5434 g_b_init_get_security_descriptor_owner
= 0;
5435 g_b_init_get_security_descriptor_group
= 0;
5436 g_b_init_is_valid_sid
= 0;
5437 g_b_init_create_toolhelp32_snapshot
= 0;
5438 g_b_init_process32_first
= 0;
5439 g_b_init_process32_next
= 0;
5440 g_b_init_open_thread_token
= 0;
5441 g_b_init_impersonate_self
= 0;
5442 g_b_init_revert_to_self
= 0;
5443 g_b_init_get_process_memory_info
= 0;
5444 g_b_init_get_process_working_set_size
= 0;
5445 g_b_init_global_memory_status
= 0;
5446 g_b_init_global_memory_status_ex
= 0;
5447 /* The following sets a handler for shutdown notifications for
5448 console apps. This actually applies to Emacs in both console and
5449 GUI modes, since we had to fool windows into thinking emacs is a
5450 console application to get console mode to work. */
5451 SetConsoleCtrlHandler(shutdown_handler
, TRUE
);
5453 /* "None" is the default group name on standalone workstations. */
5454 strcpy (dflt_group_name
, "None");
5457 /* For make-serial-process */
5458 int serial_open (char *port
)
5464 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5465 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5466 if (hnd
== INVALID_HANDLE_VALUE
)
5467 error ("Could not open %s", port
);
5468 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5470 error ("Could not open %s", port
);
5474 error ("Could not create child process");
5476 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5477 fd_info
[ fd
].hnd
= hnd
;
5478 fd_info
[ fd
].flags
|=
5479 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5480 if (fd_info
[ fd
].cp
!= NULL
)
5482 error ("fd_info[fd = %d] is already in use", fd
);
5484 fd_info
[ fd
].cp
= cp
;
5485 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5486 if (cp
->ovl_read
.hEvent
== NULL
)
5487 error ("Could not create read event");
5488 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5489 if (cp
->ovl_write
.hEvent
== NULL
)
5490 error ("Could not create write event");
5495 /* For serial-process-configure */
5497 serial_configure (struct Lisp_Process
*p
,
5498 Lisp_Object contact
)
5500 Lisp_Object childp2
= Qnil
;
5501 Lisp_Object tem
= Qnil
;
5505 char summary
[4] = "???"; /* This usually becomes "8N1". */
5507 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
5508 error ("Not a serial process");
5509 hnd
= fd_info
[ p
->outfd
].hnd
;
5511 childp2
= Fcopy_sequence (p
->childp
);
5513 /* Initialize timeouts for blocking read and blocking write. */
5514 if (!GetCommTimeouts (hnd
, &ct
))
5515 error ("GetCommTimeouts() failed");
5516 ct
.ReadIntervalTimeout
= 0;
5517 ct
.ReadTotalTimeoutMultiplier
= 0;
5518 ct
.ReadTotalTimeoutConstant
= 0;
5519 ct
.WriteTotalTimeoutMultiplier
= 0;
5520 ct
.WriteTotalTimeoutConstant
= 0;
5521 if (!SetCommTimeouts (hnd
, &ct
))
5522 error ("SetCommTimeouts() failed");
5523 /* Read port attributes and prepare default configuration. */
5524 memset (&dcb
, 0, sizeof (dcb
));
5525 dcb
.DCBlength
= sizeof (DCB
);
5526 if (!GetCommState (hnd
, &dcb
))
5527 error ("GetCommState() failed");
5530 dcb
.fAbortOnError
= FALSE
;
5531 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
5536 /* Configure speed. */
5537 if (!NILP (Fplist_member (contact
, QCspeed
)))
5538 tem
= Fplist_get (contact
, QCspeed
);
5540 tem
= Fplist_get (p
->childp
, QCspeed
);
5542 dcb
.BaudRate
= XINT (tem
);
5543 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
5545 /* Configure bytesize. */
5546 if (!NILP (Fplist_member (contact
, QCbytesize
)))
5547 tem
= Fplist_get (contact
, QCbytesize
);
5549 tem
= Fplist_get (p
->childp
, QCbytesize
);
5551 tem
= make_number (8);
5553 if (XINT (tem
) != 7 && XINT (tem
) != 8)
5554 error (":bytesize must be nil (8), 7, or 8");
5555 dcb
.ByteSize
= XINT (tem
);
5556 summary
[0] = XINT (tem
) + '0';
5557 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
5559 /* Configure parity. */
5560 if (!NILP (Fplist_member (contact
, QCparity
)))
5561 tem
= Fplist_get (contact
, QCparity
);
5563 tem
= Fplist_get (p
->childp
, QCparity
);
5564 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
5565 error (":parity must be nil (no parity), `even', or `odd'");
5566 dcb
.fParity
= FALSE
;
5567 dcb
.Parity
= NOPARITY
;
5568 dcb
.fErrorChar
= FALSE
;
5573 else if (EQ (tem
, Qeven
))
5577 dcb
.Parity
= EVENPARITY
;
5578 dcb
.fErrorChar
= TRUE
;
5580 else if (EQ (tem
, Qodd
))
5584 dcb
.Parity
= ODDPARITY
;
5585 dcb
.fErrorChar
= TRUE
;
5587 childp2
= Fplist_put (childp2
, QCparity
, tem
);
5589 /* Configure stopbits. */
5590 if (!NILP (Fplist_member (contact
, QCstopbits
)))
5591 tem
= Fplist_get (contact
, QCstopbits
);
5593 tem
= Fplist_get (p
->childp
, QCstopbits
);
5595 tem
= make_number (1);
5597 if (XINT (tem
) != 1 && XINT (tem
) != 2)
5598 error (":stopbits must be nil (1 stopbit), 1, or 2");
5599 summary
[2] = XINT (tem
) + '0';
5600 if (XINT (tem
) == 1)
5601 dcb
.StopBits
= ONESTOPBIT
;
5602 else if (XINT (tem
) == 2)
5603 dcb
.StopBits
= TWOSTOPBITS
;
5604 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
5606 /* Configure flowcontrol. */
5607 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
5608 tem
= Fplist_get (contact
, QCflowcontrol
);
5610 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
5611 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
5612 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
5613 dcb
.fOutxCtsFlow
= FALSE
;
5614 dcb
.fOutxDsrFlow
= FALSE
;
5615 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
5616 dcb
.fDsrSensitivity
= FALSE
;
5617 dcb
.fTXContinueOnXoff
= FALSE
;
5620 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
5621 dcb
.XonChar
= 17; /* Control-Q */
5622 dcb
.XoffChar
= 19; /* Control-S */
5625 /* Already configured. */
5627 else if (EQ (tem
, Qhw
))
5629 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
5630 dcb
.fOutxCtsFlow
= TRUE
;
5632 else if (EQ (tem
, Qsw
))
5637 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
5639 /* Activate configuration. */
5640 if (!SetCommState (hnd
, &dcb
))
5641 error ("SetCommState() failed");
5643 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
5644 p
->childp
= childp2
;
5649 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
5650 (do not change this comment) */