Merge into trunk
[emacs.git] / src / w32.c
blobb50cd13517d5583837dfb1fa3748fb04e35c3b7c
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
2 Copyright (C) 1994-1995, 2000-2012 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
22 #include <stddef.h> /* for offsetof */
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <float.h> /* for DBL_EPSILON */
26 #include <io.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <ctype.h>
30 #include <signal.h>
31 #include <sys/file.h>
32 #include <sys/time.h>
33 #include <sys/utime.h>
34 #include <math.h>
35 #include <time.h>
37 /* must include CRT headers *before* config.h */
39 #include <config.h>
40 #include <mbstring.h> /* for _mbspbrk */
42 #undef access
43 #undef chdir
44 #undef chmod
45 #undef creat
46 #undef ctime
47 #undef fopen
48 #undef link
49 #undef mkdir
50 #undef mktemp
51 #undef open
52 #undef rename
53 #undef rmdir
54 #undef unlink
56 #undef close
57 #undef dup
58 #undef dup2
59 #undef pipe
60 #undef read
61 #undef write
63 #undef strerror
65 #undef localtime
67 #include "lisp.h"
69 #include <pwd.h>
70 #include <grp.h>
72 #ifdef __GNUC__
73 #define _ANONYMOUS_UNION
74 #define _ANONYMOUS_STRUCT
75 #endif
76 #include <windows.h>
77 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
78 use a different name to avoid compilation problems. */
79 typedef struct _MEMORY_STATUS_EX {
80 DWORD dwLength;
81 DWORD dwMemoryLoad;
82 DWORDLONG ullTotalPhys;
83 DWORDLONG ullAvailPhys;
84 DWORDLONG ullTotalPageFile;
85 DWORDLONG ullAvailPageFile;
86 DWORDLONG ullTotalVirtual;
87 DWORDLONG ullAvailVirtual;
88 DWORDLONG ullAvailExtendedVirtual;
89 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
91 #include <lmcons.h>
92 #include <shlobj.h>
94 #include <tlhelp32.h>
95 #include <psapi.h>
96 #ifndef _MSC_VER
97 #include <w32api.h>
98 #endif
99 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
100 /* This either is not in psapi.h or guarded by higher value of
101 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
102 defines it in psapi.h */
103 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
104 DWORD cb;
105 DWORD PageFaultCount;
106 DWORD PeakWorkingSetSize;
107 DWORD WorkingSetSize;
108 DWORD QuotaPeakPagedPoolUsage;
109 DWORD QuotaPagedPoolUsage;
110 DWORD QuotaPeakNonPagedPoolUsage;
111 DWORD QuotaNonPagedPoolUsage;
112 DWORD PagefileUsage;
113 DWORD PeakPagefileUsage;
114 DWORD PrivateUsage;
115 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
116 #endif
118 #include <winioctl.h>
119 #include <aclapi.h>
121 #ifdef _MSC_VER
122 /* MSVC doesn't provide the definition of REPARSE_DATA_BUFFER, except
123 on ntifs.h, which cannot be included because it triggers conflicts
124 with other Windows API headers. So we define it here by hand. */
126 typedef struct _REPARSE_DATA_BUFFER {
127 ULONG ReparseTag;
128 USHORT ReparseDataLength;
129 USHORT Reserved;
130 union {
131 struct {
132 USHORT SubstituteNameOffset;
133 USHORT SubstituteNameLength;
134 USHORT PrintNameOffset;
135 USHORT PrintNameLength;
136 ULONG Flags;
137 WCHAR PathBuffer[1];
138 } SymbolicLinkReparseBuffer;
139 struct {
140 USHORT SubstituteNameOffset;
141 USHORT SubstituteNameLength;
142 USHORT PrintNameOffset;
143 USHORT PrintNameLength;
144 WCHAR PathBuffer[1];
145 } MountPointReparseBuffer;
146 struct {
147 UCHAR DataBuffer[1];
148 } GenericReparseBuffer;
149 } DUMMYUNIONNAME;
150 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
152 #endif
154 /* TCP connection support. */
155 #include <sys/socket.h>
156 #undef socket
157 #undef bind
158 #undef connect
159 #undef htons
160 #undef ntohs
161 #undef inet_addr
162 #undef gethostname
163 #undef gethostbyname
164 #undef getservbyname
165 #undef getpeername
166 #undef shutdown
167 #undef setsockopt
168 #undef listen
169 #undef getsockname
170 #undef accept
171 #undef recvfrom
172 #undef sendto
174 #include "w32.h"
175 #include "ndir.h"
176 #include "w32common.h"
177 #include "w32heap.h"
178 #include "systime.h"
179 #include "dispextern.h" /* for xstrcasecmp */
180 #include "coding.h" /* for Vlocale_coding_system */
182 #include "careadlinkat.h"
183 #include "allocator.h"
185 /* For serial_configure and serial_open. */
186 #include "process.h"
188 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
189 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
191 Lisp_Object QCloaded_from;
193 void globals_of_w32 (void);
194 static DWORD get_rid (PSID);
195 static int is_symlink (const char *);
196 static char * chase_symlinks (const char *);
197 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
198 static int restore_privilege (TOKEN_PRIVILEGES *);
199 static BOOL WINAPI revert_to_self (void);
202 /* Initialization states.
204 WARNING: If you add any more such variables for additional APIs,
205 you MUST add initialization for them to globals_of_w32
206 below. This is because these variables might get set
207 to non-NULL values during dumping, but the dumped Emacs
208 cannot reuse those values, because it could be run on a
209 different version of the OS, where API addresses are
210 different. */
211 static BOOL g_b_init_is_windows_9x;
212 static BOOL g_b_init_open_process_token;
213 static BOOL g_b_init_get_token_information;
214 static BOOL g_b_init_lookup_account_sid;
215 static BOOL g_b_init_get_sid_sub_authority;
216 static BOOL g_b_init_get_sid_sub_authority_count;
217 static BOOL g_b_init_get_security_info;
218 static BOOL g_b_init_get_file_security;
219 static BOOL g_b_init_get_security_descriptor_owner;
220 static BOOL g_b_init_get_security_descriptor_group;
221 static BOOL g_b_init_is_valid_sid;
222 static BOOL g_b_init_create_toolhelp32_snapshot;
223 static BOOL g_b_init_process32_first;
224 static BOOL g_b_init_process32_next;
225 static BOOL g_b_init_open_thread_token;
226 static BOOL g_b_init_impersonate_self;
227 static BOOL g_b_init_revert_to_self;
228 static BOOL g_b_init_get_process_memory_info;
229 static BOOL g_b_init_get_process_working_set_size;
230 static BOOL g_b_init_global_memory_status;
231 static BOOL g_b_init_global_memory_status_ex;
232 static BOOL g_b_init_get_length_sid;
233 static BOOL g_b_init_equal_sid;
234 static BOOL g_b_init_copy_sid;
235 static BOOL g_b_init_get_native_system_info;
236 static BOOL g_b_init_get_system_times;
237 static BOOL g_b_init_create_symbolic_link;
240 BEGIN: Wrapper functions around OpenProcessToken
241 and other functions in advapi32.dll that are only
242 supported in Windows NT / 2k / XP
244 /* ** Function pointer typedefs ** */
245 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
246 HANDLE ProcessHandle,
247 DWORD DesiredAccess,
248 PHANDLE TokenHandle);
249 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
250 HANDLE TokenHandle,
251 TOKEN_INFORMATION_CLASS TokenInformationClass,
252 LPVOID TokenInformation,
253 DWORD TokenInformationLength,
254 PDWORD ReturnLength);
255 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
256 HANDLE process_handle,
257 LPFILETIME creation_time,
258 LPFILETIME exit_time,
259 LPFILETIME kernel_time,
260 LPFILETIME user_time);
262 GetProcessTimes_Proc get_process_times_fn = NULL;
264 #ifdef _UNICODE
265 const char * const LookupAccountSid_Name = "LookupAccountSidW";
266 const char * const GetFileSecurity_Name = "GetFileSecurityW";
267 #else
268 const char * const LookupAccountSid_Name = "LookupAccountSidA";
269 const char * const GetFileSecurity_Name = "GetFileSecurityA";
270 #endif
271 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
272 LPCTSTR lpSystemName,
273 PSID Sid,
274 LPTSTR Name,
275 LPDWORD cbName,
276 LPTSTR DomainName,
277 LPDWORD cbDomainName,
278 PSID_NAME_USE peUse);
279 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
280 PSID pSid,
281 DWORD n);
282 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
283 PSID pSid);
284 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
285 HANDLE handle,
286 SE_OBJECT_TYPE ObjectType,
287 SECURITY_INFORMATION SecurityInfo,
288 PSID *ppsidOwner,
289 PSID *ppsidGroup,
290 PACL *ppDacl,
291 PACL *ppSacl,
292 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
293 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
294 LPCTSTR lpFileName,
295 SECURITY_INFORMATION RequestedInformation,
296 PSECURITY_DESCRIPTOR pSecurityDescriptor,
297 DWORD nLength,
298 LPDWORD lpnLengthNeeded);
299 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
300 PSECURITY_DESCRIPTOR pSecurityDescriptor,
301 PSID *pOwner,
302 LPBOOL lpbOwnerDefaulted);
303 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
304 PSECURITY_DESCRIPTOR pSecurityDescriptor,
305 PSID *pGroup,
306 LPBOOL lpbGroupDefaulted);
307 typedef BOOL (WINAPI * IsValidSid_Proc) (
308 PSID sid);
309 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
310 DWORD dwFlags,
311 DWORD th32ProcessID);
312 typedef BOOL (WINAPI * Process32First_Proc) (
313 HANDLE hSnapshot,
314 LPPROCESSENTRY32 lppe);
315 typedef BOOL (WINAPI * Process32Next_Proc) (
316 HANDLE hSnapshot,
317 LPPROCESSENTRY32 lppe);
318 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
319 HANDLE ThreadHandle,
320 DWORD DesiredAccess,
321 BOOL OpenAsSelf,
322 PHANDLE TokenHandle);
323 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
324 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
325 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
326 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
327 HANDLE Process,
328 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
329 DWORD cb);
330 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
331 HANDLE hProcess,
332 DWORD * lpMinimumWorkingSetSize,
333 DWORD * lpMaximumWorkingSetSize);
334 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
335 LPMEMORYSTATUS lpBuffer);
336 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
337 LPMEMORY_STATUS_EX lpBuffer);
338 typedef BOOL (WINAPI * CopySid_Proc) (
339 DWORD nDestinationSidLength,
340 PSID pDestinationSid,
341 PSID pSourceSid);
342 typedef BOOL (WINAPI * EqualSid_Proc) (
343 PSID pSid1,
344 PSID pSid2);
345 typedef DWORD (WINAPI * GetLengthSid_Proc) (
346 PSID pSid);
347 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
348 LPSYSTEM_INFO lpSystemInfo);
349 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
350 LPFILETIME lpIdleTime,
351 LPFILETIME lpKernelTime,
352 LPFILETIME lpUserTime);
353 typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) (
354 LPTSTR lpSymlinkFileName,
355 LPTSTR lpTargetFileName,
356 DWORD dwFlags);
358 /* ** A utility function ** */
359 static BOOL
360 is_windows_9x (void)
362 static BOOL s_b_ret = 0;
363 OSVERSIONINFO os_ver;
364 if (g_b_init_is_windows_9x == 0)
366 g_b_init_is_windows_9x = 1;
367 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
368 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
369 if (GetVersionEx (&os_ver))
371 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
374 return s_b_ret;
377 static Lisp_Object ltime (ULONGLONG);
379 /* Get total user and system times for get-internal-run-time.
380 Returns a list of integers if the times are provided by the OS
381 (NT derivatives), otherwise it returns the result of current-time. */
382 Lisp_Object
383 w32_get_internal_run_time (void)
385 if (get_process_times_fn)
387 FILETIME create, exit, kernel, user;
388 HANDLE proc = GetCurrentProcess ();
389 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
391 LARGE_INTEGER user_int, kernel_int, total;
392 user_int.LowPart = user.dwLowDateTime;
393 user_int.HighPart = user.dwHighDateTime;
394 kernel_int.LowPart = kernel.dwLowDateTime;
395 kernel_int.HighPart = kernel.dwHighDateTime;
396 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
397 return ltime (total.QuadPart);
401 return Fcurrent_time ();
404 /* ** The wrapper functions ** */
406 static BOOL WINAPI
407 open_process_token (HANDLE ProcessHandle,
408 DWORD DesiredAccess,
409 PHANDLE TokenHandle)
411 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
412 HMODULE hm_advapi32 = NULL;
413 if (is_windows_9x () == TRUE)
415 return FALSE;
417 if (g_b_init_open_process_token == 0)
419 g_b_init_open_process_token = 1;
420 hm_advapi32 = LoadLibrary ("Advapi32.dll");
421 s_pfn_Open_Process_Token =
422 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
424 if (s_pfn_Open_Process_Token == NULL)
426 return FALSE;
428 return (
429 s_pfn_Open_Process_Token (
430 ProcessHandle,
431 DesiredAccess,
432 TokenHandle)
436 static BOOL WINAPI
437 get_token_information (HANDLE TokenHandle,
438 TOKEN_INFORMATION_CLASS TokenInformationClass,
439 LPVOID TokenInformation,
440 DWORD TokenInformationLength,
441 PDWORD ReturnLength)
443 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
444 HMODULE hm_advapi32 = NULL;
445 if (is_windows_9x () == TRUE)
447 return FALSE;
449 if (g_b_init_get_token_information == 0)
451 g_b_init_get_token_information = 1;
452 hm_advapi32 = LoadLibrary ("Advapi32.dll");
453 s_pfn_Get_Token_Information =
454 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
456 if (s_pfn_Get_Token_Information == NULL)
458 return FALSE;
460 return (
461 s_pfn_Get_Token_Information (
462 TokenHandle,
463 TokenInformationClass,
464 TokenInformation,
465 TokenInformationLength,
466 ReturnLength)
470 static BOOL WINAPI
471 lookup_account_sid (LPCTSTR lpSystemName,
472 PSID Sid,
473 LPTSTR Name,
474 LPDWORD cbName,
475 LPTSTR DomainName,
476 LPDWORD cbDomainName,
477 PSID_NAME_USE peUse)
479 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
480 HMODULE hm_advapi32 = NULL;
481 if (is_windows_9x () == TRUE)
483 return FALSE;
485 if (g_b_init_lookup_account_sid == 0)
487 g_b_init_lookup_account_sid = 1;
488 hm_advapi32 = LoadLibrary ("Advapi32.dll");
489 s_pfn_Lookup_Account_Sid =
490 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
492 if (s_pfn_Lookup_Account_Sid == NULL)
494 return FALSE;
496 return (
497 s_pfn_Lookup_Account_Sid (
498 lpSystemName,
499 Sid,
500 Name,
501 cbName,
502 DomainName,
503 cbDomainName,
504 peUse)
508 static PDWORD WINAPI
509 get_sid_sub_authority (PSID pSid, DWORD n)
511 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
512 static DWORD zero = 0U;
513 HMODULE hm_advapi32 = NULL;
514 if (is_windows_9x () == TRUE)
516 return &zero;
518 if (g_b_init_get_sid_sub_authority == 0)
520 g_b_init_get_sid_sub_authority = 1;
521 hm_advapi32 = LoadLibrary ("Advapi32.dll");
522 s_pfn_Get_Sid_Sub_Authority =
523 (GetSidSubAuthority_Proc) GetProcAddress (
524 hm_advapi32, "GetSidSubAuthority");
526 if (s_pfn_Get_Sid_Sub_Authority == NULL)
528 return &zero;
530 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
533 static PUCHAR WINAPI
534 get_sid_sub_authority_count (PSID pSid)
536 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
537 static UCHAR zero = 0U;
538 HMODULE hm_advapi32 = NULL;
539 if (is_windows_9x () == TRUE)
541 return &zero;
543 if (g_b_init_get_sid_sub_authority_count == 0)
545 g_b_init_get_sid_sub_authority_count = 1;
546 hm_advapi32 = LoadLibrary ("Advapi32.dll");
547 s_pfn_Get_Sid_Sub_Authority_Count =
548 (GetSidSubAuthorityCount_Proc) GetProcAddress (
549 hm_advapi32, "GetSidSubAuthorityCount");
551 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
553 return &zero;
555 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
558 static DWORD WINAPI
559 get_security_info (HANDLE handle,
560 SE_OBJECT_TYPE ObjectType,
561 SECURITY_INFORMATION SecurityInfo,
562 PSID *ppsidOwner,
563 PSID *ppsidGroup,
564 PACL *ppDacl,
565 PACL *ppSacl,
566 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
568 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
569 HMODULE hm_advapi32 = NULL;
570 if (is_windows_9x () == TRUE)
572 return FALSE;
574 if (g_b_init_get_security_info == 0)
576 g_b_init_get_security_info = 1;
577 hm_advapi32 = LoadLibrary ("Advapi32.dll");
578 s_pfn_Get_Security_Info =
579 (GetSecurityInfo_Proc) GetProcAddress (
580 hm_advapi32, "GetSecurityInfo");
582 if (s_pfn_Get_Security_Info == NULL)
584 return FALSE;
586 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
587 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
588 ppSecurityDescriptor));
591 static BOOL WINAPI
592 get_file_security (LPCTSTR lpFileName,
593 SECURITY_INFORMATION RequestedInformation,
594 PSECURITY_DESCRIPTOR pSecurityDescriptor,
595 DWORD nLength,
596 LPDWORD lpnLengthNeeded)
598 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
599 HMODULE hm_advapi32 = NULL;
600 if (is_windows_9x () == TRUE)
602 return FALSE;
604 if (g_b_init_get_file_security == 0)
606 g_b_init_get_file_security = 1;
607 hm_advapi32 = LoadLibrary ("Advapi32.dll");
608 s_pfn_Get_File_Security =
609 (GetFileSecurity_Proc) GetProcAddress (
610 hm_advapi32, GetFileSecurity_Name);
612 if (s_pfn_Get_File_Security == NULL)
614 return FALSE;
616 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
617 pSecurityDescriptor, nLength,
618 lpnLengthNeeded));
621 static BOOL WINAPI
622 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
623 PSID *pOwner,
624 LPBOOL lpbOwnerDefaulted)
626 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
627 HMODULE hm_advapi32 = NULL;
628 if (is_windows_9x () == TRUE)
630 return FALSE;
632 if (g_b_init_get_security_descriptor_owner == 0)
634 g_b_init_get_security_descriptor_owner = 1;
635 hm_advapi32 = LoadLibrary ("Advapi32.dll");
636 s_pfn_Get_Security_Descriptor_Owner =
637 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
638 hm_advapi32, "GetSecurityDescriptorOwner");
640 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
642 return FALSE;
644 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
645 lpbOwnerDefaulted));
648 static BOOL WINAPI
649 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
650 PSID *pGroup,
651 LPBOOL lpbGroupDefaulted)
653 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
654 HMODULE hm_advapi32 = NULL;
655 if (is_windows_9x () == TRUE)
657 return FALSE;
659 if (g_b_init_get_security_descriptor_group == 0)
661 g_b_init_get_security_descriptor_group = 1;
662 hm_advapi32 = LoadLibrary ("Advapi32.dll");
663 s_pfn_Get_Security_Descriptor_Group =
664 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
665 hm_advapi32, "GetSecurityDescriptorGroup");
667 if (s_pfn_Get_Security_Descriptor_Group == NULL)
669 return FALSE;
671 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
672 lpbGroupDefaulted));
675 static BOOL WINAPI
676 is_valid_sid (PSID sid)
678 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
679 HMODULE hm_advapi32 = NULL;
680 if (is_windows_9x () == TRUE)
682 return FALSE;
684 if (g_b_init_is_valid_sid == 0)
686 g_b_init_is_valid_sid = 1;
687 hm_advapi32 = LoadLibrary ("Advapi32.dll");
688 s_pfn_Is_Valid_Sid =
689 (IsValidSid_Proc) GetProcAddress (
690 hm_advapi32, "IsValidSid");
692 if (s_pfn_Is_Valid_Sid == NULL)
694 return FALSE;
696 return (s_pfn_Is_Valid_Sid (sid));
699 static BOOL WINAPI
700 equal_sid (PSID sid1, PSID sid2)
702 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
703 HMODULE hm_advapi32 = NULL;
704 if (is_windows_9x () == TRUE)
706 return FALSE;
708 if (g_b_init_equal_sid == 0)
710 g_b_init_equal_sid = 1;
711 hm_advapi32 = LoadLibrary ("Advapi32.dll");
712 s_pfn_Equal_Sid =
713 (EqualSid_Proc) GetProcAddress (
714 hm_advapi32, "EqualSid");
716 if (s_pfn_Equal_Sid == NULL)
718 return FALSE;
720 return (s_pfn_Equal_Sid (sid1, sid2));
723 static DWORD WINAPI
724 get_length_sid (PSID sid)
726 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
727 HMODULE hm_advapi32 = NULL;
728 if (is_windows_9x () == TRUE)
730 return 0;
732 if (g_b_init_get_length_sid == 0)
734 g_b_init_get_length_sid = 1;
735 hm_advapi32 = LoadLibrary ("Advapi32.dll");
736 s_pfn_Get_Length_Sid =
737 (GetLengthSid_Proc) GetProcAddress (
738 hm_advapi32, "GetLengthSid");
740 if (s_pfn_Get_Length_Sid == NULL)
742 return 0;
744 return (s_pfn_Get_Length_Sid (sid));
747 static BOOL WINAPI
748 copy_sid (DWORD destlen, PSID dest, PSID src)
750 static CopySid_Proc s_pfn_Copy_Sid = NULL;
751 HMODULE hm_advapi32 = NULL;
752 if (is_windows_9x () == TRUE)
754 return FALSE;
756 if (g_b_init_copy_sid == 0)
758 g_b_init_copy_sid = 1;
759 hm_advapi32 = LoadLibrary ("Advapi32.dll");
760 s_pfn_Copy_Sid =
761 (CopySid_Proc) GetProcAddress (
762 hm_advapi32, "CopySid");
764 if (s_pfn_Copy_Sid == NULL)
766 return FALSE;
768 return (s_pfn_Copy_Sid (destlen, dest, src));
772 END: Wrapper functions around OpenProcessToken
773 and other functions in advapi32.dll that are only
774 supported in Windows NT / 2k / XP
777 static void WINAPI
778 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
780 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
781 if (is_windows_9x () != TRUE)
783 if (g_b_init_get_native_system_info == 0)
785 g_b_init_get_native_system_info = 1;
786 s_pfn_Get_Native_System_Info =
787 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
788 "GetNativeSystemInfo");
790 if (s_pfn_Get_Native_System_Info != NULL)
791 s_pfn_Get_Native_System_Info (lpSystemInfo);
793 else
794 lpSystemInfo->dwNumberOfProcessors = -1;
797 static BOOL WINAPI
798 get_system_times (LPFILETIME lpIdleTime,
799 LPFILETIME lpKernelTime,
800 LPFILETIME lpUserTime)
802 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
803 if (is_windows_9x () == TRUE)
805 return FALSE;
807 if (g_b_init_get_system_times == 0)
809 g_b_init_get_system_times = 1;
810 s_pfn_Get_System_times =
811 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
812 "GetSystemTimes");
814 if (s_pfn_Get_System_times == NULL)
815 return FALSE;
816 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
819 static BOOLEAN WINAPI
820 create_symbolic_link (LPTSTR lpSymlinkFilename,
821 LPTSTR lpTargetFileName,
822 DWORD dwFlags)
824 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link = NULL;
825 BOOLEAN retval;
827 if (is_windows_9x () == TRUE)
829 errno = ENOSYS;
830 return 0;
832 if (g_b_init_create_symbolic_link == 0)
834 g_b_init_create_symbolic_link = 1;
835 #ifdef _UNICODE
836 s_pfn_Create_Symbolic_Link =
837 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
838 "CreateSymbolicLinkW");
839 #else
840 s_pfn_Create_Symbolic_Link =
841 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
842 "CreateSymbolicLinkA");
843 #endif
845 if (s_pfn_Create_Symbolic_Link == NULL)
847 errno = ENOSYS;
848 return 0;
851 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
852 dwFlags);
853 /* If we were denied creation of the symlink, try again after
854 enabling the SeCreateSymbolicLinkPrivilege for our process. */
855 if (!retval)
857 TOKEN_PRIVILEGES priv_current;
859 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE, &priv_current))
861 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
862 dwFlags);
863 restore_privilege (&priv_current);
864 revert_to_self ();
867 return retval;
871 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
872 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
874 This is called from alloc.c:valid_pointer_p. */
876 w32_valid_pointer_p (void *p, int size)
878 SIZE_T done;
879 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
881 if (h)
883 unsigned char *buf = alloca (size);
884 int retval = ReadProcessMemory (h, p, buf, size, &done);
886 CloseHandle (h);
887 return retval;
889 else
890 return -1;
893 static char startup_dir[MAXPATHLEN];
895 /* Get the current working directory. */
896 char *
897 getwd (char *dir)
899 #if 0
900 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
901 return dir;
902 return NULL;
903 #else
904 /* Emacs doesn't actually change directory itself, it stays in the
905 same directory where it was started. */
906 strcpy (dir, startup_dir);
907 return dir;
908 #endif
911 /* Emulate getloadavg. */
913 struct load_sample {
914 time_t sample_time;
915 ULONGLONG idle;
916 ULONGLONG kernel;
917 ULONGLONG user;
920 /* Number of processors on this machine. */
921 static unsigned num_of_processors;
923 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
924 static struct load_sample samples[16*60];
925 static int first_idx = -1, last_idx = -1;
926 static int max_idx = sizeof (samples) / sizeof (samples[0]);
928 static int
929 buf_next (int from)
931 int next_idx = from + 1;
933 if (next_idx >= max_idx)
934 next_idx = 0;
936 return next_idx;
939 static int
940 buf_prev (int from)
942 int prev_idx = from - 1;
944 if (prev_idx < 0)
945 prev_idx = max_idx - 1;
947 return prev_idx;
950 static void
951 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
953 SYSTEM_INFO sysinfo;
954 FILETIME ft_idle, ft_user, ft_kernel;
956 /* Initialize the number of processors on this machine. */
957 if (num_of_processors <= 0)
959 get_native_system_info (&sysinfo);
960 num_of_processors = sysinfo.dwNumberOfProcessors;
961 if (num_of_processors <= 0)
963 GetSystemInfo (&sysinfo);
964 num_of_processors = sysinfo.dwNumberOfProcessors;
966 if (num_of_processors <= 0)
967 num_of_processors = 1;
970 /* TODO: Take into account threads that are ready to run, by
971 sampling the "\System\Processor Queue Length" performance
972 counter. The code below accounts only for threads that are
973 actually running. */
975 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
977 ULARGE_INTEGER uidle, ukernel, uuser;
979 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
980 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
981 memcpy (&uuser, &ft_user, sizeof (ft_user));
982 *idle = uidle.QuadPart;
983 *kernel = ukernel.QuadPart;
984 *user = uuser.QuadPart;
986 else
988 *idle = 0;
989 *kernel = 0;
990 *user = 0;
994 /* Produce the load average for a given time interval, using the
995 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
996 1-minute, 5-minute, or 15-minute average, respectively. */
997 static double
998 getavg (int which)
1000 double retval = -1.0;
1001 double tdiff;
1002 int idx;
1003 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1004 time_t now = samples[last_idx].sample_time;
1006 if (first_idx != last_idx)
1008 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1010 tdiff = difftime (now, samples[idx].sample_time);
1011 if (tdiff >= span - 2*DBL_EPSILON*now)
1013 long double sys =
1014 samples[last_idx].kernel + samples[last_idx].user
1015 - (samples[idx].kernel + samples[idx].user);
1016 long double idl = samples[last_idx].idle - samples[idx].idle;
1018 retval = (1.0 - idl / sys) * num_of_processors;
1019 break;
1021 if (idx == first_idx)
1022 break;
1026 return retval;
1030 getloadavg (double loadavg[], int nelem)
1032 int elem;
1033 ULONGLONG idle, kernel, user;
1034 time_t now = time (NULL);
1036 /* Store another sample. We ignore samples that are less than 1 sec
1037 apart. */
1038 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
1040 sample_system_load (&idle, &kernel, &user);
1041 last_idx = buf_next (last_idx);
1042 samples[last_idx].sample_time = now;
1043 samples[last_idx].idle = idle;
1044 samples[last_idx].kernel = kernel;
1045 samples[last_idx].user = user;
1046 /* If the buffer has more that 15 min worth of samples, discard
1047 the old ones. */
1048 if (first_idx == -1)
1049 first_idx = last_idx;
1050 while (first_idx != last_idx
1051 && (difftime (now, samples[first_idx].sample_time)
1052 >= 15.0*60 + 2*DBL_EPSILON*now))
1053 first_idx = buf_next (first_idx);
1056 for (elem = 0; elem < nelem; elem++)
1058 double avg = getavg (elem);
1060 if (avg < 0)
1061 break;
1062 loadavg[elem] = avg;
1065 return elem;
1068 /* Emulate getpwuid, getpwnam and others. */
1070 #define PASSWD_FIELD_SIZE 256
1072 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1073 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1074 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1075 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
1076 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
1078 static struct passwd dflt_passwd =
1080 dflt_passwd_name,
1081 dflt_passwd_passwd,
1085 dflt_passwd_gecos,
1086 dflt_passwd_dir,
1087 dflt_passwd_shell,
1090 static char dflt_group_name[GNLEN+1];
1092 static struct group dflt_group =
1094 /* When group information is not available, we return this as the
1095 group for all files. */
1096 dflt_group_name,
1100 unsigned
1101 getuid (void)
1103 return dflt_passwd.pw_uid;
1106 unsigned
1107 geteuid (void)
1109 /* I could imagine arguing for checking to see whether the user is
1110 in the Administrators group and returning a UID of 0 for that
1111 case, but I don't know how wise that would be in the long run. */
1112 return getuid ();
1115 unsigned
1116 getgid (void)
1118 return dflt_passwd.pw_gid;
1121 unsigned
1122 getegid (void)
1124 return getgid ();
1127 struct passwd *
1128 getpwuid (unsigned uid)
1130 if (uid == dflt_passwd.pw_uid)
1131 return &dflt_passwd;
1132 return NULL;
1135 struct group *
1136 getgrgid (gid_t gid)
1138 return &dflt_group;
1141 struct passwd *
1142 getpwnam (char *name)
1144 struct passwd *pw;
1146 pw = getpwuid (getuid ());
1147 if (!pw)
1148 return pw;
1150 if (xstrcasecmp (name, pw->pw_name))
1151 return NULL;
1153 return pw;
1156 static void
1157 init_user_info (void)
1159 /* Find the user's real name by opening the process token and
1160 looking up the name associated with the user-sid in that token.
1162 Use the relative portion of the identifier authority value from
1163 the user-sid as the user id value (same for group id using the
1164 primary group sid from the process token). */
1166 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1167 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1168 DWORD glength = sizeof (gname);
1169 HANDLE token = NULL;
1170 SID_NAME_USE user_type;
1171 unsigned char *buf = NULL;
1172 DWORD blen = 0;
1173 TOKEN_USER user_token;
1174 TOKEN_PRIMARY_GROUP group_token;
1175 BOOL result;
1177 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1178 if (result)
1180 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1181 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1183 buf = xmalloc (blen);
1184 result = get_token_information (token, TokenUser,
1185 (LPVOID)buf, blen, &needed);
1186 if (result)
1188 memcpy (&user_token, buf, sizeof (user_token));
1189 result = lookup_account_sid (NULL, user_token.User.Sid,
1190 uname, &ulength,
1191 domain, &dlength, &user_type);
1194 else
1195 result = FALSE;
1197 if (result)
1199 strcpy (dflt_passwd.pw_name, uname);
1200 /* Determine a reasonable uid value. */
1201 if (xstrcasecmp ("administrator", uname) == 0)
1203 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1204 dflt_passwd.pw_gid = 513; /* well-known None gid */
1206 else
1208 /* Use the last sub-authority value of the RID, the relative
1209 portion of the SID, as user/group ID. */
1210 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1212 /* Get group id and name. */
1213 result = get_token_information (token, TokenPrimaryGroup,
1214 (LPVOID)buf, blen, &needed);
1215 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1217 buf = xrealloc (buf, blen = needed);
1218 result = get_token_information (token, TokenPrimaryGroup,
1219 (LPVOID)buf, blen, &needed);
1221 if (result)
1223 memcpy (&group_token, buf, sizeof (group_token));
1224 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1225 dlength = sizeof (domain);
1226 /* If we can get at the real Primary Group name, use that.
1227 Otherwise, the default group name was already set to
1228 "None" in globals_of_w32. */
1229 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1230 gname, &glength, NULL, &dlength,
1231 &user_type))
1232 strcpy (dflt_group_name, gname);
1234 else
1235 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1238 /* If security calls are not supported (presumably because we
1239 are running under Windows 9X), fallback to this: */
1240 else if (GetUserName (uname, &ulength))
1242 strcpy (dflt_passwd.pw_name, uname);
1243 if (xstrcasecmp ("administrator", uname) == 0)
1244 dflt_passwd.pw_uid = 0;
1245 else
1246 dflt_passwd.pw_uid = 123;
1247 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1249 else
1251 strcpy (dflt_passwd.pw_name, "unknown");
1252 dflt_passwd.pw_uid = 123;
1253 dflt_passwd.pw_gid = 123;
1255 dflt_group.gr_gid = dflt_passwd.pw_gid;
1257 /* Ensure HOME and SHELL are defined. */
1258 if (getenv ("HOME") == NULL)
1259 emacs_abort ();
1260 if (getenv ("SHELL") == NULL)
1261 emacs_abort ();
1263 /* Set dir and shell from environment variables. */
1264 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1265 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1267 xfree (buf);
1268 if (token)
1269 CloseHandle (token);
1273 random (void)
1275 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1276 return ((rand () << 15) | rand ());
1279 void
1280 srandom (int seed)
1282 srand (seed);
1286 /* Normalize filename by converting all path separators to
1287 the specified separator. Also conditionally convert upper
1288 case path name components to lower case. */
1290 static void
1291 normalize_filename (register char *fp, char path_sep)
1293 char sep;
1294 char *elem;
1296 /* Always lower-case drive letters a-z, even if the filesystem
1297 preserves case in filenames.
1298 This is so filenames can be compared by string comparison
1299 functions that are case-sensitive. Even case-preserving filesystems
1300 do not distinguish case in drive letters. */
1301 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
1303 *fp += 'a' - 'A';
1304 fp += 2;
1307 if (NILP (Vw32_downcase_file_names))
1309 while (*fp)
1311 if (*fp == '/' || *fp == '\\')
1312 *fp = path_sep;
1313 fp++;
1315 return;
1318 sep = path_sep; /* convert to this path separator */
1319 elem = fp; /* start of current path element */
1321 do {
1322 if (*fp >= 'a' && *fp <= 'z')
1323 elem = 0; /* don't convert this element */
1325 if (*fp == 0 || *fp == ':')
1327 sep = *fp; /* restore current separator (or 0) */
1328 *fp = '/'; /* after conversion of this element */
1331 if (*fp == '/' || *fp == '\\')
1333 if (elem && elem != fp)
1335 *fp = 0; /* temporary end of string */
1336 _strlwr (elem); /* while we convert to lower case */
1338 *fp = sep; /* convert (or restore) path separator */
1339 elem = fp + 1; /* next element starts after separator */
1340 sep = path_sep;
1342 } while (*fp++);
1345 /* Destructively turn backslashes into slashes. */
1346 void
1347 dostounix_filename (register char *p)
1349 normalize_filename (p, '/');
1352 /* Destructively turn slashes into backslashes. */
1353 void
1354 unixtodos_filename (register char *p)
1356 normalize_filename (p, '\\');
1359 /* Remove all CR's that are followed by a LF.
1360 (From msdos.c...probably should figure out a way to share it,
1361 although this code isn't going to ever change.) */
1362 static int
1363 crlf_to_lf (register int n, register unsigned char *buf)
1365 unsigned char *np = buf;
1366 unsigned char *startp = buf;
1367 unsigned char *endp = buf + n;
1369 if (n == 0)
1370 return n;
1371 while (buf < endp - 1)
1373 if (*buf == 0x0d)
1375 if (*(++buf) != 0x0a)
1376 *np++ = 0x0d;
1378 else
1379 *np++ = *buf++;
1381 if (buf < endp)
1382 *np++ = *buf++;
1383 return np - startp;
1386 /* Parse the root part of file name, if present. Return length and
1387 optionally store pointer to char after root. */
1388 static int
1389 parse_root (char * name, char ** pPath)
1391 char * start = name;
1393 if (name == NULL)
1394 return 0;
1396 /* find the root name of the volume if given */
1397 if (isalpha (name[0]) && name[1] == ':')
1399 /* skip past drive specifier */
1400 name += 2;
1401 if (IS_DIRECTORY_SEP (name[0]))
1402 name++;
1404 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1406 int slashes = 2;
1407 name += 2;
1410 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1411 break;
1412 name++;
1414 while ( *name );
1415 if (IS_DIRECTORY_SEP (name[0]))
1416 name++;
1419 if (pPath)
1420 *pPath = name;
1422 return name - start;
1425 /* Get long base name for name; name is assumed to be absolute. */
1426 static int
1427 get_long_basename (char * name, char * buf, int size)
1429 WIN32_FIND_DATA find_data;
1430 HANDLE dir_handle;
1431 int len = 0;
1433 /* must be valid filename, no wild cards or other invalid characters */
1434 if (_mbspbrk (name, "*?|<>\""))
1435 return 0;
1437 dir_handle = FindFirstFile (name, &find_data);
1438 if (dir_handle != INVALID_HANDLE_VALUE)
1440 if ((len = strlen (find_data.cFileName)) < size)
1441 memcpy (buf, find_data.cFileName, len + 1);
1442 else
1443 len = 0;
1444 FindClose (dir_handle);
1446 return len;
1449 /* Get long name for file, if possible (assumed to be absolute). */
1450 BOOL
1451 w32_get_long_filename (char * name, char * buf, int size)
1453 char * o = buf;
1454 char * p;
1455 char * q;
1456 char full[ MAX_PATH ];
1457 int len;
1459 len = strlen (name);
1460 if (len >= MAX_PATH)
1461 return FALSE;
1463 /* Use local copy for destructive modification. */
1464 memcpy (full, name, len+1);
1465 unixtodos_filename (full);
1467 /* Copy root part verbatim. */
1468 len = parse_root (full, &p);
1469 memcpy (o, full, len);
1470 o += len;
1471 *o = '\0';
1472 size -= len;
1474 while (p != NULL && *p)
1476 q = p;
1477 p = strchr (q, '\\');
1478 if (p) *p = '\0';
1479 len = get_long_basename (full, o, size);
1480 if (len > 0)
1482 o += len;
1483 size -= len;
1484 if (p != NULL)
1486 *p++ = '\\';
1487 if (size < 2)
1488 return FALSE;
1489 *o++ = '\\';
1490 size--;
1491 *o = '\0';
1494 else
1495 return FALSE;
1498 return TRUE;
1501 static int
1502 is_unc_volume (const char *filename)
1504 const char *ptr = filename;
1506 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1507 return 0;
1509 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1510 return 0;
1512 return 1;
1515 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1517 LPBYTE
1518 w32_get_resource (char *key, LPDWORD lpdwtype)
1520 LPBYTE lpvalue;
1521 HKEY hrootkey = NULL;
1522 DWORD cbData;
1524 /* Check both the current user and the local machine to see if
1525 we have any resources. */
1527 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1529 lpvalue = NULL;
1531 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1532 && (lpvalue = xmalloc (cbData)) != NULL
1533 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1535 RegCloseKey (hrootkey);
1536 return (lpvalue);
1539 xfree (lpvalue);
1541 RegCloseKey (hrootkey);
1544 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1546 lpvalue = NULL;
1548 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1549 && (lpvalue = xmalloc (cbData)) != NULL
1550 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1552 RegCloseKey (hrootkey);
1553 return (lpvalue);
1556 xfree (lpvalue);
1558 RegCloseKey (hrootkey);
1561 return (NULL);
1564 char *get_emacs_configuration (void);
1566 void
1567 init_environment (char ** argv)
1569 static const char * const tempdirs[] = {
1570 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1573 int i;
1575 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1577 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1578 temporary files and assume "/tmp" if $TMPDIR is unset, which
1579 will break on DOS/Windows. Refuse to work if we cannot find
1580 a directory, not even "c:/", usable for that purpose. */
1581 for (i = 0; i < imax ; i++)
1583 const char *tmp = tempdirs[i];
1585 if (*tmp == '$')
1586 tmp = getenv (tmp + 1);
1587 /* Note that `access' can lie to us if the directory resides on a
1588 read-only filesystem, like CD-ROM or a write-protected floppy.
1589 The only way to be really sure is to actually create a file and
1590 see if it succeeds. But I think that's too much to ask. */
1592 /* MSVCRT's _access crashes with D_OK. */
1593 if (tmp && sys_access (tmp, D_OK) == 0)
1595 char * var = alloca (strlen (tmp) + 8);
1596 sprintf (var, "TMPDIR=%s", tmp);
1597 _putenv (strdup (var));
1598 break;
1601 if (i >= imax)
1602 cmd_error_internal
1603 (Fcons (Qerror,
1604 Fcons (build_string ("no usable temporary directories found!!"),
1605 Qnil)),
1606 "While setting TMPDIR: ");
1608 /* Check for environment variables and use registry settings if they
1609 don't exist. Fallback on default values where applicable. */
1611 int i;
1612 LPBYTE lpval;
1613 DWORD dwType;
1614 char locale_name[32];
1615 struct stat ignored;
1616 char default_home[MAX_PATH];
1617 int appdata = 0;
1619 static const struct env_entry
1621 char * name;
1622 char * def_value;
1623 } dflt_envvars[] =
1625 /* If the default value is NULL, we will use the value from the
1626 outside environment or the Registry, but will not push the
1627 variable into the Emacs environment if it is defined neither
1628 in the Registry nor in the outside environment. */
1629 {"HOME", "C:/"},
1630 {"PRELOAD_WINSOCK", NULL},
1631 {"emacs_dir", "C:/emacs"},
1632 {"EMACSLOADPATH", NULL},
1633 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1634 {"EMACSDATA", NULL},
1635 {"EMACSPATH", NULL},
1636 {"INFOPATH", NULL},
1637 {"EMACSDOC", NULL},
1638 {"TERM", "cmd"},
1639 {"LANG", NULL},
1642 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1644 /* We need to copy dflt_envvars[] and work on the copy because we
1645 don't want the dumped Emacs to inherit the values of
1646 environment variables we saw during dumping (which could be on
1647 a different system). The defaults above must be left intact. */
1648 struct env_entry env_vars[N_ENV_VARS];
1650 for (i = 0; i < N_ENV_VARS; i++)
1651 env_vars[i] = dflt_envvars[i];
1653 /* For backwards compatibility, check if a .emacs file exists in C:/
1654 If not, then we can try to default to the appdata directory under the
1655 user's profile, which is more likely to be writable. */
1656 if (stat ("C:/.emacs", &ignored) < 0)
1658 HRESULT profile_result;
1659 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1660 of Windows 95 and NT4 that have not been updated to include
1661 MSIE 5. */
1662 ShGetFolderPath_fn get_folder_path;
1663 get_folder_path = (ShGetFolderPath_fn)
1664 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1666 if (get_folder_path != NULL)
1668 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1669 0, default_home);
1671 /* If we can't get the appdata dir, revert to old behavior. */
1672 if (profile_result == S_OK)
1674 env_vars[0].def_value = default_home;
1675 appdata = 1;
1680 /* Get default locale info and use it for LANG. */
1681 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1682 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1683 locale_name, sizeof (locale_name)))
1685 for (i = 0; i < N_ENV_VARS; i++)
1687 if (strcmp (env_vars[i].name, "LANG") == 0)
1689 env_vars[i].def_value = locale_name;
1690 break;
1695 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1697 /* Treat emacs_dir specially: set it unconditionally based on our
1698 location. */
1700 char *p;
1701 char modname[MAX_PATH];
1703 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1704 emacs_abort ();
1705 if ((p = strrchr (modname, '\\')) == NULL)
1706 emacs_abort ();
1707 *p = 0;
1709 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1711 char buf[SET_ENV_BUF_SIZE];
1713 *p = 0;
1714 for (p = modname; *p; p++)
1715 if (*p == '\\') *p = '/';
1717 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1718 _putenv (strdup (buf));
1720 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1722 /* FIXME: should use substring of get_emacs_configuration ().
1723 But I don't think the Windows build supports alpha, mips etc
1724 anymore, so have taken the easy option for now. */
1725 else if (p && (xstrcasecmp (p, "\\i386") == 0
1726 || xstrcasecmp (p, "\\AMD64") == 0))
1728 *p = 0;
1729 p = strrchr (modname, '\\');
1730 if (p != NULL)
1732 *p = 0;
1733 p = strrchr (modname, '\\');
1734 if (p && xstrcasecmp (p, "\\src") == 0)
1736 char buf[SET_ENV_BUF_SIZE];
1738 *p = 0;
1739 for (p = modname; *p; p++)
1740 if (*p == '\\') *p = '/';
1742 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1743 _putenv (strdup (buf));
1749 for (i = 0; i < N_ENV_VARS; i++)
1751 if (!getenv (env_vars[i].name))
1753 int dont_free = 0;
1755 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1756 /* Also ignore empty environment variables. */
1757 || *lpval == 0)
1759 xfree (lpval);
1760 lpval = env_vars[i].def_value;
1761 dwType = REG_EXPAND_SZ;
1762 dont_free = 1;
1763 if (!strcmp (env_vars[i].name, "HOME") && !appdata)
1764 Vdelayed_warnings_list
1765 = Fcons (listn (CONSTYPE_HEAP, 2,
1766 intern ("initialization"),
1767 build_string ("Setting HOME to C:\\ by default is deprecated")),
1768 Vdelayed_warnings_list);
1771 if (lpval)
1773 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1775 if (dwType == REG_EXPAND_SZ)
1776 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
1777 else if (dwType == REG_SZ)
1778 strcpy (buf1, lpval);
1779 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1781 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
1782 buf1);
1783 _putenv (strdup (buf2));
1786 if (!dont_free)
1787 xfree (lpval);
1793 /* Rebuild system configuration to reflect invoking system. */
1794 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1796 /* Another special case: on NT, the PATH variable is actually named
1797 "Path" although cmd.exe (perhaps NT itself) arranges for
1798 environment variable lookup and setting to be case insensitive.
1799 However, Emacs assumes a fully case sensitive environment, so we
1800 need to change "Path" to "PATH" to match the expectations of
1801 various elisp packages. We do this by the sneaky method of
1802 modifying the string in the C runtime environ entry.
1804 The same applies to COMSPEC. */
1806 char ** envp;
1808 for (envp = environ; *envp; envp++)
1809 if (_strnicmp (*envp, "PATH=", 5) == 0)
1810 memcpy (*envp, "PATH=", 5);
1811 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1812 memcpy (*envp, "COMSPEC=", 8);
1815 /* Remember the initial working directory for getwd. */
1816 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
1817 Does it matter anywhere in Emacs? */
1818 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1819 emacs_abort ();
1822 static char modname[MAX_PATH];
1824 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1825 emacs_abort ();
1826 argv[0] = modname;
1829 /* Determine if there is a middle mouse button, to allow parse_button
1830 to decide whether right mouse events should be mouse-2 or
1831 mouse-3. */
1832 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1834 init_user_info ();
1837 /* Called from expand-file-name when default-directory is not a string. */
1839 char *
1840 emacs_root_dir (void)
1842 static char root_dir[FILENAME_MAX];
1843 const char *p;
1845 p = getenv ("emacs_dir");
1846 if (p == NULL)
1847 emacs_abort ();
1848 strcpy (root_dir, p);
1849 root_dir[parse_root (root_dir, NULL)] = '\0';
1850 dostounix_filename (root_dir);
1851 return root_dir;
1854 /* We don't have scripts to automatically determine the system configuration
1855 for Emacs before it's compiled, and we don't want to have to make the
1856 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1857 routine. */
1859 char *
1860 get_emacs_configuration (void)
1862 char *arch, *oem, *os;
1863 int build_num;
1864 static char configuration_buffer[32];
1866 /* Determine the processor type. */
1867 switch (get_processor_type ())
1870 #ifdef PROCESSOR_INTEL_386
1871 case PROCESSOR_INTEL_386:
1872 case PROCESSOR_INTEL_486:
1873 case PROCESSOR_INTEL_PENTIUM:
1874 #ifdef _WIN64
1875 arch = "amd64";
1876 #else
1877 arch = "i386";
1878 #endif
1879 break;
1880 #endif
1881 #ifdef PROCESSOR_AMD_X8664
1882 case PROCESSOR_AMD_X8664:
1883 arch = "amd64";
1884 break;
1885 #endif
1887 #ifdef PROCESSOR_MIPS_R2000
1888 case PROCESSOR_MIPS_R2000:
1889 case PROCESSOR_MIPS_R3000:
1890 case PROCESSOR_MIPS_R4000:
1891 arch = "mips";
1892 break;
1893 #endif
1895 #ifdef PROCESSOR_ALPHA_21064
1896 case PROCESSOR_ALPHA_21064:
1897 arch = "alpha";
1898 break;
1899 #endif
1901 default:
1902 arch = "unknown";
1903 break;
1906 /* Use the OEM field to reflect the compiler/library combination. */
1907 #ifdef _MSC_VER
1908 #define COMPILER_NAME "msvc"
1909 #else
1910 #ifdef __GNUC__
1911 #define COMPILER_NAME "mingw"
1912 #else
1913 #define COMPILER_NAME "unknown"
1914 #endif
1915 #endif
1916 oem = COMPILER_NAME;
1918 switch (osinfo_cache.dwPlatformId) {
1919 case VER_PLATFORM_WIN32_NT:
1920 os = "nt";
1921 build_num = osinfo_cache.dwBuildNumber;
1922 break;
1923 case VER_PLATFORM_WIN32_WINDOWS:
1924 if (osinfo_cache.dwMinorVersion == 0) {
1925 os = "windows95";
1926 } else {
1927 os = "windows98";
1929 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1930 break;
1931 case VER_PLATFORM_WIN32s:
1932 /* Not supported, should not happen. */
1933 os = "windows32s";
1934 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1935 break;
1936 default:
1937 os = "unknown";
1938 build_num = 0;
1939 break;
1942 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1943 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1944 get_w32_major_version (), get_w32_minor_version (), build_num);
1945 } else {
1946 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1949 return configuration_buffer;
1952 char *
1953 get_emacs_configuration_options (void)
1955 static char *options_buffer;
1956 char cv[32]; /* Enough for COMPILER_VERSION. */
1957 char *options[] = {
1958 cv, /* To be filled later. */
1959 #ifdef EMACSDEBUG
1960 " --no-opt",
1961 #endif
1962 #ifdef ENABLE_CHECKING
1963 " --enable-checking",
1964 #endif
1965 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1966 with a starting space to save work here. */
1967 #ifdef USER_CFLAGS
1968 " --cflags", USER_CFLAGS,
1969 #endif
1970 #ifdef USER_LDFLAGS
1971 " --ldflags", USER_LDFLAGS,
1972 #endif
1973 NULL
1975 size_t size = 0;
1976 int i;
1978 /* Work out the effective configure options for this build. */
1979 #ifdef _MSC_VER
1980 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1981 #else
1982 #ifdef __GNUC__
1983 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1984 #else
1985 #define COMPILER_VERSION ""
1986 #endif
1987 #endif
1989 if (_snprintf (cv, sizeof (cv) - 1, COMPILER_VERSION) < 0)
1990 return "Error: not enough space for compiler version";
1991 cv[sizeof (cv) - 1] = '\0';
1993 for (i = 0; options[i]; i++)
1994 size += strlen (options[i]);
1996 options_buffer = xmalloc (size + 1);
1997 options_buffer[0] = '\0';
1999 for (i = 0; options[i]; i++)
2000 strcat (options_buffer, options[i]);
2002 return options_buffer;
2006 #include <sys/timeb.h>
2008 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2009 void
2010 gettimeofday (struct timeval *tv, struct timezone *tz)
2012 struct _timeb tb;
2013 _ftime (&tb);
2015 tv->tv_sec = tb.time;
2016 tv->tv_usec = tb.millitm * 1000L;
2017 /* Implementation note: _ftime sometimes doesn't update the dstflag
2018 according to the new timezone when the system timezone is
2019 changed. We could fix that by using GetSystemTime and
2020 GetTimeZoneInformation, but that doesn't seem necessary, since
2021 Emacs always calls gettimeofday with the 2nd argument NULL (see
2022 current_emacs_time). */
2023 if (tz)
2025 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2026 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2030 /* Emulate fdutimens. */
2032 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2033 TIMESPEC[0] and TIMESPEC[1], respectively.
2034 FD must be either negative -- in which case it is ignored --
2035 or a file descriptor that is open on FILE.
2036 If FD is nonnegative, then FILE can be NULL, which means
2037 use just futimes instead of utimes.
2038 If TIMESPEC is null, FAIL.
2039 Return 0 on success, -1 (setting errno) on failure. */
2042 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2044 struct _utimbuf ut;
2046 if (!timespec)
2048 errno = ENOSYS;
2049 return -1;
2051 if (fd < 0 && !file)
2053 errno = EBADF;
2054 return -1;
2056 ut.actime = timespec[0].tv_sec;
2057 ut.modtime = timespec[1].tv_sec;
2058 if (fd >= 0)
2059 return _futime (fd, &ut);
2060 else
2061 return _utime (file, &ut);
2065 /* ------------------------------------------------------------------------- */
2066 /* IO support and wrapper functions for the Windows API. */
2067 /* ------------------------------------------------------------------------- */
2069 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2070 on network directories, so we handle that case here.
2071 (Ulrich Leodolter, 1/11/95). */
2072 char *
2073 sys_ctime (const time_t *t)
2075 char *str = (char *) ctime (t);
2076 return (str ? str : "Sun Jan 01 00:00:00 1970");
2079 /* Emulate sleep...we could have done this with a define, but that
2080 would necessitate including windows.h in the files that used it.
2081 This is much easier. */
2082 void
2083 sys_sleep (int seconds)
2085 Sleep (seconds * 1000);
2088 /* Internal MSVC functions for low-level descriptor munging */
2089 extern int __cdecl _set_osfhnd (int fd, long h);
2090 extern int __cdecl _free_osfhnd (int fd);
2092 /* parallel array of private info on file handles */
2093 filedesc fd_info [ MAXDESC ];
2095 typedef struct volume_info_data {
2096 struct volume_info_data * next;
2098 /* time when info was obtained */
2099 DWORD timestamp;
2101 /* actual volume info */
2102 char * root_dir;
2103 DWORD serialnum;
2104 DWORD maxcomp;
2105 DWORD flags;
2106 char * name;
2107 char * type;
2108 } volume_info_data;
2110 /* Global referenced by various functions. */
2111 static volume_info_data volume_info;
2113 /* Vector to indicate which drives are local and fixed (for which cached
2114 data never expires). */
2115 static BOOL fixed_drives[26];
2117 /* Consider cached volume information to be stale if older than 10s,
2118 at least for non-local drives. Info for fixed drives is never stale. */
2119 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2120 #define VOLINFO_STILL_VALID( root_dir, info ) \
2121 ( ( isalpha (root_dir[0]) && \
2122 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2123 || GetTickCount () - info->timestamp < 10000 )
2125 /* Cache support functions. */
2127 /* Simple linked list with linear search is sufficient. */
2128 static volume_info_data *volume_cache = NULL;
2130 static volume_info_data *
2131 lookup_volume_info (char * root_dir)
2133 volume_info_data * info;
2135 for (info = volume_cache; info; info = info->next)
2136 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2137 break;
2138 return info;
2141 static void
2142 add_volume_info (char * root_dir, volume_info_data * info)
2144 info->root_dir = xstrdup (root_dir);
2145 info->next = volume_cache;
2146 volume_cache = info;
2150 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2151 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2152 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2153 static volume_info_data *
2154 GetCachedVolumeInformation (char * root_dir)
2156 volume_info_data * info;
2157 char default_root[ MAX_PATH ];
2159 /* NULL for root_dir means use root from current directory. */
2160 if (root_dir == NULL)
2162 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
2163 return NULL;
2164 parse_root (default_root, &root_dir);
2165 *root_dir = 0;
2166 root_dir = default_root;
2169 /* Local fixed drives can be cached permanently. Removable drives
2170 cannot be cached permanently, since the volume name and serial
2171 number (if nothing else) can change. Remote drives should be
2172 treated as if they are removable, since there is no sure way to
2173 tell whether they are or not. Also, the UNC association of drive
2174 letters mapped to remote volumes can be changed at any time (even
2175 by other processes) without notice.
2177 As a compromise, so we can benefit from caching info for remote
2178 volumes, we use a simple expiry mechanism to invalidate cache
2179 entries that are more than ten seconds old. */
2181 #if 0
2182 /* No point doing this, because WNetGetConnection is even slower than
2183 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2184 GetDriveType is about the only call of this type which does not
2185 involve network access, and so is extremely quick). */
2187 /* Map drive letter to UNC if remote. */
2188 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2190 char remote_name[ 256 ];
2191 char drive[3] = { root_dir[0], ':' };
2193 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2194 == NO_ERROR)
2195 /* do something */ ;
2197 #endif
2199 info = lookup_volume_info (root_dir);
2201 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2203 char name[ 256 ];
2204 DWORD serialnum;
2205 DWORD maxcomp;
2206 DWORD flags;
2207 char type[ 256 ];
2209 /* Info is not cached, or is stale. */
2210 if (!GetVolumeInformation (root_dir,
2211 name, sizeof (name),
2212 &serialnum,
2213 &maxcomp,
2214 &flags,
2215 type, sizeof (type)))
2216 return NULL;
2218 /* Cache the volume information for future use, overwriting existing
2219 entry if present. */
2220 if (info == NULL)
2222 info = xmalloc (sizeof (volume_info_data));
2223 add_volume_info (root_dir, info);
2225 else
2227 xfree (info->name);
2228 xfree (info->type);
2231 info->name = xstrdup (name);
2232 info->serialnum = serialnum;
2233 info->maxcomp = maxcomp;
2234 info->flags = flags;
2235 info->type = xstrdup (type);
2236 info->timestamp = GetTickCount ();
2239 return info;
2242 /* Get information on the volume where NAME is held; set path pointer to
2243 start of pathname in NAME (past UNC header\volume header if present),
2244 if pPath is non-NULL.
2246 Note: if NAME includes symlinks, the information is for the volume
2247 of the symlink, not of its target. That's because, even though
2248 GetVolumeInformation returns information about the symlink target
2249 of its argument, we only pass the root directory to
2250 GetVolumeInformation, not the full NAME. */
2251 static int
2252 get_volume_info (const char * name, const char ** pPath)
2254 char temp[MAX_PATH];
2255 char *rootname = NULL; /* default to current volume */
2256 volume_info_data * info;
2258 if (name == NULL)
2259 return FALSE;
2261 /* Find the root name of the volume if given. */
2262 if (isalpha (name[0]) && name[1] == ':')
2264 rootname = temp;
2265 temp[0] = *name++;
2266 temp[1] = *name++;
2267 temp[2] = '\\';
2268 temp[3] = 0;
2270 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2272 char *str = temp;
2273 int slashes = 4;
2274 rootname = temp;
2277 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2278 break;
2279 *str++ = *name++;
2281 while ( *name );
2283 *str++ = '\\';
2284 *str = 0;
2287 if (pPath)
2288 *pPath = name;
2290 info = GetCachedVolumeInformation (rootname);
2291 if (info != NULL)
2293 /* Set global referenced by other functions. */
2294 volume_info = *info;
2295 return TRUE;
2297 return FALSE;
2300 /* Determine if volume is FAT format (ie. only supports short 8.3
2301 names); also set path pointer to start of pathname in name, if
2302 pPath is non-NULL. */
2303 static int
2304 is_fat_volume (const char * name, const char ** pPath)
2306 if (get_volume_info (name, pPath))
2307 return (volume_info.maxcomp == 12);
2308 return FALSE;
2311 /* Map filename to a valid 8.3 name if necessary.
2312 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2313 const char *
2314 map_w32_filename (const char * name, const char ** pPath)
2316 static char shortname[MAX_PATH];
2317 char * str = shortname;
2318 char c;
2319 char * path;
2320 const char * save_name = name;
2322 if (strlen (name) >= MAX_PATH)
2324 /* Return a filename which will cause callers to fail. */
2325 strcpy (shortname, "?");
2326 return shortname;
2329 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2331 register int left = 8; /* maximum number of chars in part */
2332 register int extn = 0; /* extension added? */
2333 register int dots = 2; /* maximum number of dots allowed */
2335 while (name < path)
2336 *str++ = *name++; /* skip past UNC header */
2338 while ((c = *name++))
2340 switch ( c )
2342 case ':':
2343 case '\\':
2344 case '/':
2345 *str++ = (c == ':' ? ':' : '\\');
2346 extn = 0; /* reset extension flags */
2347 dots = 2; /* max 2 dots */
2348 left = 8; /* max length 8 for main part */
2349 break;
2350 case '.':
2351 if ( dots )
2353 /* Convert path components of the form .xxx to _xxx,
2354 but leave . and .. as they are. This allows .emacs
2355 to be read as _emacs, for example. */
2357 if (! *name ||
2358 *name == '.' ||
2359 IS_DIRECTORY_SEP (*name))
2361 *str++ = '.';
2362 dots--;
2364 else
2366 *str++ = '_';
2367 left--;
2368 dots = 0;
2371 else if ( !extn )
2373 *str++ = '.';
2374 extn = 1; /* we've got an extension */
2375 left = 3; /* 3 chars in extension */
2377 else
2379 /* any embedded dots after the first are converted to _ */
2380 *str++ = '_';
2382 break;
2383 case '~':
2384 case '#': /* don't lose these, they're important */
2385 if ( ! left )
2386 str[-1] = c; /* replace last character of part */
2387 /* FALLTHRU */
2388 default:
2389 if ( left )
2391 *str++ = tolower (c); /* map to lower case (looks nicer) */
2392 left--;
2393 dots = 0; /* started a path component */
2395 break;
2398 *str = '\0';
2400 else
2402 strcpy (shortname, name);
2403 unixtodos_filename (shortname);
2406 if (pPath)
2407 *pPath = shortname + (path - save_name);
2409 return shortname;
2412 static int
2413 is_exec (const char * name)
2415 char * p = strrchr (name, '.');
2416 return
2417 (p != NULL
2418 && (xstrcasecmp (p, ".exe") == 0 ||
2419 xstrcasecmp (p, ".com") == 0 ||
2420 xstrcasecmp (p, ".bat") == 0 ||
2421 xstrcasecmp (p, ".cmd") == 0));
2424 /* Emulate the Unix directory procedures opendir, closedir,
2425 and readdir. We can't use the procedures supplied in sysdep.c,
2426 so we provide them here. */
2428 struct direct dir_static; /* simulated directory contents */
2429 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2430 static int dir_is_fat;
2431 static char dir_pathname[MAXPATHLEN+1];
2432 static WIN32_FIND_DATA dir_find_data;
2434 /* Support shares on a network resource as subdirectories of a read-only
2435 root directory. */
2436 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2437 static HANDLE open_unc_volume (const char *);
2438 static char *read_unc_volume (HANDLE, char *, int);
2439 static void close_unc_volume (HANDLE);
2441 DIR *
2442 opendir (char *filename)
2444 DIR *dirp;
2446 /* Opening is done by FindFirstFile. However, a read is inherent to
2447 this operation, so we defer the open until read time. */
2449 if (dir_find_handle != INVALID_HANDLE_VALUE)
2450 return NULL;
2451 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2452 return NULL;
2454 /* Note: We don't support traversal of UNC volumes via symlinks.
2455 Doing so would mean punishing 99.99% of use cases by resolving
2456 all the possible symlinks in FILENAME, recursively. */
2457 if (is_unc_volume (filename))
2459 wnet_enum_handle = open_unc_volume (filename);
2460 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2461 return NULL;
2464 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2465 return NULL;
2467 dirp->dd_fd = 0;
2468 dirp->dd_loc = 0;
2469 dirp->dd_size = 0;
2471 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2472 dir_pathname[MAXPATHLEN] = '\0';
2473 /* Note: We don't support symlinks to file names on FAT volumes.
2474 Doing so would mean punishing 99.99% of use cases by resolving
2475 all the possible symlinks in FILENAME, recursively. */
2476 dir_is_fat = is_fat_volume (filename, NULL);
2478 return dirp;
2481 void
2482 closedir (DIR *dirp)
2484 /* If we have a find-handle open, close it. */
2485 if (dir_find_handle != INVALID_HANDLE_VALUE)
2487 FindClose (dir_find_handle);
2488 dir_find_handle = INVALID_HANDLE_VALUE;
2490 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2492 close_unc_volume (wnet_enum_handle);
2493 wnet_enum_handle = INVALID_HANDLE_VALUE;
2495 xfree ((char *) dirp);
2498 struct direct *
2499 readdir (DIR *dirp)
2501 int downcase = !NILP (Vw32_downcase_file_names);
2503 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2505 if (!read_unc_volume (wnet_enum_handle,
2506 dir_find_data.cFileName,
2507 MAX_PATH))
2508 return NULL;
2510 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2511 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2513 char filename[MAXNAMLEN + 3];
2514 int ln;
2516 strcpy (filename, dir_pathname);
2517 ln = strlen (filename) - 1;
2518 if (!IS_DIRECTORY_SEP (filename[ln]))
2519 strcat (filename, "\\");
2520 strcat (filename, "*");
2522 /* Note: No need to resolve symlinks in FILENAME, because
2523 FindFirst opens the directory that is the target of a
2524 symlink. */
2525 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2527 if (dir_find_handle == INVALID_HANDLE_VALUE)
2528 return NULL;
2530 else
2532 if (!FindNextFile (dir_find_handle, &dir_find_data))
2533 return NULL;
2536 /* Emacs never uses this value, so don't bother making it match
2537 value returned by stat(). */
2538 dir_static.d_ino = 1;
2540 strcpy (dir_static.d_name, dir_find_data.cFileName);
2542 /* If the file name in cFileName[] includes `?' characters, it means
2543 the original file name used characters that cannot be represented
2544 by the current ANSI codepage. To avoid total lossage, retrieve
2545 the short 8+3 alias of the long file name. */
2546 if (_mbspbrk (dir_static.d_name, "?"))
2548 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2549 downcase = 1; /* 8+3 aliases are returned in all caps */
2551 dir_static.d_namlen = strlen (dir_static.d_name);
2552 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
2553 dir_static.d_namlen - dir_static.d_namlen % 4;
2555 /* If the file name in cFileName[] includes `?' characters, it means
2556 the original file name used characters that cannot be represented
2557 by the current ANSI codepage. To avoid total lossage, retrieve
2558 the short 8+3 alias of the long file name. */
2559 if (_mbspbrk (dir_find_data.cFileName, "?"))
2561 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2562 /* 8+3 aliases are returned in all caps, which could break
2563 various alists that look at filenames' extensions. */
2564 downcase = 1;
2566 else
2567 strcpy (dir_static.d_name, dir_find_data.cFileName);
2568 dir_static.d_namlen = strlen (dir_static.d_name);
2569 if (dir_is_fat)
2570 _strlwr (dir_static.d_name);
2571 else if (downcase)
2573 register char *p;
2574 for (p = dir_static.d_name; *p; p++)
2575 if (*p >= 'a' && *p <= 'z')
2576 break;
2577 if (!*p)
2578 _strlwr (dir_static.d_name);
2581 return &dir_static;
2584 static HANDLE
2585 open_unc_volume (const char *path)
2587 NETRESOURCE nr;
2588 HANDLE henum;
2589 int result;
2591 nr.dwScope = RESOURCE_GLOBALNET;
2592 nr.dwType = RESOURCETYPE_DISK;
2593 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2594 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2595 nr.lpLocalName = NULL;
2596 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
2597 nr.lpComment = NULL;
2598 nr.lpProvider = NULL;
2600 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2601 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2603 if (result == NO_ERROR)
2604 return henum;
2605 else
2606 return INVALID_HANDLE_VALUE;
2609 static char *
2610 read_unc_volume (HANDLE henum, char *readbuf, int size)
2612 DWORD count;
2613 int result;
2614 DWORD bufsize = 512;
2615 char *buffer;
2616 char *ptr;
2618 count = 1;
2619 buffer = alloca (bufsize);
2620 result = WNetEnumResource (henum, &count, buffer, &bufsize);
2621 if (result != NO_ERROR)
2622 return NULL;
2624 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2625 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2626 ptr += 2;
2627 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2628 ptr++;
2630 strncpy (readbuf, ptr, size);
2631 return readbuf;
2634 static void
2635 close_unc_volume (HANDLE henum)
2637 if (henum != INVALID_HANDLE_VALUE)
2638 WNetCloseEnum (henum);
2641 static DWORD
2642 unc_volume_file_attributes (const char *path)
2644 HANDLE henum;
2645 DWORD attrs;
2647 henum = open_unc_volume (path);
2648 if (henum == INVALID_HANDLE_VALUE)
2649 return -1;
2651 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2653 close_unc_volume (henum);
2655 return attrs;
2658 /* Ensure a network connection is authenticated. */
2659 static void
2660 logon_network_drive (const char *path)
2662 NETRESOURCE resource;
2663 char share[MAX_PATH];
2664 int i, n_slashes;
2665 char drive[4];
2666 UINT drvtype;
2668 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
2669 drvtype = DRIVE_REMOTE;
2670 else if (path[0] == '\0' || path[1] != ':')
2671 drvtype = GetDriveType (NULL);
2672 else
2674 drive[0] = path[0];
2675 drive[1] = ':';
2676 drive[2] = '\\';
2677 drive[3] = '\0';
2678 drvtype = GetDriveType (drive);
2681 /* Only logon to networked drives. */
2682 if (drvtype != DRIVE_REMOTE)
2683 return;
2685 n_slashes = 2;
2686 strncpy (share, path, MAX_PATH);
2687 /* Truncate to just server and share name. */
2688 for (i = 2; i < MAX_PATH; i++)
2690 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2692 share[i] = '\0';
2693 break;
2697 resource.dwType = RESOURCETYPE_DISK;
2698 resource.lpLocalName = NULL;
2699 resource.lpRemoteName = share;
2700 resource.lpProvider = NULL;
2702 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2705 /* Shadow some MSVC runtime functions to map requests for long filenames
2706 to reasonable short names if necessary. This was originally added to
2707 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2708 long file names. */
2711 sys_access (const char * path, int mode)
2713 DWORD attributes;
2715 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
2716 newer versions blow up when passed D_OK. */
2717 path = map_w32_filename (path, NULL);
2718 /* If the last element of PATH is a symlink, we need to resolve it
2719 to get the attributes of its target file. Note: any symlinks in
2720 PATH elements other than the last one are transparently resolved
2721 by GetFileAttributes below. */
2722 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
2723 path = chase_symlinks (path);
2725 if ((attributes = GetFileAttributes (path)) == -1)
2727 DWORD w32err = GetLastError ();
2729 switch (w32err)
2731 case ERROR_INVALID_NAME:
2732 case ERROR_BAD_PATHNAME:
2733 if (is_unc_volume (path))
2735 attributes = unc_volume_file_attributes (path);
2736 if (attributes == -1)
2738 errno = EACCES;
2739 return -1;
2741 break;
2743 /* FALLTHROUGH */
2744 case ERROR_FILE_NOT_FOUND:
2745 case ERROR_BAD_NETPATH:
2746 errno = ENOENT;
2747 break;
2748 default:
2749 errno = EACCES;
2750 break;
2752 return -1;
2754 if ((mode & X_OK) != 0 && !is_exec (path))
2756 errno = EACCES;
2757 return -1;
2759 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2761 errno = EACCES;
2762 return -1;
2764 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2766 errno = EACCES;
2767 return -1;
2769 return 0;
2773 sys_chdir (const char * path)
2775 return _chdir (map_w32_filename (path, NULL));
2779 sys_chmod (const char * path, int mode)
2781 path = chase_symlinks (map_w32_filename (path, NULL));
2782 return _chmod (path, mode);
2786 sys_chown (const char *path, uid_t owner, gid_t group)
2788 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2789 return -1;
2790 return 0;
2794 sys_creat (const char * path, int mode)
2796 return _creat (map_w32_filename (path, NULL), mode);
2799 FILE *
2800 sys_fopen (const char * path, const char * mode)
2802 int fd;
2803 int oflag;
2804 const char * mode_save = mode;
2806 /* Force all file handles to be non-inheritable. This is necessary to
2807 ensure child processes don't unwittingly inherit handles that might
2808 prevent future file access. */
2810 if (mode[0] == 'r')
2811 oflag = O_RDONLY;
2812 else if (mode[0] == 'w' || mode[0] == 'a')
2813 oflag = O_WRONLY | O_CREAT | O_TRUNC;
2814 else
2815 return NULL;
2817 /* Only do simplistic option parsing. */
2818 while (*++mode)
2819 if (mode[0] == '+')
2821 oflag &= ~(O_RDONLY | O_WRONLY);
2822 oflag |= O_RDWR;
2824 else if (mode[0] == 'b')
2826 oflag &= ~O_TEXT;
2827 oflag |= O_BINARY;
2829 else if (mode[0] == 't')
2831 oflag &= ~O_BINARY;
2832 oflag |= O_TEXT;
2834 else break;
2836 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2837 if (fd < 0)
2838 return NULL;
2840 return _fdopen (fd, mode_save);
2843 /* This only works on NTFS volumes, but is useful to have. */
2845 sys_link (const char * old, const char * new)
2847 HANDLE fileh;
2848 int result = -1;
2849 char oldname[MAX_PATH], newname[MAX_PATH];
2851 if (old == NULL || new == NULL)
2853 errno = ENOENT;
2854 return -1;
2857 strcpy (oldname, map_w32_filename (old, NULL));
2858 strcpy (newname, map_w32_filename (new, NULL));
2860 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2861 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2862 if (fileh != INVALID_HANDLE_VALUE)
2864 int wlen;
2866 /* Confusingly, the "alternate" stream name field does not apply
2867 when restoring a hard link, and instead contains the actual
2868 stream data for the link (ie. the name of the link to create).
2869 The WIN32_STREAM_ID structure before the cStreamName field is
2870 the stream header, which is then immediately followed by the
2871 stream data. */
2873 struct {
2874 WIN32_STREAM_ID wid;
2875 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2876 } data;
2878 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2879 data.wid.cStreamName, MAX_PATH);
2880 if (wlen > 0)
2882 LPVOID context = NULL;
2883 DWORD wbytes = 0;
2885 data.wid.dwStreamId = BACKUP_LINK;
2886 data.wid.dwStreamAttributes = 0;
2887 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
2888 data.wid.Size.HighPart = 0;
2889 data.wid.dwStreamNameSize = 0;
2891 if (BackupWrite (fileh, (LPBYTE)&data,
2892 offsetof (WIN32_STREAM_ID, cStreamName)
2893 + data.wid.Size.LowPart,
2894 &wbytes, FALSE, FALSE, &context)
2895 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2897 /* succeeded */
2898 result = 0;
2900 else
2902 /* Should try mapping GetLastError to errno; for now just
2903 indicate a general error (eg. links not supported). */
2904 errno = EINVAL; // perhaps EMLINK?
2908 CloseHandle (fileh);
2910 else
2911 errno = ENOENT;
2913 return result;
2917 sys_mkdir (const char * path)
2919 return _mkdir (map_w32_filename (path, NULL));
2922 /* Because of long name mapping issues, we need to implement this
2923 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2924 a unique name, instead of setting the input template to an empty
2925 string.
2927 Standard algorithm seems to be use pid or tid with a letter on the
2928 front (in place of the 6 X's) and cycle through the letters to find a
2929 unique name. We extend that to allow any reasonable character as the
2930 first of the 6 X's. */
2931 char *
2932 sys_mktemp (char * template)
2934 char * p;
2935 int i;
2936 unsigned uid = GetCurrentThreadId ();
2937 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2939 if (template == NULL)
2940 return NULL;
2941 p = template + strlen (template);
2942 i = 5;
2943 /* replace up to the last 5 X's with uid in decimal */
2944 while (--p >= template && p[0] == 'X' && --i >= 0)
2946 p[0] = '0' + uid % 10;
2947 uid /= 10;
2950 if (i < 0 && p[0] == 'X')
2952 i = 0;
2955 int save_errno = errno;
2956 p[0] = first_char[i];
2957 if (sys_access (template, 0) < 0)
2959 errno = save_errno;
2960 return template;
2963 while (++i < sizeof (first_char));
2966 /* Template is badly formed or else we can't generate a unique name,
2967 so return empty string */
2968 template[0] = 0;
2969 return template;
2973 sys_open (const char * path, int oflag, int mode)
2975 const char* mpath = map_w32_filename (path, NULL);
2976 /* Try to open file without _O_CREAT, to be able to write to hidden
2977 and system files. Force all file handles to be
2978 non-inheritable. */
2979 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2980 if (res >= 0)
2981 return res;
2982 return _open (mpath, oflag | _O_NOINHERIT, mode);
2986 sys_rename (const char * oldname, const char * newname)
2988 BOOL result;
2989 char temp[MAX_PATH];
2990 int newname_dev;
2991 int oldname_dev;
2993 /* MoveFile on Windows 95 doesn't correctly change the short file name
2994 alias in a number of circumstances (it is not easy to predict when
2995 just by looking at oldname and newname, unfortunately). In these
2996 cases, renaming through a temporary name avoids the problem.
2998 A second problem on Windows 95 is that renaming through a temp name when
2999 newname is uppercase fails (the final long name ends up in
3000 lowercase, although the short alias might be uppercase) UNLESS the
3001 long temp name is not 8.3.
3003 So, on Windows 95 we always rename through a temp name, and we make sure
3004 the temp name has a long extension to ensure correct renaming. */
3006 strcpy (temp, map_w32_filename (oldname, NULL));
3008 /* volume_info is set indirectly by map_w32_filename. */
3009 oldname_dev = volume_info.serialnum;
3011 if (os_subtype == OS_9X)
3013 char * o;
3014 char * p;
3015 int i = 0;
3017 oldname = map_w32_filename (oldname, NULL);
3018 if ((o = strrchr (oldname, '\\')))
3019 o++;
3020 else
3021 o = (char *) oldname;
3023 if ((p = strrchr (temp, '\\')))
3024 p++;
3025 else
3026 p = temp;
3030 /* Force temp name to require a manufactured 8.3 alias - this
3031 seems to make the second rename work properly. */
3032 sprintf (p, "_.%s.%u", o, i);
3033 i++;
3034 result = rename (oldname, temp);
3036 /* This loop must surely terminate! */
3037 while (result < 0 && errno == EEXIST);
3038 if (result < 0)
3039 return -1;
3042 /* Emulate Unix behavior - newname is deleted if it already exists
3043 (at least if it is a file; don't do this for directories).
3045 Since we mustn't do this if we are just changing the case of the
3046 file name (we would end up deleting the file we are trying to
3047 rename!), we let rename detect if the destination file already
3048 exists - that way we avoid the possible pitfalls of trying to
3049 determine ourselves whether two names really refer to the same
3050 file, which is not always possible in the general case. (Consider
3051 all the permutations of shared or subst'd drives, etc.) */
3053 newname = map_w32_filename (newname, NULL);
3055 /* volume_info is set indirectly by map_w32_filename. */
3056 newname_dev = volume_info.serialnum;
3058 result = rename (temp, newname);
3060 if (result < 0)
3062 DWORD w32err = GetLastError ();
3064 if (errno == EACCES
3065 && newname_dev != oldname_dev)
3067 /* The implementation of `rename' on Windows does not return
3068 errno = EXDEV when you are moving a directory to a
3069 different storage device (ex. logical disk). It returns
3070 EACCES instead. So here we handle such situations and
3071 return EXDEV. */
3072 DWORD attributes;
3074 if ((attributes = GetFileAttributes (temp)) != -1
3075 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
3076 errno = EXDEV;
3078 else if (errno == EEXIST)
3080 if (_chmod (newname, 0666) != 0)
3081 return result;
3082 if (_unlink (newname) != 0)
3083 return result;
3084 result = rename (temp, newname);
3086 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
3087 && is_symlink (temp))
3089 /* This is Windows prohibiting the user from creating a
3090 symlink in another place, since that requires
3091 privileges. */
3092 errno = EPERM;
3096 return result;
3100 sys_rmdir (const char * path)
3102 return _rmdir (map_w32_filename (path, NULL));
3106 sys_unlink (const char * path)
3108 path = map_w32_filename (path, NULL);
3110 /* On Unix, unlink works without write permission. */
3111 _chmod (path, 0666);
3112 return _unlink (path);
3115 static FILETIME utc_base_ft;
3116 static ULONGLONG utc_base; /* In 100ns units */
3117 static int init = 0;
3119 #define FILETIME_TO_U64(result, ft) \
3120 do { \
3121 ULARGE_INTEGER uiTemp; \
3122 uiTemp.LowPart = (ft).dwLowDateTime; \
3123 uiTemp.HighPart = (ft).dwHighDateTime; \
3124 result = uiTemp.QuadPart; \
3125 } while (0)
3127 static void
3128 initialize_utc_base (void)
3130 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3131 SYSTEMTIME st;
3133 st.wYear = 1970;
3134 st.wMonth = 1;
3135 st.wDay = 1;
3136 st.wHour = 0;
3137 st.wMinute = 0;
3138 st.wSecond = 0;
3139 st.wMilliseconds = 0;
3141 SystemTimeToFileTime (&st, &utc_base_ft);
3142 FILETIME_TO_U64 (utc_base, utc_base_ft);
3145 static time_t
3146 convert_time (FILETIME ft)
3148 ULONGLONG tmp;
3150 if (!init)
3152 initialize_utc_base ();
3153 init = 1;
3156 if (CompareFileTime (&ft, &utc_base_ft) < 0)
3157 return 0;
3159 FILETIME_TO_U64 (tmp, ft);
3160 return (time_t) ((tmp - utc_base) / 10000000L);
3163 static void
3164 convert_from_time_t (time_t time, FILETIME * pft)
3166 ULARGE_INTEGER tmp;
3168 if (!init)
3170 initialize_utc_base ();
3171 init = 1;
3174 /* time in 100ns units since 1-Jan-1601 */
3175 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
3176 pft->dwHighDateTime = tmp.HighPart;
3177 pft->dwLowDateTime = tmp.LowPart;
3180 #if 0
3181 /* No reason to keep this; faking inode values either by hashing or even
3182 using the file index from GetInformationByHandle, is not perfect and
3183 so by default Emacs doesn't use the inode values on Windows.
3184 Instead, we now determine file-truename correctly (except for
3185 possible drive aliasing etc). */
3187 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3188 static unsigned
3189 hashval (const unsigned char * str)
3191 unsigned h = 0;
3192 while (*str)
3194 h = (h << 4) + *str++;
3195 h ^= (h >> 28);
3197 return h;
3200 /* Return the hash value of the canonical pathname, excluding the
3201 drive/UNC header, to get a hopefully unique inode number. */
3202 static DWORD
3203 generate_inode_val (const char * name)
3205 char fullname[ MAX_PATH ];
3206 char * p;
3207 unsigned hash;
3209 /* Get the truly canonical filename, if it exists. (Note: this
3210 doesn't resolve aliasing due to subst commands, or recognize hard
3211 links. */
3212 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3213 emacs_abort ();
3215 parse_root (fullname, &p);
3216 /* Normal W32 filesystems are still case insensitive. */
3217 _strlwr (p);
3218 return hashval (p);
3221 #endif
3223 static PSECURITY_DESCRIPTOR
3224 get_file_security_desc_by_handle (HANDLE h)
3226 PSECURITY_DESCRIPTOR psd = NULL;
3227 DWORD err;
3228 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3229 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3231 err = get_security_info (h, SE_FILE_OBJECT, si,
3232 NULL, NULL, NULL, NULL, &psd);
3233 if (err != ERROR_SUCCESS)
3234 return NULL;
3236 return psd;
3239 static PSECURITY_DESCRIPTOR
3240 get_file_security_desc_by_name (const char *fname)
3242 PSECURITY_DESCRIPTOR psd = NULL;
3243 DWORD sd_len, err;
3244 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3245 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3247 if (!get_file_security (fname, si, psd, 0, &sd_len))
3249 err = GetLastError ();
3250 if (err != ERROR_INSUFFICIENT_BUFFER)
3251 return NULL;
3254 psd = xmalloc (sd_len);
3255 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3257 xfree (psd);
3258 return NULL;
3261 return psd;
3264 static DWORD
3265 get_rid (PSID sid)
3267 unsigned n_subauthorities;
3269 /* Use the last sub-authority value of the RID, the relative
3270 portion of the SID, as user/group ID. */
3271 n_subauthorities = *get_sid_sub_authority_count (sid);
3272 if (n_subauthorities < 1)
3273 return 0; /* the "World" RID */
3274 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3277 /* Caching SID and account values for faster lokup. */
3279 #ifdef __GNUC__
3280 # define FLEXIBLE_ARRAY_MEMBER
3281 #else
3282 # define FLEXIBLE_ARRAY_MEMBER 1
3283 #endif
3285 struct w32_id {
3286 unsigned rid;
3287 struct w32_id *next;
3288 char name[GNLEN+1];
3289 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3292 static struct w32_id *w32_idlist;
3294 static int
3295 w32_cached_id (PSID sid, unsigned *id, char *name)
3297 struct w32_id *tail, *found;
3299 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3301 if (equal_sid ((PSID)tail->sid, sid))
3303 found = tail;
3304 break;
3307 if (found)
3309 *id = found->rid;
3310 strcpy (name, found->name);
3311 return 1;
3313 else
3314 return 0;
3317 static void
3318 w32_add_to_cache (PSID sid, unsigned id, char *name)
3320 DWORD sid_len;
3321 struct w32_id *new_entry;
3323 /* We don't want to leave behind stale cache from when Emacs was
3324 dumped. */
3325 if (initialized)
3327 sid_len = get_length_sid (sid);
3328 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3329 if (new_entry)
3331 new_entry->rid = id;
3332 strcpy (new_entry->name, name);
3333 copy_sid (sid_len, (PSID)new_entry->sid, sid);
3334 new_entry->next = w32_idlist;
3335 w32_idlist = new_entry;
3340 #define UID 1
3341 #define GID 2
3343 static int
3344 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
3345 unsigned *id, char *nm, int what)
3347 PSID sid = NULL;
3348 char machine[MAX_COMPUTERNAME_LENGTH+1];
3349 BOOL dflt;
3350 SID_NAME_USE ignore;
3351 char name[UNLEN+1];
3352 DWORD name_len = sizeof (name);
3353 char domain[1024];
3354 DWORD domain_len = sizeof (domain);
3355 char *mp = NULL;
3356 int use_dflt = 0;
3357 int result;
3359 if (what == UID)
3360 result = get_security_descriptor_owner (psd, &sid, &dflt);
3361 else if (what == GID)
3362 result = get_security_descriptor_group (psd, &sid, &dflt);
3363 else
3364 result = 0;
3366 if (!result || !is_valid_sid (sid))
3367 use_dflt = 1;
3368 else if (!w32_cached_id (sid, id, nm))
3370 /* If FNAME is a UNC, we need to lookup account on the
3371 specified machine. */
3372 if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
3373 && fname[2] != '\0')
3375 const char *s;
3376 char *p;
3378 for (s = fname + 2, p = machine;
3379 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
3380 *p = *s;
3381 *p = '\0';
3382 mp = machine;
3385 if (!lookup_account_sid (mp, sid, name, &name_len,
3386 domain, &domain_len, &ignore)
3387 || name_len > UNLEN+1)
3388 use_dflt = 1;
3389 else
3391 *id = get_rid (sid);
3392 strcpy (nm, name);
3393 w32_add_to_cache (sid, *id, name);
3396 return use_dflt;
3399 static void
3400 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd,
3401 const char *fname,
3402 struct stat *st)
3404 int dflt_usr = 0, dflt_grp = 0;
3406 if (!psd)
3408 dflt_usr = 1;
3409 dflt_grp = 1;
3411 else
3413 if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
3414 dflt_usr = 1;
3415 if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
3416 dflt_grp = 1;
3418 /* Consider files to belong to current user/group, if we cannot get
3419 more accurate information. */
3420 if (dflt_usr)
3422 st->st_uid = dflt_passwd.pw_uid;
3423 strcpy (st->st_uname, dflt_passwd.pw_name);
3425 if (dflt_grp)
3427 st->st_gid = dflt_passwd.pw_gid;
3428 strcpy (st->st_gname, dflt_group.gr_name);
3432 /* Return non-zero if NAME is a potentially slow filesystem. */
3434 is_slow_fs (const char *name)
3436 char drive_root[4];
3437 UINT devtype;
3439 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
3440 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
3441 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
3442 devtype = GetDriveType (NULL); /* use root of current drive */
3443 else
3445 /* GetDriveType needs the root directory of the drive. */
3446 strncpy (drive_root, name, 2);
3447 drive_root[2] = '\\';
3448 drive_root[3] = '\0';
3449 devtype = GetDriveType (drive_root);
3451 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
3454 /* MSVC stat function can't cope with UNC names and has other bugs, so
3455 replace it with our own. This also allows us to calculate consistent
3456 inode values and owner/group without hacks in the main Emacs code. */
3458 static int
3459 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
3461 char *name, *save_name, *r;
3462 WIN32_FIND_DATA wfd;
3463 HANDLE fh;
3464 unsigned __int64 fake_inode = 0;
3465 int permission;
3466 int len;
3467 int rootdir = FALSE;
3468 PSECURITY_DESCRIPTOR psd = NULL;
3469 int is_a_symlink = 0;
3470 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
3471 DWORD access_rights = 0;
3472 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
3473 FILETIME ctime, atime, wtime;
3475 if (path == NULL || buf == NULL)
3477 errno = EFAULT;
3478 return -1;
3481 save_name = name = (char *) map_w32_filename (path, &path);
3482 /* Must be valid filename, no wild cards or other invalid
3483 characters. We use _mbspbrk to support multibyte strings that
3484 might look to strpbrk as if they included literal *, ?, and other
3485 characters mentioned below that are disallowed by Windows
3486 filesystems. */
3487 if (_mbspbrk (name, "*?|<>\""))
3489 errno = ENOENT;
3490 return -1;
3493 /* Remove trailing directory separator, unless name is the root
3494 directory of a drive or UNC volume in which case ensure there
3495 is a trailing separator. */
3496 len = strlen (name);
3497 name = strcpy (alloca (len + 2), name);
3499 /* Avoid a somewhat costly call to is_symlink if the filesystem
3500 doesn't support symlinks. */
3501 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
3502 is_a_symlink = is_symlink (name);
3504 /* Plan A: Open the file and get all the necessary information via
3505 the resulting handle. This solves several issues in one blow:
3507 . retrieves attributes for the target of a symlink, if needed
3508 . gets attributes of root directories and symlinks pointing to
3509 root directories, thus avoiding the need for special-casing
3510 these and detecting them by examining the file-name format
3511 . retrieves more accurate attributes (e.g., non-zero size for
3512 some directories, esp. directories that are junction points)
3513 . correctly resolves "c:/..", "/.." and similar file names
3514 . avoids run-time penalties for 99% of use cases
3516 Plan A is always tried first, unless the user asked not to (but
3517 if the file is a symlink and we need to follow links, we try Plan
3518 A even if the user asked not to).
3520 If Plan A fails, we go to Plan B (below), where various
3521 potentially expensive techniques must be used to handle "special"
3522 files such as UNC volumes etc. */
3523 if (!(NILP (Vw32_get_true_file_attributes)
3524 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
3525 /* Following symlinks requires getting the info by handle. */
3526 || (is_a_symlink && follow_symlinks))
3528 BY_HANDLE_FILE_INFORMATION info;
3530 if (is_a_symlink && !follow_symlinks)
3531 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
3532 /* READ_CONTROL access rights are required to get security info
3533 by handle. But if the OS doesn't support security in the
3534 first place, we don't need to try. */
3535 if (is_windows_9x () != TRUE)
3536 access_rights |= READ_CONTROL;
3538 fh = CreateFile (name, access_rights, 0, NULL, OPEN_EXISTING,
3539 file_flags, NULL);
3540 /* If CreateFile fails with READ_CONTROL, try again with zero as
3541 access rights. */
3542 if (fh == INVALID_HANDLE_VALUE && access_rights)
3543 fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
3544 file_flags, NULL);
3545 if (fh == INVALID_HANDLE_VALUE)
3546 goto no_true_file_attributes;
3548 /* This is more accurate in terms of getting the correct number
3549 of links, but is quite slow (it is noticeable when Emacs is
3550 making a list of file name completions). */
3551 if (GetFileInformationByHandle (fh, &info))
3553 nlinks = info.nNumberOfLinks;
3554 /* Might as well use file index to fake inode values, but this
3555 is not guaranteed to be unique unless we keep a handle open
3556 all the time (even then there are situations where it is
3557 not unique). Reputedly, there are at most 48 bits of info
3558 (on NTFS, presumably less on FAT). */
3559 fake_inode = info.nFileIndexHigh;
3560 fake_inode <<= 32;
3561 fake_inode += info.nFileIndexLow;
3562 serialnum = info.dwVolumeSerialNumber;
3563 fs_high = info.nFileSizeHigh;
3564 fs_low = info.nFileSizeLow;
3565 ctime = info.ftCreationTime;
3566 atime = info.ftLastAccessTime;
3567 wtime = info.ftLastWriteTime;
3568 fattrs = info.dwFileAttributes;
3570 else
3572 /* We don't go to Plan B here, because it's not clear that
3573 it's a good idea. The only known use case where
3574 CreateFile succeeds, but GetFileInformationByHandle fails
3575 (with ERROR_INVALID_FUNCTION) is for character devices
3576 such as NUL, PRN, etc. For these, switching to Plan B is
3577 a net loss, because we lose the character device
3578 attribute returned by GetFileType below (FindFirstFile
3579 doesn't set that bit in the attributes), and the other
3580 fields don't make sense for character devices anyway.
3581 Emacs doesn't really care for non-file entities in the
3582 context of l?stat, so neither do we. */
3584 /* w32err is assigned so one could put a breakpoint here and
3585 examine its value, when GetFileInformationByHandle
3586 fails. */
3587 DWORD w32err = GetLastError ();
3589 switch (w32err)
3591 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
3592 errno = ENOENT;
3593 return -1;
3597 /* Test for a symlink before testing for a directory, since
3598 symlinks to directories have the directory bit set, but we
3599 don't want them to appear as directories. */
3600 if (is_a_symlink && !follow_symlinks)
3601 buf->st_mode = S_IFLNK;
3602 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3603 buf->st_mode = S_IFDIR;
3604 else
3606 DWORD ftype = GetFileType (fh);
3608 switch (ftype)
3610 case FILE_TYPE_DISK:
3611 buf->st_mode = S_IFREG;
3612 break;
3613 case FILE_TYPE_PIPE:
3614 buf->st_mode = S_IFIFO;
3615 break;
3616 case FILE_TYPE_CHAR:
3617 case FILE_TYPE_UNKNOWN:
3618 default:
3619 buf->st_mode = S_IFCHR;
3622 /* We produce the fallback owner and group data, based on the
3623 current user that runs Emacs, in the following cases:
3625 . this is Windows 9X
3626 . getting security by handle failed, and we need to produce
3627 information for the target of a symlink (this is better
3628 than producing a potentially misleading info about the
3629 symlink itself)
3631 If getting security by handle fails, and we don't need to
3632 resolve symlinks, we try getting security by name. */
3633 if (is_windows_9x () != TRUE)
3634 psd = get_file_security_desc_by_handle (fh);
3635 if (psd)
3637 get_file_owner_and_group (psd, name, buf);
3638 LocalFree (psd);
3640 else if (is_windows_9x () == TRUE)
3641 get_file_owner_and_group (NULL, name, buf);
3642 else if (!(is_a_symlink && follow_symlinks))
3644 psd = get_file_security_desc_by_name (name);
3645 get_file_owner_and_group (psd, name, buf);
3646 xfree (psd);
3648 else
3649 get_file_owner_and_group (NULL, name, buf);
3650 CloseHandle (fh);
3652 else
3654 no_true_file_attributes:
3655 /* Plan B: Either getting a handle on the file failed, or the
3656 caller explicitly asked us to not bother making this
3657 information more accurate.
3659 Implementation note: In Plan B, we never bother to resolve
3660 symlinks, even if we got here because we tried Plan A and
3661 failed. That's because, even if the caller asked for extra
3662 precision by setting Vw32_get_true_file_attributes to t,
3663 resolving symlinks requires acquiring a file handle to the
3664 symlink, which we already know will fail. And if the user
3665 did not ask for extra precision, resolving symlinks will fly
3666 in the face of that request, since the user then wants the
3667 lightweight version of the code. */
3668 rootdir = (path >= save_name + len - 1
3669 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3671 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3672 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3673 if (IS_DIRECTORY_SEP (r[0])
3674 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3675 r[1] = r[2] = '\0';
3677 /* Note: If NAME is a symlink to the root of a UNC volume
3678 (i.e. "\\SERVER"), we will not detect that here, and we will
3679 return data about the symlink as result of FindFirst below.
3680 This is unfortunate, but that marginal use case does not
3681 justify a call to chase_symlinks which would impose a penalty
3682 on all the other use cases. (We get here for symlinks to
3683 roots of UNC volumes because CreateFile above fails for them,
3684 unlike with symlinks to root directories X:\ of drives.) */
3685 if (is_unc_volume (name))
3687 fattrs = unc_volume_file_attributes (name);
3688 if (fattrs == -1)
3689 return -1;
3691 ctime = atime = wtime = utc_base_ft;
3693 else if (rootdir)
3695 if (!IS_DIRECTORY_SEP (name[len-1]))
3696 strcat (name, "\\");
3697 if (GetDriveType (name) < 2)
3699 errno = ENOENT;
3700 return -1;
3703 fattrs = FILE_ATTRIBUTE_DIRECTORY;
3704 ctime = atime = wtime = utc_base_ft;
3706 else
3708 if (IS_DIRECTORY_SEP (name[len-1]))
3709 name[len - 1] = 0;
3711 /* (This is hacky, but helps when doing file completions on
3712 network drives.) Optimize by using information available from
3713 active readdir if possible. */
3714 len = strlen (dir_pathname);
3715 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3716 len--;
3717 if (dir_find_handle != INVALID_HANDLE_VALUE
3718 && !(is_a_symlink && follow_symlinks)
3719 && strnicmp (save_name, dir_pathname, len) == 0
3720 && IS_DIRECTORY_SEP (name[len])
3721 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3723 /* This was the last entry returned by readdir. */
3724 wfd = dir_find_data;
3726 else
3728 logon_network_drive (name);
3730 fh = FindFirstFile (name, &wfd);
3731 if (fh == INVALID_HANDLE_VALUE)
3733 errno = ENOENT;
3734 return -1;
3736 FindClose (fh);
3738 /* Note: if NAME is a symlink, the information we get from
3739 FindFirstFile is for the symlink, not its target. */
3740 fattrs = wfd.dwFileAttributes;
3741 ctime = wfd.ftCreationTime;
3742 atime = wfd.ftLastAccessTime;
3743 wtime = wfd.ftLastWriteTime;
3744 fs_high = wfd.nFileSizeHigh;
3745 fs_low = wfd.nFileSizeLow;
3746 fake_inode = 0;
3747 nlinks = 1;
3748 serialnum = volume_info.serialnum;
3750 if (is_a_symlink && !follow_symlinks)
3751 buf->st_mode = S_IFLNK;
3752 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3753 buf->st_mode = S_IFDIR;
3754 else
3755 buf->st_mode = S_IFREG;
3757 get_file_owner_and_group (NULL, name, buf);
3760 #if 0
3761 /* Not sure if there is any point in this. */
3762 if (!NILP (Vw32_generate_fake_inodes))
3763 fake_inode = generate_inode_val (name);
3764 else if (fake_inode == 0)
3766 /* For want of something better, try to make everything unique. */
3767 static DWORD gen_num = 0;
3768 fake_inode = ++gen_num;
3770 #endif
3772 buf->st_ino = fake_inode;
3774 buf->st_dev = serialnum;
3775 buf->st_rdev = serialnum;
3777 buf->st_size = fs_high;
3778 buf->st_size <<= 32;
3779 buf->st_size += fs_low;
3780 buf->st_nlink = nlinks;
3782 /* Convert timestamps to Unix format. */
3783 buf->st_mtime = convert_time (wtime);
3784 buf->st_atime = convert_time (atime);
3785 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3786 buf->st_ctime = convert_time (ctime);
3787 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3789 /* determine rwx permissions */
3790 if (is_a_symlink && !follow_symlinks)
3791 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
3792 else
3794 if (fattrs & FILE_ATTRIBUTE_READONLY)
3795 permission = S_IREAD;
3796 else
3797 permission = S_IREAD | S_IWRITE;
3799 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3800 permission |= S_IEXEC;
3801 else if (is_exec (name))
3802 permission |= S_IEXEC;
3805 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3807 return 0;
3811 stat (const char * path, struct stat * buf)
3813 return stat_worker (path, buf, 1);
3817 lstat (const char * path, struct stat * buf)
3819 return stat_worker (path, buf, 0);
3822 /* Provide fstat and utime as well as stat for consistent handling of
3823 file timestamps. */
3825 fstat (int desc, struct stat * buf)
3827 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3828 BY_HANDLE_FILE_INFORMATION info;
3829 unsigned __int64 fake_inode;
3830 int permission;
3832 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3834 case FILE_TYPE_DISK:
3835 buf->st_mode = S_IFREG;
3836 if (!GetFileInformationByHandle (fh, &info))
3838 errno = EACCES;
3839 return -1;
3841 break;
3842 case FILE_TYPE_PIPE:
3843 buf->st_mode = S_IFIFO;
3844 goto non_disk;
3845 case FILE_TYPE_CHAR:
3846 case FILE_TYPE_UNKNOWN:
3847 default:
3848 buf->st_mode = S_IFCHR;
3849 non_disk:
3850 memset (&info, 0, sizeof (info));
3851 info.dwFileAttributes = 0;
3852 info.ftCreationTime = utc_base_ft;
3853 info.ftLastAccessTime = utc_base_ft;
3854 info.ftLastWriteTime = utc_base_ft;
3857 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3858 buf->st_mode = S_IFDIR;
3860 buf->st_nlink = info.nNumberOfLinks;
3861 /* Might as well use file index to fake inode values, but this
3862 is not guaranteed to be unique unless we keep a handle open
3863 all the time (even then there are situations where it is
3864 not unique). Reputedly, there are at most 48 bits of info
3865 (on NTFS, presumably less on FAT). */
3866 fake_inode = info.nFileIndexHigh;
3867 fake_inode <<= 32;
3868 fake_inode += info.nFileIndexLow;
3870 /* MSVC defines _ino_t to be short; other libc's might not. */
3871 if (sizeof (buf->st_ino) == 2)
3872 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3873 else
3874 buf->st_ino = fake_inode;
3876 /* Consider files to belong to current user.
3877 FIXME: this should use GetSecurityInfo API, but it is only
3878 available for _WIN32_WINNT >= 0x501. */
3879 buf->st_uid = dflt_passwd.pw_uid;
3880 buf->st_gid = dflt_passwd.pw_gid;
3881 strcpy (buf->st_uname, dflt_passwd.pw_name);
3882 strcpy (buf->st_gname, dflt_group.gr_name);
3884 buf->st_dev = info.dwVolumeSerialNumber;
3885 buf->st_rdev = info.dwVolumeSerialNumber;
3887 buf->st_size = info.nFileSizeHigh;
3888 buf->st_size <<= 32;
3889 buf->st_size += info.nFileSizeLow;
3891 /* Convert timestamps to Unix format. */
3892 buf->st_mtime = convert_time (info.ftLastWriteTime);
3893 buf->st_atime = convert_time (info.ftLastAccessTime);
3894 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3895 buf->st_ctime = convert_time (info.ftCreationTime);
3896 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3898 /* determine rwx permissions */
3899 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3900 permission = S_IREAD;
3901 else
3902 permission = S_IREAD | S_IWRITE;
3904 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3905 permission |= S_IEXEC;
3906 else
3908 #if 0 /* no way of knowing the filename */
3909 char * p = strrchr (name, '.');
3910 if (p != NULL &&
3911 (xstrcasecmp (p, ".exe") == 0 ||
3912 xstrcasecmp (p, ".com") == 0 ||
3913 xstrcasecmp (p, ".bat") == 0 ||
3914 xstrcasecmp (p, ".cmd") == 0))
3915 permission |= S_IEXEC;
3916 #endif
3919 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3921 return 0;
3925 utime (const char *name, struct utimbuf *times)
3927 struct utimbuf deftime;
3928 HANDLE fh;
3929 FILETIME mtime;
3930 FILETIME atime;
3932 if (times == NULL)
3934 deftime.modtime = deftime.actime = time (NULL);
3935 times = &deftime;
3938 /* Need write access to set times. */
3939 fh = CreateFile (name, FILE_WRITE_ATTRIBUTES,
3940 /* If NAME specifies a directory, FILE_SHARE_DELETE
3941 allows other processes to delete files inside it,
3942 while we have the directory open. */
3943 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
3944 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
3945 if (fh != INVALID_HANDLE_VALUE)
3947 convert_from_time_t (times->actime, &atime);
3948 convert_from_time_t (times->modtime, &mtime);
3949 if (!SetFileTime (fh, NULL, &atime, &mtime))
3951 CloseHandle (fh);
3952 errno = EACCES;
3953 return -1;
3955 CloseHandle (fh);
3957 else
3959 errno = EINVAL;
3960 return -1;
3962 return 0;
3966 /* Symlink-related functions. */
3967 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
3968 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
3969 #endif
3972 symlink (char const *filename, char const *linkname)
3974 char linkfn[MAX_PATH], *tgtfn;
3975 DWORD flags = 0;
3976 int dir_access, filename_ends_in_slash;
3978 /* Diagnostics follows Posix as much as possible. */
3979 if (filename == NULL || linkname == NULL)
3981 errno = EFAULT;
3982 return -1;
3984 if (!*filename)
3986 errno = ENOENT;
3987 return -1;
3989 if (strlen (filename) > MAX_PATH || strlen (linkname) > MAX_PATH)
3991 errno = ENAMETOOLONG;
3992 return -1;
3995 strcpy (linkfn, map_w32_filename (linkname, NULL));
3996 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
3998 errno = EPERM;
3999 return -1;
4002 /* Note: since empty FILENAME was already rejected, we can safely
4003 refer to FILENAME[1]. */
4004 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
4006 /* Non-absolute FILENAME is understood as being relative to
4007 LINKNAME's directory. We need to prepend that directory to
4008 FILENAME to get correct results from sys_access below, since
4009 otherwise it will interpret FILENAME relative to the
4010 directory where the Emacs process runs. Note that
4011 make-symbolic-link always makes sure LINKNAME is a fully
4012 expanded file name. */
4013 char tem[MAX_PATH];
4014 char *p = linkfn + strlen (linkfn);
4016 while (p > linkfn && !IS_ANY_SEP (p[-1]))
4017 p--;
4018 if (p > linkfn)
4019 strncpy (tem, linkfn, p - linkfn);
4020 tem[p - linkfn] = '\0';
4021 strcat (tem, filename);
4022 dir_access = sys_access (tem, D_OK);
4024 else
4025 dir_access = sys_access (filename, D_OK);
4027 /* Since Windows distinguishes between symlinks to directories and
4028 to files, we provide a kludgy feature: if FILENAME doesn't
4029 exist, but ends in a slash, we create a symlink to directory. If
4030 FILENAME exists and is a directory, we always create a symlink to
4031 directory. */
4032 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
4033 if (dir_access == 0 || filename_ends_in_slash)
4034 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
4036 tgtfn = (char *)map_w32_filename (filename, NULL);
4037 if (filename_ends_in_slash)
4038 tgtfn[strlen (tgtfn) - 1] = '\0';
4040 errno = 0;
4041 if (!create_symbolic_link (linkfn, tgtfn, flags))
4043 /* ENOSYS is set by create_symbolic_link, when it detects that
4044 the OS doesn't support the CreateSymbolicLink API. */
4045 if (errno != ENOSYS)
4047 DWORD w32err = GetLastError ();
4049 switch (w32err)
4051 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4052 TGTFN point to the same file name, go figure. */
4053 case ERROR_SUCCESS:
4054 case ERROR_FILE_EXISTS:
4055 errno = EEXIST;
4056 break;
4057 case ERROR_ACCESS_DENIED:
4058 errno = EACCES;
4059 break;
4060 case ERROR_FILE_NOT_FOUND:
4061 case ERROR_PATH_NOT_FOUND:
4062 case ERROR_BAD_NETPATH:
4063 case ERROR_INVALID_REPARSE_DATA:
4064 errno = ENOENT;
4065 break;
4066 case ERROR_DIRECTORY:
4067 errno = EISDIR;
4068 break;
4069 case ERROR_PRIVILEGE_NOT_HELD:
4070 case ERROR_NOT_ALL_ASSIGNED:
4071 errno = EPERM;
4072 break;
4073 case ERROR_DISK_FULL:
4074 errno = ENOSPC;
4075 break;
4076 default:
4077 errno = EINVAL;
4078 break;
4081 return -1;
4083 return 0;
4086 /* A quick inexpensive test of whether FILENAME identifies a file that
4087 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4088 must already be in the normalized form returned by
4089 map_w32_filename.
4091 Note: for repeated operations on many files, it is best to test
4092 whether the underlying volume actually supports symlinks, by
4093 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4094 avoid the call to this function if it doesn't. That's because the
4095 call to GetFileAttributes takes a non-negligible time, especially
4096 on non-local or removable filesystems. See stat_worker for an
4097 example of how to do that. */
4098 static int
4099 is_symlink (const char *filename)
4101 DWORD attrs;
4102 WIN32_FIND_DATA wfd;
4103 HANDLE fh;
4105 attrs = GetFileAttributes (filename);
4106 if (attrs == -1)
4108 DWORD w32err = GetLastError ();
4110 switch (w32err)
4112 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
4113 break;
4114 case ERROR_ACCESS_DENIED:
4115 errno = EACCES;
4116 break;
4117 case ERROR_FILE_NOT_FOUND:
4118 case ERROR_PATH_NOT_FOUND:
4119 default:
4120 errno = ENOENT;
4121 break;
4123 return 0;
4125 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
4126 return 0;
4127 logon_network_drive (filename);
4128 fh = FindFirstFile (filename, &wfd);
4129 if (fh == INVALID_HANDLE_VALUE)
4130 return 0;
4131 FindClose (fh);
4132 return (wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
4133 && (wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
4136 /* If NAME identifies a symbolic link, copy into BUF the file name of
4137 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4138 null-terminate the target name, even if it fits. Return the number
4139 of bytes copied, or -1 if NAME is not a symlink or any error was
4140 encountered while resolving it. The file name copied into BUF is
4141 encoded in the current ANSI codepage. */
4142 ssize_t
4143 readlink (const char *name, char *buf, size_t buf_size)
4145 const char *path;
4146 TOKEN_PRIVILEGES privs;
4147 int restore_privs = 0;
4148 HANDLE sh;
4149 ssize_t retval;
4151 if (name == NULL)
4153 errno = EFAULT;
4154 return -1;
4156 if (!*name)
4158 errno = ENOENT;
4159 return -1;
4162 path = map_w32_filename (name, NULL);
4164 if (strlen (path) > MAX_PATH)
4166 errno = ENAMETOOLONG;
4167 return -1;
4170 errno = 0;
4171 if (is_windows_9x () == TRUE
4172 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
4173 || !is_symlink (path))
4175 if (!errno)
4176 errno = EINVAL; /* not a symlink */
4177 return -1;
4180 /* Done with simple tests, now we're in for some _real_ work. */
4181 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
4182 restore_privs = 1;
4183 /* Implementation note: From here and onward, don't return early,
4184 since that will fail to restore the original set of privileges of
4185 the calling thread. */
4187 retval = -1; /* not too optimistic, are we? */
4189 /* Note: In the next call to CreateFile, we use zero as the 2nd
4190 argument because, when the symlink is a hidden/system file,
4191 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4192 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4193 and directory symlinks. */
4194 sh = CreateFile (path, 0, 0, NULL, OPEN_EXISTING,
4195 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
4196 NULL);
4197 if (sh != INVALID_HANDLE_VALUE)
4199 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
4200 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
4201 DWORD retbytes;
4203 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
4204 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
4205 &retbytes, NULL))
4206 errno = EIO;
4207 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
4208 errno = EINVAL;
4209 else
4211 /* Copy the link target name, in wide characters, fro
4212 reparse_data, then convert it to multibyte encoding in
4213 the current locale's codepage. */
4214 WCHAR *lwname;
4215 BYTE lname[MAX_PATH];
4216 USHORT lname_len;
4217 USHORT lwname_len =
4218 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
4219 WCHAR *lwname_src =
4220 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
4221 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
4223 /* According to MSDN, PrintNameLength does not include the
4224 terminating null character. */
4225 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
4226 memcpy (lwname, lwname_src, lwname_len);
4227 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
4229 /* FIXME: Should we use the current file-name coding system
4230 instead of the fixed value of the ANSI codepage? */
4231 lname_len = WideCharToMultiByte (w32_ansi_code_page, 0, lwname, -1,
4232 lname, MAX_PATH, NULL, NULL);
4233 if (!lname_len)
4235 /* WideCharToMultiByte failed. */
4236 DWORD w32err1 = GetLastError ();
4238 switch (w32err1)
4240 case ERROR_INSUFFICIENT_BUFFER:
4241 errno = ENAMETOOLONG;
4242 break;
4243 case ERROR_INVALID_PARAMETER:
4244 errno = EFAULT;
4245 break;
4246 case ERROR_NO_UNICODE_TRANSLATION:
4247 errno = ENOENT;
4248 break;
4249 default:
4250 errno = EINVAL;
4251 break;
4254 else
4256 size_t size_to_copy = buf_size;
4257 BYTE *p = lname;
4258 BYTE *pend = p + lname_len;
4260 /* Normalize like dostounix_filename does, but we don't
4261 want to assume that lname is null-terminated. */
4262 if (*p && p[1] == ':' && *p >= 'A' && *p <= 'Z')
4263 *p += 'a' - 'A';
4264 while (p <= pend)
4266 if (*p == '\\')
4267 *p = '/';
4268 ++p;
4270 /* Testing for null-terminated LNAME is paranoia:
4271 WideCharToMultiByte should always return a
4272 null-terminated string when its 4th argument is -1
4273 and its 3rd argument is null-terminated (which they
4274 are, see above). */
4275 if (lname[lname_len - 1] == '\0')
4276 lname_len--;
4277 if (lname_len <= buf_size)
4278 size_to_copy = lname_len;
4279 strncpy (buf, lname, size_to_copy);
4280 /* Success! */
4281 retval = size_to_copy;
4284 CloseHandle (sh);
4286 else
4288 /* CreateFile failed. */
4289 DWORD w32err2 = GetLastError ();
4291 switch (w32err2)
4293 case ERROR_FILE_NOT_FOUND:
4294 case ERROR_PATH_NOT_FOUND:
4295 errno = ENOENT;
4296 break;
4297 case ERROR_ACCESS_DENIED:
4298 case ERROR_TOO_MANY_OPEN_FILES:
4299 errno = EACCES;
4300 break;
4301 default:
4302 errno = EPERM;
4303 break;
4306 if (restore_privs)
4308 restore_privilege (&privs);
4309 revert_to_self ();
4312 return retval;
4315 /* If FILE is a symlink, return its target (stored in a static
4316 buffer); otherwise return FILE.
4318 This function repeatedly resolves symlinks in the last component of
4319 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4320 until it arrives at a file whose last component is not a symlink,
4321 or some error occurs. It returns the target of the last
4322 successfully resolved symlink in the chain. If it succeeds to
4323 resolve even a single symlink, the value returned is an absolute
4324 file name with backslashes (result of GetFullPathName). By
4325 contrast, if the original FILE is returned, it is unaltered.
4327 Note: This function can set errno even if it succeeds.
4329 Implementation note: we only resolve the last portion ("basename")
4330 of the argument FILE and of each following file in the chain,
4331 disregarding any possible symlinks in its leading directories.
4332 This is because Windows system calls and library functions
4333 transparently resolve symlinks in leading directories and return
4334 correct information, as long as the basename is not a symlink. */
4335 static char *
4336 chase_symlinks (const char *file)
4338 static char target[MAX_PATH];
4339 char link[MAX_PATH];
4340 ssize_t res, link_len;
4341 int loop_count = 0;
4343 if (is_windows_9x () == TRUE || !is_symlink (file))
4344 return (char *)file;
4346 if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0)
4347 return (char *)file;
4349 target[0] = '\0';
4350 do {
4352 /* Remove trailing slashes, as we want to resolve the last
4353 non-trivial part of the link name. */
4354 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
4355 link[link_len--] = '\0';
4357 res = readlink (link, target, MAX_PATH);
4358 if (res > 0)
4360 target[res] = '\0';
4361 if (!(IS_DEVICE_SEP (target[1])
4362 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
4364 /* Target is relative. Append it to the directory part of
4365 the symlink, then copy the result back to target. */
4366 char *p = link + link_len;
4368 while (p > link && !IS_ANY_SEP (p[-1]))
4369 p--;
4370 strcpy (p, target);
4371 strcpy (target, link);
4373 /* Resolve any "." and ".." to get a fully-qualified file name
4374 in link[] again. */
4375 link_len = GetFullPathName (target, MAX_PATH, link, NULL);
4377 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
4379 if (loop_count > 100)
4380 errno = ELOOP;
4382 if (target[0] == '\0') /* not a single call to readlink succeeded */
4383 return (char *)file;
4384 return target;
4387 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
4388 have a fixed max size for file names, so we don't need the kind of
4389 alloc/malloc/realloc dance the gnulib version does. We also don't
4390 support FD-relative symlinks. */
4391 char *
4392 careadlinkat (int fd, char const *filename,
4393 char *buffer, size_t buffer_size,
4394 struct allocator const *alloc,
4395 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
4397 char linkname[MAX_PATH];
4398 ssize_t link_size;
4400 if (fd != AT_FDCWD)
4402 errno = EINVAL;
4403 return NULL;
4406 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
4408 if (link_size > 0)
4410 char *retval = buffer;
4412 linkname[link_size++] = '\0';
4413 if (link_size > buffer_size)
4414 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
4415 if (retval)
4416 memcpy (retval, linkname, link_size);
4418 return retval;
4420 return NULL;
4423 ssize_t
4424 careadlinkatcwd (int fd, char const *filename, char *buffer,
4425 size_t buffer_size)
4427 (void) fd;
4428 return readlink (filename, buffer, buffer_size);
4432 /* Support for browsing other processes and their attributes. See
4433 process.c for the Lisp bindings. */
4435 /* Helper wrapper functions. */
4437 static HANDLE WINAPI
4438 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
4440 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
4442 if (g_b_init_create_toolhelp32_snapshot == 0)
4444 g_b_init_create_toolhelp32_snapshot = 1;
4445 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
4446 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4447 "CreateToolhelp32Snapshot");
4449 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
4451 return INVALID_HANDLE_VALUE;
4453 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
4456 static BOOL WINAPI
4457 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
4459 static Process32First_Proc s_pfn_Process32_First = NULL;
4461 if (g_b_init_process32_first == 0)
4463 g_b_init_process32_first = 1;
4464 s_pfn_Process32_First = (Process32First_Proc)
4465 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4466 "Process32First");
4468 if (s_pfn_Process32_First == NULL)
4470 return FALSE;
4472 return (s_pfn_Process32_First (hSnapshot, lppe));
4475 static BOOL WINAPI
4476 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
4478 static Process32Next_Proc s_pfn_Process32_Next = NULL;
4480 if (g_b_init_process32_next == 0)
4482 g_b_init_process32_next = 1;
4483 s_pfn_Process32_Next = (Process32Next_Proc)
4484 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4485 "Process32Next");
4487 if (s_pfn_Process32_Next == NULL)
4489 return FALSE;
4491 return (s_pfn_Process32_Next (hSnapshot, lppe));
4494 static BOOL WINAPI
4495 open_thread_token (HANDLE ThreadHandle,
4496 DWORD DesiredAccess,
4497 BOOL OpenAsSelf,
4498 PHANDLE TokenHandle)
4500 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
4501 HMODULE hm_advapi32 = NULL;
4502 if (is_windows_9x () == TRUE)
4504 SetLastError (ERROR_NOT_SUPPORTED);
4505 return FALSE;
4507 if (g_b_init_open_thread_token == 0)
4509 g_b_init_open_thread_token = 1;
4510 hm_advapi32 = LoadLibrary ("Advapi32.dll");
4511 s_pfn_Open_Thread_Token =
4512 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
4514 if (s_pfn_Open_Thread_Token == NULL)
4516 SetLastError (ERROR_NOT_SUPPORTED);
4517 return FALSE;
4519 return (
4520 s_pfn_Open_Thread_Token (
4521 ThreadHandle,
4522 DesiredAccess,
4523 OpenAsSelf,
4524 TokenHandle)
4528 static BOOL WINAPI
4529 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
4531 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
4532 HMODULE hm_advapi32 = NULL;
4533 if (is_windows_9x () == TRUE)
4535 return FALSE;
4537 if (g_b_init_impersonate_self == 0)
4539 g_b_init_impersonate_self = 1;
4540 hm_advapi32 = LoadLibrary ("Advapi32.dll");
4541 s_pfn_Impersonate_Self =
4542 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
4544 if (s_pfn_Impersonate_Self == NULL)
4546 return FALSE;
4548 return s_pfn_Impersonate_Self (ImpersonationLevel);
4551 static BOOL WINAPI
4552 revert_to_self (void)
4554 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
4555 HMODULE hm_advapi32 = NULL;
4556 if (is_windows_9x () == TRUE)
4558 return FALSE;
4560 if (g_b_init_revert_to_self == 0)
4562 g_b_init_revert_to_self = 1;
4563 hm_advapi32 = LoadLibrary ("Advapi32.dll");
4564 s_pfn_Revert_To_Self =
4565 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
4567 if (s_pfn_Revert_To_Self == NULL)
4569 return FALSE;
4571 return s_pfn_Revert_To_Self ();
4574 static BOOL WINAPI
4575 get_process_memory_info (HANDLE h_proc,
4576 PPROCESS_MEMORY_COUNTERS mem_counters,
4577 DWORD bufsize)
4579 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
4580 HMODULE hm_psapi = NULL;
4581 if (is_windows_9x () == TRUE)
4583 return FALSE;
4585 if (g_b_init_get_process_memory_info == 0)
4587 g_b_init_get_process_memory_info = 1;
4588 hm_psapi = LoadLibrary ("Psapi.dll");
4589 if (hm_psapi)
4590 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
4591 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
4593 if (s_pfn_Get_Process_Memory_Info == NULL)
4595 return FALSE;
4597 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
4600 static BOOL WINAPI
4601 get_process_working_set_size (HANDLE h_proc,
4602 DWORD *minrss,
4603 DWORD *maxrss)
4605 static GetProcessWorkingSetSize_Proc
4606 s_pfn_Get_Process_Working_Set_Size = NULL;
4608 if (is_windows_9x () == TRUE)
4610 return FALSE;
4612 if (g_b_init_get_process_working_set_size == 0)
4614 g_b_init_get_process_working_set_size = 1;
4615 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
4616 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4617 "GetProcessWorkingSetSize");
4619 if (s_pfn_Get_Process_Working_Set_Size == NULL)
4621 return FALSE;
4623 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
4626 static BOOL WINAPI
4627 global_memory_status (MEMORYSTATUS *buf)
4629 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
4631 if (is_windows_9x () == TRUE)
4633 return FALSE;
4635 if (g_b_init_global_memory_status == 0)
4637 g_b_init_global_memory_status = 1;
4638 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
4639 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4640 "GlobalMemoryStatus");
4642 if (s_pfn_Global_Memory_Status == NULL)
4644 return FALSE;
4646 return s_pfn_Global_Memory_Status (buf);
4649 static BOOL WINAPI
4650 global_memory_status_ex (MEMORY_STATUS_EX *buf)
4652 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
4654 if (is_windows_9x () == TRUE)
4656 return FALSE;
4658 if (g_b_init_global_memory_status_ex == 0)
4660 g_b_init_global_memory_status_ex = 1;
4661 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
4662 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4663 "GlobalMemoryStatusEx");
4665 if (s_pfn_Global_Memory_Status_Ex == NULL)
4667 return FALSE;
4669 return s_pfn_Global_Memory_Status_Ex (buf);
4672 Lisp_Object
4673 list_system_processes (void)
4675 struct gcpro gcpro1;
4676 Lisp_Object proclist = Qnil;
4677 HANDLE h_snapshot;
4679 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4681 if (h_snapshot != INVALID_HANDLE_VALUE)
4683 PROCESSENTRY32 proc_entry;
4684 DWORD proc_id;
4685 BOOL res;
4687 GCPRO1 (proclist);
4689 proc_entry.dwSize = sizeof (PROCESSENTRY32);
4690 for (res = process32_first (h_snapshot, &proc_entry); res;
4691 res = process32_next (h_snapshot, &proc_entry))
4693 proc_id = proc_entry.th32ProcessID;
4694 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
4697 CloseHandle (h_snapshot);
4698 UNGCPRO;
4699 proclist = Fnreverse (proclist);
4702 return proclist;
4705 static int
4706 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
4708 TOKEN_PRIVILEGES priv;
4709 DWORD priv_size = sizeof (priv);
4710 DWORD opriv_size = sizeof (*old_priv);
4711 HANDLE h_token = NULL;
4712 HANDLE h_thread = GetCurrentThread ();
4713 int ret_val = 0;
4714 BOOL res;
4716 res = open_thread_token (h_thread,
4717 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4718 FALSE, &h_token);
4719 if (!res && GetLastError () == ERROR_NO_TOKEN)
4721 if (impersonate_self (SecurityImpersonation))
4722 res = open_thread_token (h_thread,
4723 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4724 FALSE, &h_token);
4726 if (res)
4728 priv.PrivilegeCount = 1;
4729 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
4730 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
4731 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
4732 old_priv, &opriv_size)
4733 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
4734 ret_val = 1;
4736 if (h_token)
4737 CloseHandle (h_token);
4739 return ret_val;
4742 static int
4743 restore_privilege (TOKEN_PRIVILEGES *priv)
4745 DWORD priv_size = sizeof (*priv);
4746 HANDLE h_token = NULL;
4747 int ret_val = 0;
4749 if (open_thread_token (GetCurrentThread (),
4750 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4751 FALSE, &h_token))
4753 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
4754 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
4755 ret_val = 1;
4757 if (h_token)
4758 CloseHandle (h_token);
4760 return ret_val;
4763 static Lisp_Object
4764 ltime (ULONGLONG time_100ns)
4766 ULONGLONG time_sec = time_100ns / 10000000;
4767 int subsec = time_100ns % 10000000;
4768 return list4 (make_number (time_sec >> 16),
4769 make_number (time_sec & 0xffff),
4770 make_number (subsec / 10),
4771 make_number (subsec % 10 * 100000));
4774 #define U64_TO_LISP_TIME(time) ltime (time)
4776 static int
4777 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
4778 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
4779 double *pcpu)
4781 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
4782 ULONGLONG tem1, tem2, tem3, tem;
4784 if (!h_proc
4785 || !get_process_times_fn
4786 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
4787 &ft_kernel, &ft_user))
4788 return 0;
4790 GetSystemTimeAsFileTime (&ft_current);
4792 FILETIME_TO_U64 (tem1, ft_kernel);
4793 *stime = U64_TO_LISP_TIME (tem1);
4795 FILETIME_TO_U64 (tem2, ft_user);
4796 *utime = U64_TO_LISP_TIME (tem2);
4798 tem3 = tem1 + tem2;
4799 *ttime = U64_TO_LISP_TIME (tem3);
4801 FILETIME_TO_U64 (tem, ft_creation);
4802 /* Process no 4 (System) returns zero creation time. */
4803 if (tem)
4804 tem -= utc_base;
4805 *ctime = U64_TO_LISP_TIME (tem);
4807 if (tem)
4809 FILETIME_TO_U64 (tem3, ft_current);
4810 tem = (tem3 - utc_base) - tem;
4812 *etime = U64_TO_LISP_TIME (tem);
4814 if (tem)
4816 *pcpu = 100.0 * (tem1 + tem2) / tem;
4817 if (*pcpu > 100)
4818 *pcpu = 100.0;
4820 else
4821 *pcpu = 0;
4823 return 1;
4826 Lisp_Object
4827 system_process_attributes (Lisp_Object pid)
4829 struct gcpro gcpro1, gcpro2, gcpro3;
4830 Lisp_Object attrs = Qnil;
4831 Lisp_Object cmd_str, decoded_cmd, tem;
4832 HANDLE h_snapshot, h_proc;
4833 DWORD proc_id;
4834 int found_proc = 0;
4835 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
4836 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
4837 DWORD glength = sizeof (gname);
4838 HANDLE token = NULL;
4839 SID_NAME_USE user_type;
4840 unsigned char *buf = NULL;
4841 DWORD blen = 0;
4842 TOKEN_USER user_token;
4843 TOKEN_PRIMARY_GROUP group_token;
4844 unsigned euid;
4845 unsigned egid;
4846 PROCESS_MEMORY_COUNTERS mem;
4847 PROCESS_MEMORY_COUNTERS_EX mem_ex;
4848 DWORD minrss, maxrss;
4849 MEMORYSTATUS memst;
4850 MEMORY_STATUS_EX memstex;
4851 double totphys = 0.0;
4852 Lisp_Object ctime, stime, utime, etime, ttime;
4853 double pcpu;
4854 BOOL result = FALSE;
4856 CHECK_NUMBER_OR_FLOAT (pid);
4857 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
4859 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4861 GCPRO3 (attrs, decoded_cmd, tem);
4863 if (h_snapshot != INVALID_HANDLE_VALUE)
4865 PROCESSENTRY32 pe;
4866 BOOL res;
4868 pe.dwSize = sizeof (PROCESSENTRY32);
4869 for (res = process32_first (h_snapshot, &pe); res;
4870 res = process32_next (h_snapshot, &pe))
4872 if (proc_id == pe.th32ProcessID)
4874 if (proc_id == 0)
4875 decoded_cmd = build_string ("Idle");
4876 else
4878 /* Decode the command name from locale-specific
4879 encoding. */
4880 cmd_str = make_unibyte_string (pe.szExeFile,
4881 strlen (pe.szExeFile));
4882 decoded_cmd =
4883 code_convert_string_norecord (cmd_str,
4884 Vlocale_coding_system, 0);
4886 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
4887 attrs = Fcons (Fcons (Qppid,
4888 make_fixnum_or_float (pe.th32ParentProcessID)),
4889 attrs);
4890 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
4891 attrs);
4892 attrs = Fcons (Fcons (Qthcount,
4893 make_fixnum_or_float (pe.cntThreads)),
4894 attrs);
4895 found_proc = 1;
4896 break;
4900 CloseHandle (h_snapshot);
4903 if (!found_proc)
4905 UNGCPRO;
4906 return Qnil;
4909 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4910 FALSE, proc_id);
4911 /* If we were denied a handle to the process, try again after
4912 enabling the SeDebugPrivilege in our process. */
4913 if (!h_proc)
4915 TOKEN_PRIVILEGES priv_current;
4917 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
4919 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4920 FALSE, proc_id);
4921 restore_privilege (&priv_current);
4922 revert_to_self ();
4925 if (h_proc)
4927 result = open_process_token (h_proc, TOKEN_QUERY, &token);
4928 if (result)
4930 result = get_token_information (token, TokenUser, NULL, 0, &blen);
4931 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4933 buf = xmalloc (blen);
4934 result = get_token_information (token, TokenUser,
4935 (LPVOID)buf, blen, &needed);
4936 if (result)
4938 memcpy (&user_token, buf, sizeof (user_token));
4939 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
4941 euid = get_rid (user_token.User.Sid);
4942 result = lookup_account_sid (NULL, user_token.User.Sid,
4943 uname, &ulength,
4944 domain, &dlength,
4945 &user_type);
4946 if (result)
4947 w32_add_to_cache (user_token.User.Sid, euid, uname);
4948 else
4950 strcpy (uname, "unknown");
4951 result = TRUE;
4954 ulength = strlen (uname);
4958 if (result)
4960 /* Determine a reasonable euid and gid values. */
4961 if (xstrcasecmp ("administrator", uname) == 0)
4963 euid = 500; /* well-known Administrator uid */
4964 egid = 513; /* well-known None gid */
4966 else
4968 /* Get group id and name. */
4969 result = get_token_information (token, TokenPrimaryGroup,
4970 (LPVOID)buf, blen, &needed);
4971 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4973 buf = xrealloc (buf, blen = needed);
4974 result = get_token_information (token, TokenPrimaryGroup,
4975 (LPVOID)buf, blen, &needed);
4977 if (result)
4979 memcpy (&group_token, buf, sizeof (group_token));
4980 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
4982 egid = get_rid (group_token.PrimaryGroup);
4983 dlength = sizeof (domain);
4984 result =
4985 lookup_account_sid (NULL, group_token.PrimaryGroup,
4986 gname, &glength, NULL, &dlength,
4987 &user_type);
4988 if (result)
4989 w32_add_to_cache (group_token.PrimaryGroup,
4990 egid, gname);
4991 else
4993 strcpy (gname, "None");
4994 result = TRUE;
4997 glength = strlen (gname);
5001 xfree (buf);
5003 if (!result)
5005 if (!is_windows_9x ())
5007 /* We couldn't open the process token, presumably because of
5008 insufficient access rights. Assume this process is run
5009 by the system. */
5010 strcpy (uname, "SYSTEM");
5011 strcpy (gname, "None");
5012 euid = 18; /* SYSTEM */
5013 egid = 513; /* None */
5014 glength = strlen (gname);
5015 ulength = strlen (uname);
5017 /* If we are running under Windows 9X, where security calls are
5018 not supported, we assume all processes are run by the current
5019 user. */
5020 else if (GetUserName (uname, &ulength))
5022 if (xstrcasecmp ("administrator", uname) == 0)
5023 euid = 0;
5024 else
5025 euid = 123;
5026 egid = euid;
5027 strcpy (gname, "None");
5028 glength = strlen (gname);
5029 ulength = strlen (uname);
5031 else
5033 euid = 123;
5034 egid = 123;
5035 strcpy (uname, "administrator");
5036 ulength = strlen (uname);
5037 strcpy (gname, "None");
5038 glength = strlen (gname);
5040 if (token)
5041 CloseHandle (token);
5044 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
5045 tem = make_unibyte_string (uname, ulength);
5046 attrs = Fcons (Fcons (Quser,
5047 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
5048 attrs);
5049 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
5050 tem = make_unibyte_string (gname, glength);
5051 attrs = Fcons (Fcons (Qgroup,
5052 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
5053 attrs);
5055 if (global_memory_status_ex (&memstex))
5056 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
5057 totphys = memstex.ullTotalPhys / 1024.0;
5058 #else
5059 /* Visual Studio 6 cannot convert an unsigned __int64 type to
5060 double, so we need to do this for it... */
5062 DWORD tot_hi = memstex.ullTotalPhys >> 32;
5063 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
5064 DWORD tot_lo = memstex.ullTotalPhys % 1024;
5066 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
5068 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5069 else if (global_memory_status (&memst))
5070 totphys = memst.dwTotalPhys / 1024.0;
5072 if (h_proc
5073 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
5074 sizeof (mem_ex)))
5076 DWORD rss = mem_ex.WorkingSetSize / 1024;
5078 attrs = Fcons (Fcons (Qmajflt,
5079 make_fixnum_or_float (mem_ex.PageFaultCount)),
5080 attrs);
5081 attrs = Fcons (Fcons (Qvsize,
5082 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
5083 attrs);
5084 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
5085 if (totphys)
5086 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
5088 else if (h_proc
5089 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
5091 DWORD rss = mem_ex.WorkingSetSize / 1024;
5093 attrs = Fcons (Fcons (Qmajflt,
5094 make_fixnum_or_float (mem.PageFaultCount)),
5095 attrs);
5096 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
5097 if (totphys)
5098 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
5100 else if (h_proc
5101 && get_process_working_set_size (h_proc, &minrss, &maxrss))
5103 DWORD rss = maxrss / 1024;
5105 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
5106 if (totphys)
5107 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
5110 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
5112 attrs = Fcons (Fcons (Qutime, utime), attrs);
5113 attrs = Fcons (Fcons (Qstime, stime), attrs);
5114 attrs = Fcons (Fcons (Qtime, ttime), attrs);
5115 attrs = Fcons (Fcons (Qstart, ctime), attrs);
5116 attrs = Fcons (Fcons (Qetime, etime), attrs);
5117 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
5120 /* FIXME: Retrieve command line by walking the PEB of the process. */
5122 if (h_proc)
5123 CloseHandle (h_proc);
5124 UNGCPRO;
5125 return attrs;
5129 /* Wrappers for winsock functions to map between our file descriptors
5130 and winsock's handles; also set h_errno for convenience.
5132 To allow Emacs to run on systems which don't have winsock support
5133 installed, we dynamically link to winsock on startup if present, and
5134 otherwise provide the minimum necessary functionality
5135 (eg. gethostname). */
5137 /* function pointers for relevant socket functions */
5138 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
5139 void (PASCAL *pfn_WSASetLastError) (int iError);
5140 int (PASCAL *pfn_WSAGetLastError) (void);
5141 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
5142 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
5143 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
5144 int (PASCAL *pfn_socket) (int af, int type, int protocol);
5145 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
5146 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
5147 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
5148 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
5149 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
5150 int (PASCAL *pfn_closesocket) (SOCKET s);
5151 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
5152 int (PASCAL *pfn_WSACleanup) (void);
5154 u_short (PASCAL *pfn_htons) (u_short hostshort);
5155 u_short (PASCAL *pfn_ntohs) (u_short netshort);
5156 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
5157 int (PASCAL *pfn_gethostname) (char * name, int namelen);
5158 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
5159 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
5160 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
5161 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
5162 const char * optval, int optlen);
5163 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
5164 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
5165 int * namelen);
5166 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
5167 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
5168 struct sockaddr * from, int * fromlen);
5169 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
5170 const struct sockaddr * to, int tolen);
5172 /* SetHandleInformation is only needed to make sockets non-inheritable. */
5173 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
5174 #ifndef HANDLE_FLAG_INHERIT
5175 #define HANDLE_FLAG_INHERIT 1
5176 #endif
5178 HANDLE winsock_lib;
5179 static int winsock_inuse;
5181 BOOL
5182 term_winsock (void)
5184 if (winsock_lib != NULL && winsock_inuse == 0)
5186 /* Not sure what would cause WSAENETDOWN, or even if it can happen
5187 after WSAStartup returns successfully, but it seems reasonable
5188 to allow unloading winsock anyway in that case. */
5189 if (pfn_WSACleanup () == 0 ||
5190 pfn_WSAGetLastError () == WSAENETDOWN)
5192 if (FreeLibrary (winsock_lib))
5193 winsock_lib = NULL;
5194 return TRUE;
5197 return FALSE;
5200 BOOL
5201 init_winsock (int load_now)
5203 WSADATA winsockData;
5205 if (winsock_lib != NULL)
5206 return TRUE;
5208 pfn_SetHandleInformation
5209 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
5210 "SetHandleInformation");
5212 winsock_lib = LoadLibrary ("Ws2_32.dll");
5214 if (winsock_lib != NULL)
5216 /* dynamically link to socket functions */
5218 #define LOAD_PROC(fn) \
5219 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
5220 goto fail;
5222 LOAD_PROC (WSAStartup);
5223 LOAD_PROC (WSASetLastError);
5224 LOAD_PROC (WSAGetLastError);
5225 LOAD_PROC (WSAEventSelect);
5226 LOAD_PROC (WSACreateEvent);
5227 LOAD_PROC (WSACloseEvent);
5228 LOAD_PROC (socket);
5229 LOAD_PROC (bind);
5230 LOAD_PROC (connect);
5231 LOAD_PROC (ioctlsocket);
5232 LOAD_PROC (recv);
5233 LOAD_PROC (send);
5234 LOAD_PROC (closesocket);
5235 LOAD_PROC (shutdown);
5236 LOAD_PROC (htons);
5237 LOAD_PROC (ntohs);
5238 LOAD_PROC (inet_addr);
5239 LOAD_PROC (gethostname);
5240 LOAD_PROC (gethostbyname);
5241 LOAD_PROC (getservbyname);
5242 LOAD_PROC (getpeername);
5243 LOAD_PROC (WSACleanup);
5244 LOAD_PROC (setsockopt);
5245 LOAD_PROC (listen);
5246 LOAD_PROC (getsockname);
5247 LOAD_PROC (accept);
5248 LOAD_PROC (recvfrom);
5249 LOAD_PROC (sendto);
5250 #undef LOAD_PROC
5252 /* specify version 1.1 of winsock */
5253 if (pfn_WSAStartup (0x101, &winsockData) == 0)
5255 if (winsockData.wVersion != 0x101)
5256 goto fail;
5258 if (!load_now)
5260 /* Report that winsock exists and is usable, but leave
5261 socket functions disabled. I am assuming that calling
5262 WSAStartup does not require any network interaction,
5263 and in particular does not cause or require a dial-up
5264 connection to be established. */
5266 pfn_WSACleanup ();
5267 FreeLibrary (winsock_lib);
5268 winsock_lib = NULL;
5270 winsock_inuse = 0;
5271 return TRUE;
5274 fail:
5275 FreeLibrary (winsock_lib);
5276 winsock_lib = NULL;
5279 return FALSE;
5283 int h_errno = 0;
5285 /* function to set h_errno for compatibility; map winsock error codes to
5286 normal system codes where they overlap (non-overlapping definitions
5287 are already in <sys/socket.h> */
5288 static void
5289 set_errno (void)
5291 if (winsock_lib == NULL)
5292 h_errno = EINVAL;
5293 else
5294 h_errno = pfn_WSAGetLastError ();
5296 switch (h_errno)
5298 case WSAEACCES: h_errno = EACCES; break;
5299 case WSAEBADF: h_errno = EBADF; break;
5300 case WSAEFAULT: h_errno = EFAULT; break;
5301 case WSAEINTR: h_errno = EINTR; break;
5302 case WSAEINVAL: h_errno = EINVAL; break;
5303 case WSAEMFILE: h_errno = EMFILE; break;
5304 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
5305 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
5307 errno = h_errno;
5310 static void
5311 check_errno (void)
5313 if (h_errno == 0 && winsock_lib != NULL)
5314 pfn_WSASetLastError (0);
5317 /* Extend strerror to handle the winsock-specific error codes. */
5318 struct {
5319 int errnum;
5320 char * msg;
5321 } _wsa_errlist[] = {
5322 {WSAEINTR , "Interrupted function call"},
5323 {WSAEBADF , "Bad file descriptor"},
5324 {WSAEACCES , "Permission denied"},
5325 {WSAEFAULT , "Bad address"},
5326 {WSAEINVAL , "Invalid argument"},
5327 {WSAEMFILE , "Too many open files"},
5329 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
5330 {WSAEINPROGRESS , "Operation now in progress"},
5331 {WSAEALREADY , "Operation already in progress"},
5332 {WSAENOTSOCK , "Socket operation on non-socket"},
5333 {WSAEDESTADDRREQ , "Destination address required"},
5334 {WSAEMSGSIZE , "Message too long"},
5335 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
5336 {WSAENOPROTOOPT , "Bad protocol option"},
5337 {WSAEPROTONOSUPPORT , "Protocol not supported"},
5338 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
5339 {WSAEOPNOTSUPP , "Operation not supported"},
5340 {WSAEPFNOSUPPORT , "Protocol family not supported"},
5341 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
5342 {WSAEADDRINUSE , "Address already in use"},
5343 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
5344 {WSAENETDOWN , "Network is down"},
5345 {WSAENETUNREACH , "Network is unreachable"},
5346 {WSAENETRESET , "Network dropped connection on reset"},
5347 {WSAECONNABORTED , "Software caused connection abort"},
5348 {WSAECONNRESET , "Connection reset by peer"},
5349 {WSAENOBUFS , "No buffer space available"},
5350 {WSAEISCONN , "Socket is already connected"},
5351 {WSAENOTCONN , "Socket is not connected"},
5352 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
5353 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
5354 {WSAETIMEDOUT , "Connection timed out"},
5355 {WSAECONNREFUSED , "Connection refused"},
5356 {WSAELOOP , "Network loop"}, /* not sure */
5357 {WSAENAMETOOLONG , "Name is too long"},
5358 {WSAEHOSTDOWN , "Host is down"},
5359 {WSAEHOSTUNREACH , "No route to host"},
5360 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
5361 {WSAEPROCLIM , "Too many processes"},
5362 {WSAEUSERS , "Too many users"}, /* not sure */
5363 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
5364 {WSAESTALE , "Data is stale"}, /* not sure */
5365 {WSAEREMOTE , "Remote error"}, /* not sure */
5367 {WSASYSNOTREADY , "Network subsystem is unavailable"},
5368 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
5369 {WSANOTINITIALISED , "Winsock not initialized successfully"},
5370 {WSAEDISCON , "Graceful shutdown in progress"},
5371 #ifdef WSAENOMORE
5372 {WSAENOMORE , "No more operations allowed"}, /* not sure */
5373 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
5374 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
5375 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
5376 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
5377 {WSASYSCALLFAILURE , "System call failure"},
5378 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
5379 {WSATYPE_NOT_FOUND , "Class type not found"},
5380 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
5381 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
5382 {WSAEREFUSED , "Operation refused"}, /* not sure */
5383 #endif
5385 {WSAHOST_NOT_FOUND , "Host not found"},
5386 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
5387 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
5388 {WSANO_DATA , "Valid name, no data record of requested type"},
5390 {-1, NULL}
5393 char *
5394 sys_strerror (int error_no)
5396 int i;
5397 static char unknown_msg[40];
5399 if (error_no >= 0 && error_no < sys_nerr)
5400 return sys_errlist[error_no];
5402 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
5403 if (_wsa_errlist[i].errnum == error_no)
5404 return _wsa_errlist[i].msg;
5406 sprintf (unknown_msg, "Unidentified error: %d", error_no);
5407 return unknown_msg;
5410 /* [andrewi 3-May-96] I've had conflicting results using both methods,
5411 but I believe the method of keeping the socket handle separate (and
5412 insuring it is not inheritable) is the correct one. */
5414 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
5416 static int socket_to_fd (SOCKET s);
5419 sys_socket (int af, int type, int protocol)
5421 SOCKET s;
5423 if (winsock_lib == NULL)
5425 h_errno = ENETDOWN;
5426 return INVALID_SOCKET;
5429 check_errno ();
5431 /* call the real socket function */
5432 s = pfn_socket (af, type, protocol);
5434 if (s != INVALID_SOCKET)
5435 return socket_to_fd (s);
5437 set_errno ();
5438 return -1;
5441 /* Convert a SOCKET to a file descriptor. */
5442 static int
5443 socket_to_fd (SOCKET s)
5445 int fd;
5446 child_process * cp;
5448 /* Although under NT 3.5 _open_osfhandle will accept a socket
5449 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
5450 that does not work under NT 3.1. However, we can get the same
5451 effect by using a backdoor function to replace an existing
5452 descriptor handle with the one we want. */
5454 /* allocate a file descriptor (with appropriate flags) */
5455 fd = _open ("NUL:", _O_RDWR);
5456 if (fd >= 0)
5458 /* Make a non-inheritable copy of the socket handle. Note
5459 that it is possible that sockets aren't actually kernel
5460 handles, which appears to be the case on Windows 9x when
5461 the MS Proxy winsock client is installed. */
5463 /* Apparently there is a bug in NT 3.51 with some service
5464 packs, which prevents using DuplicateHandle to make a
5465 socket handle non-inheritable (causes WSACleanup to
5466 hang). The work-around is to use SetHandleInformation
5467 instead if it is available and implemented. */
5468 if (pfn_SetHandleInformation)
5470 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
5472 else
5474 HANDLE parent = GetCurrentProcess ();
5475 HANDLE new_s = INVALID_HANDLE_VALUE;
5477 if (DuplicateHandle (parent,
5478 (HANDLE) s,
5479 parent,
5480 &new_s,
5482 FALSE,
5483 DUPLICATE_SAME_ACCESS))
5485 /* It is possible that DuplicateHandle succeeds even
5486 though the socket wasn't really a kernel handle,
5487 because a real handle has the same value. So
5488 test whether the new handle really is a socket. */
5489 long nonblocking = 0;
5490 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
5492 pfn_closesocket (s);
5493 s = (SOCKET) new_s;
5495 else
5497 CloseHandle (new_s);
5502 fd_info[fd].hnd = (HANDLE) s;
5504 /* set our own internal flags */
5505 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
5507 cp = new_child ();
5508 if (cp)
5510 cp->fd = fd;
5511 cp->status = STATUS_READ_ACKNOWLEDGED;
5513 /* attach child_process to fd_info */
5514 if (fd_info[ fd ].cp != NULL)
5516 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
5517 emacs_abort ();
5520 fd_info[ fd ].cp = cp;
5522 /* success! */
5523 winsock_inuse++; /* count open sockets */
5524 return fd;
5527 /* clean up */
5528 _close (fd);
5530 pfn_closesocket (s);
5531 h_errno = EMFILE;
5532 return -1;
5536 sys_bind (int s, const struct sockaddr * addr, int namelen)
5538 if (winsock_lib == NULL)
5540 h_errno = ENOTSOCK;
5541 return SOCKET_ERROR;
5544 check_errno ();
5545 if (fd_info[s].flags & FILE_SOCKET)
5547 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
5548 if (rc == SOCKET_ERROR)
5549 set_errno ();
5550 return rc;
5552 h_errno = ENOTSOCK;
5553 return SOCKET_ERROR;
5557 sys_connect (int s, const struct sockaddr * name, int namelen)
5559 if (winsock_lib == NULL)
5561 h_errno = ENOTSOCK;
5562 return SOCKET_ERROR;
5565 check_errno ();
5566 if (fd_info[s].flags & FILE_SOCKET)
5568 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
5569 if (rc == SOCKET_ERROR)
5570 set_errno ();
5571 return rc;
5573 h_errno = ENOTSOCK;
5574 return SOCKET_ERROR;
5577 u_short
5578 sys_htons (u_short hostshort)
5580 return (winsock_lib != NULL) ?
5581 pfn_htons (hostshort) : hostshort;
5584 u_short
5585 sys_ntohs (u_short netshort)
5587 return (winsock_lib != NULL) ?
5588 pfn_ntohs (netshort) : netshort;
5591 unsigned long
5592 sys_inet_addr (const char * cp)
5594 return (winsock_lib != NULL) ?
5595 pfn_inet_addr (cp) : INADDR_NONE;
5599 sys_gethostname (char * name, int namelen)
5601 if (winsock_lib != NULL)
5602 return pfn_gethostname (name, namelen);
5604 if (namelen > MAX_COMPUTERNAME_LENGTH)
5605 return !GetComputerName (name, (DWORD *)&namelen);
5607 h_errno = EFAULT;
5608 return SOCKET_ERROR;
5611 struct hostent *
5612 sys_gethostbyname (const char * name)
5614 struct hostent * host;
5616 if (winsock_lib == NULL)
5618 h_errno = ENETDOWN;
5619 return NULL;
5622 check_errno ();
5623 host = pfn_gethostbyname (name);
5624 if (!host)
5625 set_errno ();
5626 return host;
5629 struct servent *
5630 sys_getservbyname (const char * name, const char * proto)
5632 struct servent * serv;
5634 if (winsock_lib == NULL)
5636 h_errno = ENETDOWN;
5637 return NULL;
5640 check_errno ();
5641 serv = pfn_getservbyname (name, proto);
5642 if (!serv)
5643 set_errno ();
5644 return serv;
5648 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
5650 if (winsock_lib == NULL)
5652 h_errno = ENETDOWN;
5653 return SOCKET_ERROR;
5656 check_errno ();
5657 if (fd_info[s].flags & FILE_SOCKET)
5659 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
5660 if (rc == SOCKET_ERROR)
5661 set_errno ();
5662 return rc;
5664 h_errno = ENOTSOCK;
5665 return SOCKET_ERROR;
5669 sys_shutdown (int s, int how)
5671 if (winsock_lib == NULL)
5673 h_errno = ENETDOWN;
5674 return SOCKET_ERROR;
5677 check_errno ();
5678 if (fd_info[s].flags & FILE_SOCKET)
5680 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
5681 if (rc == SOCKET_ERROR)
5682 set_errno ();
5683 return rc;
5685 h_errno = ENOTSOCK;
5686 return SOCKET_ERROR;
5690 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
5692 if (winsock_lib == NULL)
5694 h_errno = ENETDOWN;
5695 return SOCKET_ERROR;
5698 check_errno ();
5699 if (fd_info[s].flags & FILE_SOCKET)
5701 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
5702 (const char *)optval, optlen);
5703 if (rc == SOCKET_ERROR)
5704 set_errno ();
5705 return rc;
5707 h_errno = ENOTSOCK;
5708 return SOCKET_ERROR;
5712 sys_listen (int s, int backlog)
5714 if (winsock_lib == NULL)
5716 h_errno = ENETDOWN;
5717 return SOCKET_ERROR;
5720 check_errno ();
5721 if (fd_info[s].flags & FILE_SOCKET)
5723 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
5724 if (rc == SOCKET_ERROR)
5725 set_errno ();
5726 else
5727 fd_info[s].flags |= FILE_LISTEN;
5728 return rc;
5730 h_errno = ENOTSOCK;
5731 return SOCKET_ERROR;
5735 sys_getsockname (int s, struct sockaddr * name, int * namelen)
5737 if (winsock_lib == NULL)
5739 h_errno = ENETDOWN;
5740 return SOCKET_ERROR;
5743 check_errno ();
5744 if (fd_info[s].flags & FILE_SOCKET)
5746 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
5747 if (rc == SOCKET_ERROR)
5748 set_errno ();
5749 return rc;
5751 h_errno = ENOTSOCK;
5752 return SOCKET_ERROR;
5756 sys_accept (int s, struct sockaddr * addr, int * addrlen)
5758 if (winsock_lib == NULL)
5760 h_errno = ENETDOWN;
5761 return -1;
5764 check_errno ();
5765 if (fd_info[s].flags & FILE_LISTEN)
5767 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
5768 int fd = -1;
5769 if (t == INVALID_SOCKET)
5770 set_errno ();
5771 else
5772 fd = socket_to_fd (t);
5774 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
5775 ResetEvent (fd_info[s].cp->char_avail);
5776 return fd;
5778 h_errno = ENOTSOCK;
5779 return -1;
5783 sys_recvfrom (int s, char * buf, int len, int flags,
5784 struct sockaddr * from, int * fromlen)
5786 if (winsock_lib == NULL)
5788 h_errno = ENETDOWN;
5789 return SOCKET_ERROR;
5792 check_errno ();
5793 if (fd_info[s].flags & FILE_SOCKET)
5795 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
5796 if (rc == SOCKET_ERROR)
5797 set_errno ();
5798 return rc;
5800 h_errno = ENOTSOCK;
5801 return SOCKET_ERROR;
5805 sys_sendto (int s, const char * buf, int len, int flags,
5806 const struct sockaddr * to, int tolen)
5808 if (winsock_lib == NULL)
5810 h_errno = ENETDOWN;
5811 return SOCKET_ERROR;
5814 check_errno ();
5815 if (fd_info[s].flags & FILE_SOCKET)
5817 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
5818 if (rc == SOCKET_ERROR)
5819 set_errno ();
5820 return rc;
5822 h_errno = ENOTSOCK;
5823 return SOCKET_ERROR;
5826 /* Windows does not have an fcntl function. Provide an implementation
5827 solely for making sockets non-blocking. */
5829 fcntl (int s, int cmd, int options)
5831 if (winsock_lib == NULL)
5833 h_errno = ENETDOWN;
5834 return -1;
5837 check_errno ();
5838 if (fd_info[s].flags & FILE_SOCKET)
5840 if (cmd == F_SETFL && options == O_NDELAY)
5842 unsigned long nblock = 1;
5843 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
5844 if (rc == SOCKET_ERROR)
5845 set_errno ();
5846 /* Keep track of the fact that we set this to non-blocking. */
5847 fd_info[s].flags |= FILE_NDELAY;
5848 return rc;
5850 else
5852 h_errno = EINVAL;
5853 return SOCKET_ERROR;
5856 h_errno = ENOTSOCK;
5857 return SOCKET_ERROR;
5861 /* Shadow main io functions: we need to handle pipes and sockets more
5862 intelligently, and implement non-blocking mode as well. */
5865 sys_close (int fd)
5867 int rc;
5869 if (fd < 0)
5871 errno = EBADF;
5872 return -1;
5875 if (fd < MAXDESC && fd_info[fd].cp)
5877 child_process * cp = fd_info[fd].cp;
5879 fd_info[fd].cp = NULL;
5881 if (CHILD_ACTIVE (cp))
5883 /* if last descriptor to active child_process then cleanup */
5884 int i;
5885 for (i = 0; i < MAXDESC; i++)
5887 if (i == fd)
5888 continue;
5889 if (fd_info[i].cp == cp)
5890 break;
5892 if (i == MAXDESC)
5894 if (fd_info[fd].flags & FILE_SOCKET)
5896 if (winsock_lib == NULL) emacs_abort ();
5898 pfn_shutdown (SOCK_HANDLE (fd), 2);
5899 rc = pfn_closesocket (SOCK_HANDLE (fd));
5901 winsock_inuse--; /* count open sockets */
5903 delete_child (cp);
5908 /* Note that sockets do not need special treatment here (at least on
5909 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5910 closesocket is equivalent to CloseHandle, which is to be expected
5911 because socket handles are fully fledged kernel handles. */
5912 rc = _close (fd);
5914 if (rc == 0 && fd < MAXDESC)
5915 fd_info[fd].flags = 0;
5917 return rc;
5921 sys_dup (int fd)
5923 int new_fd;
5925 new_fd = _dup (fd);
5926 if (new_fd >= 0 && new_fd < MAXDESC)
5928 /* duplicate our internal info as well */
5929 fd_info[new_fd] = fd_info[fd];
5931 return new_fd;
5935 sys_dup2 (int src, int dst)
5937 int rc;
5939 if (dst < 0 || dst >= MAXDESC)
5941 errno = EBADF;
5942 return -1;
5945 /* make sure we close the destination first if it's a pipe or socket */
5946 if (src != dst && fd_info[dst].flags != 0)
5947 sys_close (dst);
5949 rc = _dup2 (src, dst);
5950 if (rc == 0)
5952 /* duplicate our internal info as well */
5953 fd_info[dst] = fd_info[src];
5955 return rc;
5958 /* Unix pipe() has only one arg */
5960 sys_pipe (int * phandles)
5962 int rc;
5963 unsigned flags;
5965 /* make pipe handles non-inheritable; when we spawn a child, we
5966 replace the relevant handle with an inheritable one. Also put
5967 pipes into binary mode; we will do text mode translation ourselves
5968 if required. */
5969 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
5971 if (rc == 0)
5973 /* Protect against overflow, since Windows can open more handles than
5974 our fd_info array has room for. */
5975 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
5977 _close (phandles[0]);
5978 _close (phandles[1]);
5979 rc = -1;
5981 else
5983 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
5984 fd_info[phandles[0]].flags = flags;
5986 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
5987 fd_info[phandles[1]].flags = flags;
5991 return rc;
5994 /* Function to do blocking read of one byte, needed to implement
5995 select. It is only allowed on sockets and pipes. */
5997 _sys_read_ahead (int fd)
5999 child_process * cp;
6000 int rc;
6002 if (fd < 0 || fd >= MAXDESC)
6003 return STATUS_READ_ERROR;
6005 cp = fd_info[fd].cp;
6007 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
6008 return STATUS_READ_ERROR;
6010 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
6011 || (fd_info[fd].flags & FILE_READ) == 0)
6013 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
6014 emacs_abort ();
6017 cp->status = STATUS_READ_IN_PROGRESS;
6019 if (fd_info[fd].flags & FILE_PIPE)
6021 rc = _read (fd, &cp->chr, sizeof (char));
6023 /* Give subprocess time to buffer some more output for us before
6024 reporting that input is available; we need this because Windows 95
6025 connects DOS programs to pipes by making the pipe appear to be
6026 the normal console stdout - as a result most DOS programs will
6027 write to stdout without buffering, ie. one character at a
6028 time. Even some W32 programs do this - "dir" in a command
6029 shell on NT is very slow if we don't do this. */
6030 if (rc > 0)
6032 int wait = w32_pipe_read_delay;
6034 if (wait > 0)
6035 Sleep (wait);
6036 else if (wait < 0)
6037 while (++wait <= 0)
6038 /* Yield remainder of our time slice, effectively giving a
6039 temporary priority boost to the child process. */
6040 Sleep (0);
6043 else if (fd_info[fd].flags & FILE_SERIAL)
6045 HANDLE hnd = fd_info[fd].hnd;
6046 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
6047 COMMTIMEOUTS ct;
6049 /* Configure timeouts for blocking read. */
6050 if (!GetCommTimeouts (hnd, &ct))
6051 return STATUS_READ_ERROR;
6052 ct.ReadIntervalTimeout = 0;
6053 ct.ReadTotalTimeoutMultiplier = 0;
6054 ct.ReadTotalTimeoutConstant = 0;
6055 if (!SetCommTimeouts (hnd, &ct))
6056 return STATUS_READ_ERROR;
6058 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
6060 if (GetLastError () != ERROR_IO_PENDING)
6061 return STATUS_READ_ERROR;
6062 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
6063 return STATUS_READ_ERROR;
6066 else if (fd_info[fd].flags & FILE_SOCKET)
6068 unsigned long nblock = 0;
6069 /* We always want this to block, so temporarily disable NDELAY. */
6070 if (fd_info[fd].flags & FILE_NDELAY)
6071 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6073 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
6075 if (fd_info[fd].flags & FILE_NDELAY)
6077 nblock = 1;
6078 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6082 if (rc == sizeof (char))
6083 cp->status = STATUS_READ_SUCCEEDED;
6084 else
6085 cp->status = STATUS_READ_FAILED;
6087 return cp->status;
6091 _sys_wait_accept (int fd)
6093 HANDLE hEv;
6094 child_process * cp;
6095 int rc;
6097 if (fd < 0 || fd >= MAXDESC)
6098 return STATUS_READ_ERROR;
6100 cp = fd_info[fd].cp;
6102 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
6103 return STATUS_READ_ERROR;
6105 cp->status = STATUS_READ_FAILED;
6107 hEv = pfn_WSACreateEvent ();
6108 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
6109 if (rc != SOCKET_ERROR)
6111 rc = WaitForSingleObject (hEv, INFINITE);
6112 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
6113 if (rc == WAIT_OBJECT_0)
6114 cp->status = STATUS_READ_SUCCEEDED;
6116 pfn_WSACloseEvent (hEv);
6118 return cp->status;
6122 sys_read (int fd, char * buffer, unsigned int count)
6124 int nchars;
6125 int to_read;
6126 DWORD waiting;
6127 char * orig_buffer = buffer;
6129 if (fd < 0)
6131 errno = EBADF;
6132 return -1;
6135 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
6137 child_process *cp = fd_info[fd].cp;
6139 if ((fd_info[fd].flags & FILE_READ) == 0)
6141 errno = EBADF;
6142 return -1;
6145 nchars = 0;
6147 /* re-read CR carried over from last read */
6148 if (fd_info[fd].flags & FILE_LAST_CR)
6150 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
6151 *buffer++ = 0x0d;
6152 count--;
6153 nchars++;
6154 fd_info[fd].flags &= ~FILE_LAST_CR;
6157 /* presence of a child_process structure means we are operating in
6158 non-blocking mode - otherwise we just call _read directly.
6159 Note that the child_process structure might be missing because
6160 reap_subprocess has been called; in this case the pipe is
6161 already broken, so calling _read on it is okay. */
6162 if (cp)
6164 int current_status = cp->status;
6166 switch (current_status)
6168 case STATUS_READ_FAILED:
6169 case STATUS_READ_ERROR:
6170 /* report normal EOF if nothing in buffer */
6171 if (nchars <= 0)
6172 fd_info[fd].flags |= FILE_AT_EOF;
6173 return nchars;
6175 case STATUS_READ_READY:
6176 case STATUS_READ_IN_PROGRESS:
6177 DebPrint (("sys_read called when read is in progress\n"));
6178 errno = EWOULDBLOCK;
6179 return -1;
6181 case STATUS_READ_SUCCEEDED:
6182 /* consume read-ahead char */
6183 *buffer++ = cp->chr;
6184 count--;
6185 nchars++;
6186 cp->status = STATUS_READ_ACKNOWLEDGED;
6187 ResetEvent (cp->char_avail);
6189 case STATUS_READ_ACKNOWLEDGED:
6190 break;
6192 default:
6193 DebPrint (("sys_read: bad status %d\n", current_status));
6194 errno = EBADF;
6195 return -1;
6198 if (fd_info[fd].flags & FILE_PIPE)
6200 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
6201 to_read = min (waiting, (DWORD) count);
6203 if (to_read > 0)
6204 nchars += _read (fd, buffer, to_read);
6206 else if (fd_info[fd].flags & FILE_SERIAL)
6208 HANDLE hnd = fd_info[fd].hnd;
6209 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
6210 int rc = 0;
6211 COMMTIMEOUTS ct;
6213 if (count > 0)
6215 /* Configure timeouts for non-blocking read. */
6216 if (!GetCommTimeouts (hnd, &ct))
6218 errno = EIO;
6219 return -1;
6221 ct.ReadIntervalTimeout = MAXDWORD;
6222 ct.ReadTotalTimeoutMultiplier = 0;
6223 ct.ReadTotalTimeoutConstant = 0;
6224 if (!SetCommTimeouts (hnd, &ct))
6226 errno = EIO;
6227 return -1;
6230 if (!ResetEvent (ovl->hEvent))
6232 errno = EIO;
6233 return -1;
6235 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
6237 if (GetLastError () != ERROR_IO_PENDING)
6239 errno = EIO;
6240 return -1;
6242 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
6244 errno = EIO;
6245 return -1;
6248 nchars += rc;
6251 else /* FILE_SOCKET */
6253 if (winsock_lib == NULL) emacs_abort ();
6255 /* do the equivalent of a non-blocking read */
6256 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
6257 if (waiting == 0 && nchars == 0)
6259 h_errno = errno = EWOULDBLOCK;
6260 return -1;
6263 if (waiting)
6265 /* always use binary mode for sockets */
6266 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
6267 if (res == SOCKET_ERROR)
6269 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
6270 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
6271 set_errno ();
6272 return -1;
6274 nchars += res;
6278 else
6280 int nread = _read (fd, buffer, count);
6281 if (nread >= 0)
6282 nchars += nread;
6283 else if (nchars == 0)
6284 nchars = nread;
6287 if (nchars <= 0)
6288 fd_info[fd].flags |= FILE_AT_EOF;
6289 /* Perform text mode translation if required. */
6290 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
6292 nchars = crlf_to_lf (nchars, orig_buffer);
6293 /* If buffer contains only CR, return that. To be absolutely
6294 sure we should attempt to read the next char, but in
6295 practice a CR to be followed by LF would not appear by
6296 itself in the buffer. */
6297 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
6299 fd_info[fd].flags |= FILE_LAST_CR;
6300 nchars--;
6304 else
6305 nchars = _read (fd, buffer, count);
6307 return nchars;
6310 /* From w32xfns.c */
6311 extern HANDLE interrupt_handle;
6313 /* For now, don't bother with a non-blocking mode */
6315 sys_write (int fd, const void * buffer, unsigned int count)
6317 int nchars;
6319 if (fd < 0)
6321 errno = EBADF;
6322 return -1;
6325 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
6327 if ((fd_info[fd].flags & FILE_WRITE) == 0)
6329 errno = EBADF;
6330 return -1;
6333 /* Perform text mode translation if required. */
6334 if ((fd_info[fd].flags & FILE_BINARY) == 0)
6336 char * tmpbuf = alloca (count * 2);
6337 unsigned char * src = (void *)buffer;
6338 unsigned char * dst = tmpbuf;
6339 int nbytes = count;
6341 while (1)
6343 unsigned char *next;
6344 /* copy next line or remaining bytes */
6345 next = _memccpy (dst, src, '\n', nbytes);
6346 if (next)
6348 /* copied one line ending with '\n' */
6349 int copied = next - dst;
6350 nbytes -= copied;
6351 src += copied;
6352 /* insert '\r' before '\n' */
6353 next[-1] = '\r';
6354 next[0] = '\n';
6355 dst = next + 1;
6356 count++;
6358 else
6359 /* copied remaining partial line -> now finished */
6360 break;
6362 buffer = tmpbuf;
6366 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
6368 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
6369 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
6370 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
6371 DWORD active = 0;
6373 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
6375 if (GetLastError () != ERROR_IO_PENDING)
6377 errno = EIO;
6378 return -1;
6380 if (detect_input_pending ())
6381 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
6382 QS_ALLINPUT);
6383 else
6384 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
6385 if (active == WAIT_OBJECT_0)
6386 { /* User pressed C-g, cancel write, then leave. Don't bother
6387 cleaning up as we may only get stuck in buggy drivers. */
6388 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
6389 CancelIo (hnd);
6390 errno = EIO;
6391 return -1;
6393 if (active == WAIT_OBJECT_0 + 1
6394 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
6396 errno = EIO;
6397 return -1;
6401 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
6403 unsigned long nblock = 0;
6404 if (winsock_lib == NULL) emacs_abort ();
6406 /* TODO: implement select() properly so non-blocking I/O works. */
6407 /* For now, make sure the write blocks. */
6408 if (fd_info[fd].flags & FILE_NDELAY)
6409 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6411 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
6413 /* Set the socket back to non-blocking if it was before,
6414 for other operations that support it. */
6415 if (fd_info[fd].flags & FILE_NDELAY)
6417 nblock = 1;
6418 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6421 if (nchars == SOCKET_ERROR)
6423 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
6424 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
6425 set_errno ();
6428 else
6430 /* Some networked filesystems don't like too large writes, so
6431 break them into smaller chunks. See the Comments section of
6432 the MSDN documentation of WriteFile for details behind the
6433 choice of the value of CHUNK below. See also the thread
6434 http://thread.gmane.org/gmane.comp.version-control.git/145294
6435 in the git mailing list. */
6436 const unsigned char *p = buffer;
6437 const unsigned chunk = 30 * 1024 * 1024;
6439 nchars = 0;
6440 while (count > 0)
6442 unsigned this_chunk = count < chunk ? count : chunk;
6443 int n = _write (fd, p, this_chunk);
6445 nchars += n;
6446 if (n < 0)
6448 nchars = n;
6449 break;
6451 else if (n < this_chunk)
6452 break;
6453 count -= n;
6454 p += n;
6458 return nchars;
6461 /* The Windows CRT functions are "optimized for speed", so they don't
6462 check for timezone and DST changes if they were last called less
6463 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
6464 all Emacs features that repeatedly call time functions (e.g.,
6465 display-time) are in real danger of missing timezone and DST
6466 changes. Calling tzset before each localtime call fixes that. */
6467 struct tm *
6468 sys_localtime (const time_t *t)
6470 tzset ();
6471 return localtime (t);
6476 /* Try loading LIBRARY_ID from the file(s) specified in
6477 Vdynamic_library_alist. If the library is loaded successfully,
6478 return the handle of the DLL, and record the filename in the
6479 property :loaded-from of LIBRARY_ID. If the library could not be
6480 found, or when it was already loaded (because the handle is not
6481 recorded anywhere, and so is lost after use), return NULL.
6483 We could also save the handle in :loaded-from, but currently
6484 there's no use case for it. */
6485 HMODULE
6486 w32_delayed_load (Lisp_Object library_id)
6488 HMODULE library_dll = NULL;
6490 CHECK_SYMBOL (library_id);
6492 if (CONSP (Vdynamic_library_alist)
6493 && NILP (Fassq (library_id, Vlibrary_cache)))
6495 Lisp_Object found = Qnil;
6496 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
6498 if (CONSP (dlls))
6499 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
6501 CHECK_STRING_CAR (dlls);
6502 if ((library_dll = LoadLibrary (SDATA (XCAR (dlls)))))
6504 char name[MAX_PATH];
6505 DWORD len;
6507 len = GetModuleFileNameA (library_dll, name, sizeof (name));
6508 found = Fcons (XCAR (dlls),
6509 (len > 0)
6510 /* Possibly truncated */
6511 ? make_specified_string (name, -1, len, 1)
6512 : Qnil);
6513 break;
6517 Fput (library_id, QCloaded_from, found);
6520 return library_dll;
6524 void
6525 check_windows_init_file (void)
6527 /* A common indication that Emacs is not installed properly is when
6528 it cannot find the Windows installation file. If this file does
6529 not exist in the expected place, tell the user. */
6531 if (!noninteractive && !inhibit_window_system
6532 /* Vload_path is not yet initialized when we are loading
6533 loadup.el. */
6534 && NILP (Vpurify_flag))
6536 Lisp_Object init_file;
6537 int fd;
6539 init_file = build_string ("term/w32-win");
6540 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
6541 if (fd < 0)
6543 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
6544 char *init_file_name = SDATA (init_file);
6545 char *load_path = SDATA (load_path_print);
6546 char *buffer = alloca (1024
6547 + strlen (init_file_name)
6548 + strlen (load_path));
6550 sprintf (buffer,
6551 "The Emacs Windows initialization file \"%s.el\" "
6552 "could not be found in your Emacs installation. "
6553 "Emacs checked the following directories for this file:\n"
6554 "\n%s\n\n"
6555 "When Emacs cannot find this file, it usually means that it "
6556 "was not installed properly, or its distribution file was "
6557 "not unpacked properly.\nSee the README.W32 file in the "
6558 "top-level Emacs directory for more information.",
6559 init_file_name, load_path);
6560 MessageBox (NULL,
6561 buffer,
6562 "Emacs Abort Dialog",
6563 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
6564 /* Use the low-level system abort. */
6565 abort ();
6567 else
6569 _close (fd);
6574 void
6575 term_ntproc (int ignored)
6577 (void)ignored;
6579 term_timers ();
6581 /* shutdown the socket interface if necessary */
6582 term_winsock ();
6584 term_w32select ();
6587 void
6588 init_ntproc (int dumping)
6590 sigset_t initial_mask = 0;
6592 /* Initialize the socket interface now if available and requested by
6593 the user by defining PRELOAD_WINSOCK; otherwise loading will be
6594 delayed until open-network-stream is called (w32-has-winsock can
6595 also be used to dynamically load or reload winsock).
6597 Conveniently, init_environment is called before us, so
6598 PRELOAD_WINSOCK can be set in the registry. */
6600 /* Always initialize this correctly. */
6601 winsock_lib = NULL;
6603 if (getenv ("PRELOAD_WINSOCK") != NULL)
6604 init_winsock (TRUE);
6606 /* Initial preparation for subprocess support: replace our standard
6607 handles with non-inheritable versions. */
6609 HANDLE parent;
6610 HANDLE stdin_save = INVALID_HANDLE_VALUE;
6611 HANDLE stdout_save = INVALID_HANDLE_VALUE;
6612 HANDLE stderr_save = INVALID_HANDLE_VALUE;
6614 parent = GetCurrentProcess ();
6616 /* ignore errors when duplicating and closing; typically the
6617 handles will be invalid when running as a gui program. */
6618 DuplicateHandle (parent,
6619 GetStdHandle (STD_INPUT_HANDLE),
6620 parent,
6621 &stdin_save,
6623 FALSE,
6624 DUPLICATE_SAME_ACCESS);
6626 DuplicateHandle (parent,
6627 GetStdHandle (STD_OUTPUT_HANDLE),
6628 parent,
6629 &stdout_save,
6631 FALSE,
6632 DUPLICATE_SAME_ACCESS);
6634 DuplicateHandle (parent,
6635 GetStdHandle (STD_ERROR_HANDLE),
6636 parent,
6637 &stderr_save,
6639 FALSE,
6640 DUPLICATE_SAME_ACCESS);
6642 fclose (stdin);
6643 fclose (stdout);
6644 fclose (stderr);
6646 if (stdin_save != INVALID_HANDLE_VALUE)
6647 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
6648 else
6649 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
6650 _fdopen (0, "r");
6652 if (stdout_save != INVALID_HANDLE_VALUE)
6653 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
6654 else
6655 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
6656 _fdopen (1, "w");
6658 if (stderr_save != INVALID_HANDLE_VALUE)
6659 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
6660 else
6661 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
6662 _fdopen (2, "w");
6665 /* unfortunately, atexit depends on implementation of malloc */
6666 /* atexit (term_ntproc); */
6667 if (!dumping)
6669 /* Make sure we start with all signals unblocked. */
6670 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
6671 signal (SIGABRT, term_ntproc);
6673 init_timers ();
6675 /* determine which drives are fixed, for GetCachedVolumeInformation */
6677 /* GetDriveType must have trailing backslash. */
6678 char drive[] = "A:\\";
6680 /* Loop over all possible drive letters */
6681 while (*drive <= 'Z')
6683 /* Record if this drive letter refers to a fixed drive. */
6684 fixed_drives[DRIVE_INDEX (*drive)] =
6685 (GetDriveType (drive) == DRIVE_FIXED);
6687 (*drive)++;
6690 /* Reset the volume info cache. */
6691 volume_cache = NULL;
6696 shutdown_handler ensures that buffers' autosave files are
6697 up to date when the user logs off, or the system shuts down.
6699 static BOOL WINAPI
6700 shutdown_handler (DWORD type)
6702 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
6703 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
6704 || type == CTRL_LOGOFF_EVENT /* User logs off. */
6705 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
6707 /* Shut down cleanly, making sure autosave files are up to date. */
6708 shut_down_emacs (0, Qnil);
6711 /* Allow other handlers to handle this signal. */
6712 return FALSE;
6716 globals_of_w32 is used to initialize those global variables that
6717 must always be initialized on startup even when the global variable
6718 initialized is non zero (see the function main in emacs.c).
6720 void
6721 globals_of_w32 (void)
6723 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
6725 get_process_times_fn = (GetProcessTimes_Proc)
6726 GetProcAddress (kernel32, "GetProcessTimes");
6728 DEFSYM (QCloaded_from, ":loaded-from");
6730 g_b_init_is_windows_9x = 0;
6731 g_b_init_open_process_token = 0;
6732 g_b_init_get_token_information = 0;
6733 g_b_init_lookup_account_sid = 0;
6734 g_b_init_get_sid_sub_authority = 0;
6735 g_b_init_get_sid_sub_authority_count = 0;
6736 g_b_init_get_security_info = 0;
6737 g_b_init_get_file_security = 0;
6738 g_b_init_get_security_descriptor_owner = 0;
6739 g_b_init_get_security_descriptor_group = 0;
6740 g_b_init_is_valid_sid = 0;
6741 g_b_init_create_toolhelp32_snapshot = 0;
6742 g_b_init_process32_first = 0;
6743 g_b_init_process32_next = 0;
6744 g_b_init_open_thread_token = 0;
6745 g_b_init_impersonate_self = 0;
6746 g_b_init_revert_to_self = 0;
6747 g_b_init_get_process_memory_info = 0;
6748 g_b_init_get_process_working_set_size = 0;
6749 g_b_init_global_memory_status = 0;
6750 g_b_init_global_memory_status_ex = 0;
6751 g_b_init_equal_sid = 0;
6752 g_b_init_copy_sid = 0;
6753 g_b_init_get_length_sid = 0;
6754 g_b_init_get_native_system_info = 0;
6755 g_b_init_get_system_times = 0;
6756 g_b_init_create_symbolic_link = 0;
6757 num_of_processors = 0;
6758 /* The following sets a handler for shutdown notifications for
6759 console apps. This actually applies to Emacs in both console and
6760 GUI modes, since we had to fool windows into thinking emacs is a
6761 console application to get console mode to work. */
6762 SetConsoleCtrlHandler (shutdown_handler, TRUE);
6764 /* "None" is the default group name on standalone workstations. */
6765 strcpy (dflt_group_name, "None");
6768 /* For make-serial-process */
6770 serial_open (char *port)
6772 HANDLE hnd;
6773 child_process *cp;
6774 int fd = -1;
6776 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
6777 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
6778 if (hnd == INVALID_HANDLE_VALUE)
6779 error ("Could not open %s", port);
6780 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
6781 if (fd == -1)
6782 error ("Could not open %s", port);
6784 cp = new_child ();
6785 if (!cp)
6786 error ("Could not create child process");
6787 cp->fd = fd;
6788 cp->status = STATUS_READ_ACKNOWLEDGED;
6789 fd_info[ fd ].hnd = hnd;
6790 fd_info[ fd ].flags |=
6791 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
6792 if (fd_info[ fd ].cp != NULL)
6794 error ("fd_info[fd = %d] is already in use", fd);
6796 fd_info[ fd ].cp = cp;
6797 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
6798 if (cp->ovl_read.hEvent == NULL)
6799 error ("Could not create read event");
6800 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
6801 if (cp->ovl_write.hEvent == NULL)
6802 error ("Could not create write event");
6804 return fd;
6807 /* For serial-process-configure */
6808 void
6809 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
6811 Lisp_Object childp2 = Qnil;
6812 Lisp_Object tem = Qnil;
6813 HANDLE hnd;
6814 DCB dcb;
6815 COMMTIMEOUTS ct;
6816 char summary[4] = "???"; /* This usually becomes "8N1". */
6818 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
6819 error ("Not a serial process");
6820 hnd = fd_info[ p->outfd ].hnd;
6822 childp2 = Fcopy_sequence (p->childp);
6824 /* Initialize timeouts for blocking read and blocking write. */
6825 if (!GetCommTimeouts (hnd, &ct))
6826 error ("GetCommTimeouts() failed");
6827 ct.ReadIntervalTimeout = 0;
6828 ct.ReadTotalTimeoutMultiplier = 0;
6829 ct.ReadTotalTimeoutConstant = 0;
6830 ct.WriteTotalTimeoutMultiplier = 0;
6831 ct.WriteTotalTimeoutConstant = 0;
6832 if (!SetCommTimeouts (hnd, &ct))
6833 error ("SetCommTimeouts() failed");
6834 /* Read port attributes and prepare default configuration. */
6835 memset (&dcb, 0, sizeof (dcb));
6836 dcb.DCBlength = sizeof (DCB);
6837 if (!GetCommState (hnd, &dcb))
6838 error ("GetCommState() failed");
6839 dcb.fBinary = TRUE;
6840 dcb.fNull = FALSE;
6841 dcb.fAbortOnError = FALSE;
6842 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6843 dcb.ErrorChar = 0;
6844 dcb.EofChar = 0;
6845 dcb.EvtChar = 0;
6847 /* Configure speed. */
6848 if (!NILP (Fplist_member (contact, QCspeed)))
6849 tem = Fplist_get (contact, QCspeed);
6850 else
6851 tem = Fplist_get (p->childp, QCspeed);
6852 CHECK_NUMBER (tem);
6853 dcb.BaudRate = XINT (tem);
6854 childp2 = Fplist_put (childp2, QCspeed, tem);
6856 /* Configure bytesize. */
6857 if (!NILP (Fplist_member (contact, QCbytesize)))
6858 tem = Fplist_get (contact, QCbytesize);
6859 else
6860 tem = Fplist_get (p->childp, QCbytesize);
6861 if (NILP (tem))
6862 tem = make_number (8);
6863 CHECK_NUMBER (tem);
6864 if (XINT (tem) != 7 && XINT (tem) != 8)
6865 error (":bytesize must be nil (8), 7, or 8");
6866 dcb.ByteSize = XINT (tem);
6867 summary[0] = XINT (tem) + '0';
6868 childp2 = Fplist_put (childp2, QCbytesize, tem);
6870 /* Configure parity. */
6871 if (!NILP (Fplist_member (contact, QCparity)))
6872 tem = Fplist_get (contact, QCparity);
6873 else
6874 tem = Fplist_get (p->childp, QCparity);
6875 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
6876 error (":parity must be nil (no parity), `even', or `odd'");
6877 dcb.fParity = FALSE;
6878 dcb.Parity = NOPARITY;
6879 dcb.fErrorChar = FALSE;
6880 if (NILP (tem))
6882 summary[1] = 'N';
6884 else if (EQ (tem, Qeven))
6886 summary[1] = 'E';
6887 dcb.fParity = TRUE;
6888 dcb.Parity = EVENPARITY;
6889 dcb.fErrorChar = TRUE;
6891 else if (EQ (tem, Qodd))
6893 summary[1] = 'O';
6894 dcb.fParity = TRUE;
6895 dcb.Parity = ODDPARITY;
6896 dcb.fErrorChar = TRUE;
6898 childp2 = Fplist_put (childp2, QCparity, tem);
6900 /* Configure stopbits. */
6901 if (!NILP (Fplist_member (contact, QCstopbits)))
6902 tem = Fplist_get (contact, QCstopbits);
6903 else
6904 tem = Fplist_get (p->childp, QCstopbits);
6905 if (NILP (tem))
6906 tem = make_number (1);
6907 CHECK_NUMBER (tem);
6908 if (XINT (tem) != 1 && XINT (tem) != 2)
6909 error (":stopbits must be nil (1 stopbit), 1, or 2");
6910 summary[2] = XINT (tem) + '0';
6911 if (XINT (tem) == 1)
6912 dcb.StopBits = ONESTOPBIT;
6913 else if (XINT (tem) == 2)
6914 dcb.StopBits = TWOSTOPBITS;
6915 childp2 = Fplist_put (childp2, QCstopbits, tem);
6917 /* Configure flowcontrol. */
6918 if (!NILP (Fplist_member (contact, QCflowcontrol)))
6919 tem = Fplist_get (contact, QCflowcontrol);
6920 else
6921 tem = Fplist_get (p->childp, QCflowcontrol);
6922 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
6923 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6924 dcb.fOutxCtsFlow = FALSE;
6925 dcb.fOutxDsrFlow = FALSE;
6926 dcb.fDtrControl = DTR_CONTROL_DISABLE;
6927 dcb.fDsrSensitivity = FALSE;
6928 dcb.fTXContinueOnXoff = FALSE;
6929 dcb.fOutX = FALSE;
6930 dcb.fInX = FALSE;
6931 dcb.fRtsControl = RTS_CONTROL_DISABLE;
6932 dcb.XonChar = 17; /* Control-Q */
6933 dcb.XoffChar = 19; /* Control-S */
6934 if (NILP (tem))
6936 /* Already configured. */
6938 else if (EQ (tem, Qhw))
6940 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
6941 dcb.fOutxCtsFlow = TRUE;
6943 else if (EQ (tem, Qsw))
6945 dcb.fOutX = TRUE;
6946 dcb.fInX = TRUE;
6948 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
6950 /* Activate configuration. */
6951 if (!SetCommState (hnd, &dcb))
6952 error ("SetCommState() failed");
6954 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
6955 pset_childp (p, childp2);
6958 #ifdef HAVE_GNUTLS
6960 ssize_t
6961 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
6963 int n, sc, err;
6964 SELECT_TYPE fdset;
6965 struct timeval timeout;
6966 struct Lisp_Process *process = (struct Lisp_Process *)p;
6967 int fd = process->infd;
6969 for (;;)
6971 n = sys_read (fd, (char*)buf, sz);
6973 if (n >= 0)
6974 return n;
6976 err = errno;
6978 if (err == EWOULDBLOCK)
6980 /* Set a small timeout. */
6981 timeout.tv_sec = 1;
6982 timeout.tv_usec = 0;
6983 FD_ZERO (&fdset);
6984 FD_SET ((int)fd, &fdset);
6986 /* Use select with the timeout to poll the selector. */
6987 sc = select (fd + 1, &fdset, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
6988 &timeout, NULL);
6990 if (sc > 0)
6991 continue; /* Try again. */
6993 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
6994 Also accept select return 0 as an indicator to EAGAIN. */
6995 if (sc == 0 || errno == EWOULDBLOCK)
6996 err = EAGAIN;
6997 else
6998 err = errno; /* Other errors are just passed on. */
7001 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
7003 return -1;
7007 ssize_t
7008 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
7010 struct Lisp_Process *process = (struct Lisp_Process *)p;
7011 int fd = process->outfd;
7012 ssize_t n = sys_write (fd, buf, sz);
7014 /* 0 or more bytes written means everything went fine. */
7015 if (n >= 0)
7016 return n;
7018 /* Negative bytes written means we got an error in errno.
7019 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7020 emacs_gnutls_transport_set_errno (process->gnutls_state,
7021 errno == EWOULDBLOCK ? EAGAIN : errno);
7023 return -1;
7025 #endif /* HAVE_GNUTLS */
7027 /* end of w32.c */