Support filesystem notification through inotify on GNU/Linux.
[emacs.git] / src / w32.c
blobe163a3a1ee309457a9af83ac1020b1ce02c0a4be
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 SIZE_T PeakWorkingSetSize;
107 SIZE_T WorkingSetSize;
108 SIZE_T QuotaPeakPagedPoolUsage;
109 SIZE_T QuotaPagedPoolUsage;
110 SIZE_T QuotaPeakNonPagedPoolUsage;
111 SIZE_T QuotaNonPagedPoolUsage;
112 SIZE_T PagefileUsage;
113 SIZE_T PeakPagefileUsage;
114 SIZE_T 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 and the
123 associated macros, except on ntifs.h, which cannot be included
124 because it triggers conflicts with other Windows API headers. So
125 we define it here by hand. */
127 typedef struct _REPARSE_DATA_BUFFER {
128 ULONG ReparseTag;
129 USHORT ReparseDataLength;
130 USHORT Reserved;
131 union {
132 struct {
133 USHORT SubstituteNameOffset;
134 USHORT SubstituteNameLength;
135 USHORT PrintNameOffset;
136 USHORT PrintNameLength;
137 ULONG Flags;
138 WCHAR PathBuffer[1];
139 } SymbolicLinkReparseBuffer;
140 struct {
141 USHORT SubstituteNameOffset;
142 USHORT SubstituteNameLength;
143 USHORT PrintNameOffset;
144 USHORT PrintNameLength;
145 WCHAR PathBuffer[1];
146 } MountPointReparseBuffer;
147 struct {
148 UCHAR DataBuffer[1];
149 } GenericReparseBuffer;
150 } DUMMYUNIONNAME;
151 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
153 #ifndef FILE_DEVICE_FILE_SYSTEM
154 #define FILE_DEVICE_FILE_SYSTEM 9
155 #endif
156 #ifndef METHOD_BUFFERED
157 #define METHOD_BUFFERED 0
158 #endif
159 #ifndef FILE_ANY_ACCESS
160 #define FILE_ANY_ACCESS 0x00000000
161 #endif
162 #ifndef CTL_CODE
163 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
164 #endif
165 #define FSCTL_GET_REPARSE_POINT \
166 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
167 #endif
169 /* TCP connection support. */
170 #include <sys/socket.h>
171 #undef socket
172 #undef bind
173 #undef connect
174 #undef htons
175 #undef ntohs
176 #undef inet_addr
177 #undef gethostname
178 #undef gethostbyname
179 #undef getservbyname
180 #undef getpeername
181 #undef shutdown
182 #undef setsockopt
183 #undef listen
184 #undef getsockname
185 #undef accept
186 #undef recvfrom
187 #undef sendto
189 #include "w32.h"
190 #include <dirent.h>
191 #include "w32common.h"
192 #include "w32heap.h"
193 #include "w32select.h"
194 #include "systime.h"
195 #include "dispextern.h" /* for xstrcasecmp */
196 #include "coding.h" /* for Vlocale_coding_system */
198 #include "careadlinkat.h"
199 #include "allocator.h"
201 /* For serial_configure and serial_open. */
202 #include "process.h"
204 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
205 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
207 Lisp_Object QCloaded_from;
209 void globals_of_w32 (void);
210 static DWORD get_rid (PSID);
211 static int is_symlink (const char *);
212 static char * chase_symlinks (const char *);
213 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
214 static int restore_privilege (TOKEN_PRIVILEGES *);
215 static BOOL WINAPI revert_to_self (void);
217 extern int sys_access (const char *, int);
218 extern void *e_malloc (size_t);
219 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
220 EMACS_TIME *, void *);
224 /* Initialization states.
226 WARNING: If you add any more such variables for additional APIs,
227 you MUST add initialization for them to globals_of_w32
228 below. This is because these variables might get set
229 to non-NULL values during dumping, but the dumped Emacs
230 cannot reuse those values, because it could be run on a
231 different version of the OS, where API addresses are
232 different. */
233 static BOOL g_b_init_is_windows_9x;
234 static BOOL g_b_init_open_process_token;
235 static BOOL g_b_init_get_token_information;
236 static BOOL g_b_init_lookup_account_sid;
237 static BOOL g_b_init_get_sid_sub_authority;
238 static BOOL g_b_init_get_sid_sub_authority_count;
239 static BOOL g_b_init_get_security_info;
240 static BOOL g_b_init_get_file_security;
241 static BOOL g_b_init_get_security_descriptor_owner;
242 static BOOL g_b_init_get_security_descriptor_group;
243 static BOOL g_b_init_is_valid_sid;
244 static BOOL g_b_init_create_toolhelp32_snapshot;
245 static BOOL g_b_init_process32_first;
246 static BOOL g_b_init_process32_next;
247 static BOOL g_b_init_open_thread_token;
248 static BOOL g_b_init_impersonate_self;
249 static BOOL g_b_init_revert_to_self;
250 static BOOL g_b_init_get_process_memory_info;
251 static BOOL g_b_init_get_process_working_set_size;
252 static BOOL g_b_init_global_memory_status;
253 static BOOL g_b_init_global_memory_status_ex;
254 static BOOL g_b_init_get_length_sid;
255 static BOOL g_b_init_equal_sid;
256 static BOOL g_b_init_copy_sid;
257 static BOOL g_b_init_get_native_system_info;
258 static BOOL g_b_init_get_system_times;
259 static BOOL g_b_init_create_symbolic_link;
262 BEGIN: Wrapper functions around OpenProcessToken
263 and other functions in advapi32.dll that are only
264 supported in Windows NT / 2k / XP
266 /* ** Function pointer typedefs ** */
267 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
268 HANDLE ProcessHandle,
269 DWORD DesiredAccess,
270 PHANDLE TokenHandle);
271 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
272 HANDLE TokenHandle,
273 TOKEN_INFORMATION_CLASS TokenInformationClass,
274 LPVOID TokenInformation,
275 DWORD TokenInformationLength,
276 PDWORD ReturnLength);
277 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
278 HANDLE process_handle,
279 LPFILETIME creation_time,
280 LPFILETIME exit_time,
281 LPFILETIME kernel_time,
282 LPFILETIME user_time);
284 GetProcessTimes_Proc get_process_times_fn = NULL;
286 #ifdef _UNICODE
287 const char * const LookupAccountSid_Name = "LookupAccountSidW";
288 const char * const GetFileSecurity_Name = "GetFileSecurityW";
289 #else
290 const char * const LookupAccountSid_Name = "LookupAccountSidA";
291 const char * const GetFileSecurity_Name = "GetFileSecurityA";
292 #endif
293 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
294 LPCTSTR lpSystemName,
295 PSID Sid,
296 LPTSTR Name,
297 LPDWORD cbName,
298 LPTSTR DomainName,
299 LPDWORD cbDomainName,
300 PSID_NAME_USE peUse);
301 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
302 PSID pSid,
303 DWORD n);
304 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
305 PSID pSid);
306 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
307 HANDLE handle,
308 SE_OBJECT_TYPE ObjectType,
309 SECURITY_INFORMATION SecurityInfo,
310 PSID *ppsidOwner,
311 PSID *ppsidGroup,
312 PACL *ppDacl,
313 PACL *ppSacl,
314 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
315 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
316 LPCTSTR lpFileName,
317 SECURITY_INFORMATION RequestedInformation,
318 PSECURITY_DESCRIPTOR pSecurityDescriptor,
319 DWORD nLength,
320 LPDWORD lpnLengthNeeded);
321 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
322 PSECURITY_DESCRIPTOR pSecurityDescriptor,
323 PSID *pOwner,
324 LPBOOL lpbOwnerDefaulted);
325 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
326 PSECURITY_DESCRIPTOR pSecurityDescriptor,
327 PSID *pGroup,
328 LPBOOL lpbGroupDefaulted);
329 typedef BOOL (WINAPI * IsValidSid_Proc) (
330 PSID sid);
331 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
332 DWORD dwFlags,
333 DWORD th32ProcessID);
334 typedef BOOL (WINAPI * Process32First_Proc) (
335 HANDLE hSnapshot,
336 LPPROCESSENTRY32 lppe);
337 typedef BOOL (WINAPI * Process32Next_Proc) (
338 HANDLE hSnapshot,
339 LPPROCESSENTRY32 lppe);
340 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
341 HANDLE ThreadHandle,
342 DWORD DesiredAccess,
343 BOOL OpenAsSelf,
344 PHANDLE TokenHandle);
345 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
346 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
347 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
348 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
349 HANDLE Process,
350 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
351 DWORD cb);
352 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
353 HANDLE hProcess,
354 PSIZE_T lpMinimumWorkingSetSize,
355 PSIZE_T lpMaximumWorkingSetSize);
356 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
357 LPMEMORYSTATUS lpBuffer);
358 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
359 LPMEMORY_STATUS_EX lpBuffer);
360 typedef BOOL (WINAPI * CopySid_Proc) (
361 DWORD nDestinationSidLength,
362 PSID pDestinationSid,
363 PSID pSourceSid);
364 typedef BOOL (WINAPI * EqualSid_Proc) (
365 PSID pSid1,
366 PSID pSid2);
367 typedef DWORD (WINAPI * GetLengthSid_Proc) (
368 PSID pSid);
369 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
370 LPSYSTEM_INFO lpSystemInfo);
371 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
372 LPFILETIME lpIdleTime,
373 LPFILETIME lpKernelTime,
374 LPFILETIME lpUserTime);
375 typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) (
376 LPTSTR lpSymlinkFileName,
377 LPTSTR lpTargetFileName,
378 DWORD dwFlags);
380 /* ** A utility function ** */
381 static BOOL
382 is_windows_9x (void)
384 static BOOL s_b_ret = 0;
385 OSVERSIONINFO os_ver;
386 if (g_b_init_is_windows_9x == 0)
388 g_b_init_is_windows_9x = 1;
389 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
390 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
391 if (GetVersionEx (&os_ver))
393 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
396 return s_b_ret;
399 static Lisp_Object ltime (ULONGLONG);
401 /* Get total user and system times for get-internal-run-time.
402 Returns a list of integers if the times are provided by the OS
403 (NT derivatives), otherwise it returns the result of current-time. */
404 Lisp_Object
405 w32_get_internal_run_time (void)
407 if (get_process_times_fn)
409 FILETIME create, exit, kernel, user;
410 HANDLE proc = GetCurrentProcess ();
411 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
413 LARGE_INTEGER user_int, kernel_int, total;
414 user_int.LowPart = user.dwLowDateTime;
415 user_int.HighPart = user.dwHighDateTime;
416 kernel_int.LowPart = kernel.dwLowDateTime;
417 kernel_int.HighPart = kernel.dwHighDateTime;
418 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
419 return ltime (total.QuadPart);
423 return Fcurrent_time ();
426 /* ** The wrapper functions ** */
428 static BOOL WINAPI
429 open_process_token (HANDLE ProcessHandle,
430 DWORD DesiredAccess,
431 PHANDLE TokenHandle)
433 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
434 HMODULE hm_advapi32 = NULL;
435 if (is_windows_9x () == TRUE)
437 return FALSE;
439 if (g_b_init_open_process_token == 0)
441 g_b_init_open_process_token = 1;
442 hm_advapi32 = LoadLibrary ("Advapi32.dll");
443 s_pfn_Open_Process_Token =
444 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
446 if (s_pfn_Open_Process_Token == NULL)
448 return FALSE;
450 return (
451 s_pfn_Open_Process_Token (
452 ProcessHandle,
453 DesiredAccess,
454 TokenHandle)
458 static BOOL WINAPI
459 get_token_information (HANDLE TokenHandle,
460 TOKEN_INFORMATION_CLASS TokenInformationClass,
461 LPVOID TokenInformation,
462 DWORD TokenInformationLength,
463 PDWORD ReturnLength)
465 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
466 HMODULE hm_advapi32 = NULL;
467 if (is_windows_9x () == TRUE)
469 return FALSE;
471 if (g_b_init_get_token_information == 0)
473 g_b_init_get_token_information = 1;
474 hm_advapi32 = LoadLibrary ("Advapi32.dll");
475 s_pfn_Get_Token_Information =
476 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
478 if (s_pfn_Get_Token_Information == NULL)
480 return FALSE;
482 return (
483 s_pfn_Get_Token_Information (
484 TokenHandle,
485 TokenInformationClass,
486 TokenInformation,
487 TokenInformationLength,
488 ReturnLength)
492 static BOOL WINAPI
493 lookup_account_sid (LPCTSTR lpSystemName,
494 PSID Sid,
495 LPTSTR Name,
496 LPDWORD cbName,
497 LPTSTR DomainName,
498 LPDWORD cbDomainName,
499 PSID_NAME_USE peUse)
501 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
502 HMODULE hm_advapi32 = NULL;
503 if (is_windows_9x () == TRUE)
505 return FALSE;
507 if (g_b_init_lookup_account_sid == 0)
509 g_b_init_lookup_account_sid = 1;
510 hm_advapi32 = LoadLibrary ("Advapi32.dll");
511 s_pfn_Lookup_Account_Sid =
512 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
514 if (s_pfn_Lookup_Account_Sid == NULL)
516 return FALSE;
518 return (
519 s_pfn_Lookup_Account_Sid (
520 lpSystemName,
521 Sid,
522 Name,
523 cbName,
524 DomainName,
525 cbDomainName,
526 peUse)
530 static PDWORD WINAPI
531 get_sid_sub_authority (PSID pSid, DWORD n)
533 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
534 static DWORD zero = 0U;
535 HMODULE hm_advapi32 = NULL;
536 if (is_windows_9x () == TRUE)
538 return &zero;
540 if (g_b_init_get_sid_sub_authority == 0)
542 g_b_init_get_sid_sub_authority = 1;
543 hm_advapi32 = LoadLibrary ("Advapi32.dll");
544 s_pfn_Get_Sid_Sub_Authority =
545 (GetSidSubAuthority_Proc) GetProcAddress (
546 hm_advapi32, "GetSidSubAuthority");
548 if (s_pfn_Get_Sid_Sub_Authority == NULL)
550 return &zero;
552 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
555 static PUCHAR WINAPI
556 get_sid_sub_authority_count (PSID pSid)
558 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
559 static UCHAR zero = 0U;
560 HMODULE hm_advapi32 = NULL;
561 if (is_windows_9x () == TRUE)
563 return &zero;
565 if (g_b_init_get_sid_sub_authority_count == 0)
567 g_b_init_get_sid_sub_authority_count = 1;
568 hm_advapi32 = LoadLibrary ("Advapi32.dll");
569 s_pfn_Get_Sid_Sub_Authority_Count =
570 (GetSidSubAuthorityCount_Proc) GetProcAddress (
571 hm_advapi32, "GetSidSubAuthorityCount");
573 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
575 return &zero;
577 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
580 static DWORD WINAPI
581 get_security_info (HANDLE handle,
582 SE_OBJECT_TYPE ObjectType,
583 SECURITY_INFORMATION SecurityInfo,
584 PSID *ppsidOwner,
585 PSID *ppsidGroup,
586 PACL *ppDacl,
587 PACL *ppSacl,
588 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
590 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
591 HMODULE hm_advapi32 = NULL;
592 if (is_windows_9x () == TRUE)
594 return FALSE;
596 if (g_b_init_get_security_info == 0)
598 g_b_init_get_security_info = 1;
599 hm_advapi32 = LoadLibrary ("Advapi32.dll");
600 s_pfn_Get_Security_Info =
601 (GetSecurityInfo_Proc) GetProcAddress (
602 hm_advapi32, "GetSecurityInfo");
604 if (s_pfn_Get_Security_Info == NULL)
606 return FALSE;
608 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
609 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
610 ppSecurityDescriptor));
613 static BOOL WINAPI
614 get_file_security (LPCTSTR lpFileName,
615 SECURITY_INFORMATION RequestedInformation,
616 PSECURITY_DESCRIPTOR pSecurityDescriptor,
617 DWORD nLength,
618 LPDWORD lpnLengthNeeded)
620 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
621 HMODULE hm_advapi32 = NULL;
622 if (is_windows_9x () == TRUE)
624 return FALSE;
626 if (g_b_init_get_file_security == 0)
628 g_b_init_get_file_security = 1;
629 hm_advapi32 = LoadLibrary ("Advapi32.dll");
630 s_pfn_Get_File_Security =
631 (GetFileSecurity_Proc) GetProcAddress (
632 hm_advapi32, GetFileSecurity_Name);
634 if (s_pfn_Get_File_Security == NULL)
636 return FALSE;
638 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
639 pSecurityDescriptor, nLength,
640 lpnLengthNeeded));
643 static BOOL WINAPI
644 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
645 PSID *pOwner,
646 LPBOOL lpbOwnerDefaulted)
648 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
649 HMODULE hm_advapi32 = NULL;
650 if (is_windows_9x () == TRUE)
652 return FALSE;
654 if (g_b_init_get_security_descriptor_owner == 0)
656 g_b_init_get_security_descriptor_owner = 1;
657 hm_advapi32 = LoadLibrary ("Advapi32.dll");
658 s_pfn_Get_Security_Descriptor_Owner =
659 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
660 hm_advapi32, "GetSecurityDescriptorOwner");
662 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
664 return FALSE;
666 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
667 lpbOwnerDefaulted));
670 static BOOL WINAPI
671 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
672 PSID *pGroup,
673 LPBOOL lpbGroupDefaulted)
675 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
676 HMODULE hm_advapi32 = NULL;
677 if (is_windows_9x () == TRUE)
679 return FALSE;
681 if (g_b_init_get_security_descriptor_group == 0)
683 g_b_init_get_security_descriptor_group = 1;
684 hm_advapi32 = LoadLibrary ("Advapi32.dll");
685 s_pfn_Get_Security_Descriptor_Group =
686 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
687 hm_advapi32, "GetSecurityDescriptorGroup");
689 if (s_pfn_Get_Security_Descriptor_Group == NULL)
691 return FALSE;
693 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
694 lpbGroupDefaulted));
697 static BOOL WINAPI
698 is_valid_sid (PSID sid)
700 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
701 HMODULE hm_advapi32 = NULL;
702 if (is_windows_9x () == TRUE)
704 return FALSE;
706 if (g_b_init_is_valid_sid == 0)
708 g_b_init_is_valid_sid = 1;
709 hm_advapi32 = LoadLibrary ("Advapi32.dll");
710 s_pfn_Is_Valid_Sid =
711 (IsValidSid_Proc) GetProcAddress (
712 hm_advapi32, "IsValidSid");
714 if (s_pfn_Is_Valid_Sid == NULL)
716 return FALSE;
718 return (s_pfn_Is_Valid_Sid (sid));
721 static BOOL WINAPI
722 equal_sid (PSID sid1, PSID sid2)
724 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
725 HMODULE hm_advapi32 = NULL;
726 if (is_windows_9x () == TRUE)
728 return FALSE;
730 if (g_b_init_equal_sid == 0)
732 g_b_init_equal_sid = 1;
733 hm_advapi32 = LoadLibrary ("Advapi32.dll");
734 s_pfn_Equal_Sid =
735 (EqualSid_Proc) GetProcAddress (
736 hm_advapi32, "EqualSid");
738 if (s_pfn_Equal_Sid == NULL)
740 return FALSE;
742 return (s_pfn_Equal_Sid (sid1, sid2));
745 static DWORD WINAPI
746 get_length_sid (PSID sid)
748 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
749 HMODULE hm_advapi32 = NULL;
750 if (is_windows_9x () == TRUE)
752 return 0;
754 if (g_b_init_get_length_sid == 0)
756 g_b_init_get_length_sid = 1;
757 hm_advapi32 = LoadLibrary ("Advapi32.dll");
758 s_pfn_Get_Length_Sid =
759 (GetLengthSid_Proc) GetProcAddress (
760 hm_advapi32, "GetLengthSid");
762 if (s_pfn_Get_Length_Sid == NULL)
764 return 0;
766 return (s_pfn_Get_Length_Sid (sid));
769 static BOOL WINAPI
770 copy_sid (DWORD destlen, PSID dest, PSID src)
772 static CopySid_Proc s_pfn_Copy_Sid = NULL;
773 HMODULE hm_advapi32 = NULL;
774 if (is_windows_9x () == TRUE)
776 return FALSE;
778 if (g_b_init_copy_sid == 0)
780 g_b_init_copy_sid = 1;
781 hm_advapi32 = LoadLibrary ("Advapi32.dll");
782 s_pfn_Copy_Sid =
783 (CopySid_Proc) GetProcAddress (
784 hm_advapi32, "CopySid");
786 if (s_pfn_Copy_Sid == NULL)
788 return FALSE;
790 return (s_pfn_Copy_Sid (destlen, dest, src));
794 END: Wrapper functions around OpenProcessToken
795 and other functions in advapi32.dll that are only
796 supported in Windows NT / 2k / XP
799 static void WINAPI
800 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
802 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
803 if (is_windows_9x () != TRUE)
805 if (g_b_init_get_native_system_info == 0)
807 g_b_init_get_native_system_info = 1;
808 s_pfn_Get_Native_System_Info =
809 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
810 "GetNativeSystemInfo");
812 if (s_pfn_Get_Native_System_Info != NULL)
813 s_pfn_Get_Native_System_Info (lpSystemInfo);
815 else
816 lpSystemInfo->dwNumberOfProcessors = -1;
819 static BOOL WINAPI
820 get_system_times (LPFILETIME lpIdleTime,
821 LPFILETIME lpKernelTime,
822 LPFILETIME lpUserTime)
824 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
825 if (is_windows_9x () == TRUE)
827 return FALSE;
829 if (g_b_init_get_system_times == 0)
831 g_b_init_get_system_times = 1;
832 s_pfn_Get_System_times =
833 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
834 "GetSystemTimes");
836 if (s_pfn_Get_System_times == NULL)
837 return FALSE;
838 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
841 static BOOLEAN WINAPI
842 create_symbolic_link (LPTSTR lpSymlinkFilename,
843 LPTSTR lpTargetFileName,
844 DWORD dwFlags)
846 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link = NULL;
847 BOOLEAN retval;
849 if (is_windows_9x () == TRUE)
851 errno = ENOSYS;
852 return 0;
854 if (g_b_init_create_symbolic_link == 0)
856 g_b_init_create_symbolic_link = 1;
857 #ifdef _UNICODE
858 s_pfn_Create_Symbolic_Link =
859 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
860 "CreateSymbolicLinkW");
861 #else
862 s_pfn_Create_Symbolic_Link =
863 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
864 "CreateSymbolicLinkA");
865 #endif
867 if (s_pfn_Create_Symbolic_Link == NULL)
869 errno = ENOSYS;
870 return 0;
873 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
874 dwFlags);
875 /* If we were denied creation of the symlink, try again after
876 enabling the SeCreateSymbolicLinkPrivilege for our process. */
877 if (!retval)
879 TOKEN_PRIVILEGES priv_current;
881 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE, &priv_current))
883 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
884 dwFlags);
885 restore_privilege (&priv_current);
886 revert_to_self ();
889 return retval;
893 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
894 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
896 This is called from alloc.c:valid_pointer_p. */
898 w32_valid_pointer_p (void *p, int size)
900 SIZE_T done;
901 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
903 if (h)
905 unsigned char *buf = alloca (size);
906 int retval = ReadProcessMemory (h, p, buf, size, &done);
908 CloseHandle (h);
909 return retval;
911 else
912 return -1;
915 static char startup_dir[MAXPATHLEN];
917 /* Get the current working directory. */
918 char *
919 getcwd (char *dir, int dirsize)
921 if (!dirsize)
923 errno = EINVAL;
924 return NULL;
926 if (dirsize <= strlen (startup_dir))
928 errno = ERANGE;
929 return NULL;
931 #if 0
932 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
933 return dir;
934 return NULL;
935 #else
936 /* Emacs doesn't actually change directory itself, it stays in the
937 same directory where it was started. */
938 strcpy (dir, startup_dir);
939 return dir;
940 #endif
943 /* Emulate getloadavg. */
945 struct load_sample {
946 time_t sample_time;
947 ULONGLONG idle;
948 ULONGLONG kernel;
949 ULONGLONG user;
952 /* Number of processors on this machine. */
953 static unsigned num_of_processors;
955 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
956 static struct load_sample samples[16*60];
957 static int first_idx = -1, last_idx = -1;
958 static int max_idx = sizeof (samples) / sizeof (samples[0]);
960 static int
961 buf_next (int from)
963 int next_idx = from + 1;
965 if (next_idx >= max_idx)
966 next_idx = 0;
968 return next_idx;
971 static int
972 buf_prev (int from)
974 int prev_idx = from - 1;
976 if (prev_idx < 0)
977 prev_idx = max_idx - 1;
979 return prev_idx;
982 static void
983 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
985 SYSTEM_INFO sysinfo;
986 FILETIME ft_idle, ft_user, ft_kernel;
988 /* Initialize the number of processors on this machine. */
989 if (num_of_processors <= 0)
991 get_native_system_info (&sysinfo);
992 num_of_processors = sysinfo.dwNumberOfProcessors;
993 if (num_of_processors <= 0)
995 GetSystemInfo (&sysinfo);
996 num_of_processors = sysinfo.dwNumberOfProcessors;
998 if (num_of_processors <= 0)
999 num_of_processors = 1;
1002 /* TODO: Take into account threads that are ready to run, by
1003 sampling the "\System\Processor Queue Length" performance
1004 counter. The code below accounts only for threads that are
1005 actually running. */
1007 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1009 ULARGE_INTEGER uidle, ukernel, uuser;
1011 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1012 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1013 memcpy (&uuser, &ft_user, sizeof (ft_user));
1014 *idle = uidle.QuadPart;
1015 *kernel = ukernel.QuadPart;
1016 *user = uuser.QuadPart;
1018 else
1020 *idle = 0;
1021 *kernel = 0;
1022 *user = 0;
1026 /* Produce the load average for a given time interval, using the
1027 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1028 1-minute, 5-minute, or 15-minute average, respectively. */
1029 static double
1030 getavg (int which)
1032 double retval = -1.0;
1033 double tdiff;
1034 int idx;
1035 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1036 time_t now = samples[last_idx].sample_time;
1038 if (first_idx != last_idx)
1040 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1042 tdiff = difftime (now, samples[idx].sample_time);
1043 if (tdiff >= span - 2*DBL_EPSILON*now)
1045 long double sys =
1046 samples[last_idx].kernel + samples[last_idx].user
1047 - (samples[idx].kernel + samples[idx].user);
1048 long double idl = samples[last_idx].idle - samples[idx].idle;
1050 retval = (1.0 - idl / sys) * num_of_processors;
1051 break;
1053 if (idx == first_idx)
1054 break;
1058 return retval;
1062 getloadavg (double loadavg[], int nelem)
1064 int elem;
1065 ULONGLONG idle, kernel, user;
1066 time_t now = time (NULL);
1068 /* Store another sample. We ignore samples that are less than 1 sec
1069 apart. */
1070 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
1072 sample_system_load (&idle, &kernel, &user);
1073 last_idx = buf_next (last_idx);
1074 samples[last_idx].sample_time = now;
1075 samples[last_idx].idle = idle;
1076 samples[last_idx].kernel = kernel;
1077 samples[last_idx].user = user;
1078 /* If the buffer has more that 15 min worth of samples, discard
1079 the old ones. */
1080 if (first_idx == -1)
1081 first_idx = last_idx;
1082 while (first_idx != last_idx
1083 && (difftime (now, samples[first_idx].sample_time)
1084 >= 15.0*60 + 2*DBL_EPSILON*now))
1085 first_idx = buf_next (first_idx);
1088 for (elem = 0; elem < nelem; elem++)
1090 double avg = getavg (elem);
1092 if (avg < 0)
1093 break;
1094 loadavg[elem] = avg;
1097 return elem;
1100 /* Emulate getpwuid, getpwnam and others. */
1102 #define PASSWD_FIELD_SIZE 256
1104 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1105 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1106 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1107 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
1108 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
1110 static struct passwd dflt_passwd =
1112 dflt_passwd_name,
1113 dflt_passwd_passwd,
1117 dflt_passwd_gecos,
1118 dflt_passwd_dir,
1119 dflt_passwd_shell,
1122 static char dflt_group_name[GNLEN+1];
1124 static struct group dflt_group =
1126 /* When group information is not available, we return this as the
1127 group for all files. */
1128 dflt_group_name,
1132 unsigned
1133 getuid (void)
1135 return dflt_passwd.pw_uid;
1138 unsigned
1139 geteuid (void)
1141 /* I could imagine arguing for checking to see whether the user is
1142 in the Administrators group and returning a UID of 0 for that
1143 case, but I don't know how wise that would be in the long run. */
1144 return getuid ();
1147 unsigned
1148 getgid (void)
1150 return dflt_passwd.pw_gid;
1153 unsigned
1154 getegid (void)
1156 return getgid ();
1159 struct passwd *
1160 getpwuid (unsigned uid)
1162 if (uid == dflt_passwd.pw_uid)
1163 return &dflt_passwd;
1164 return NULL;
1167 struct group *
1168 getgrgid (gid_t gid)
1170 return &dflt_group;
1173 struct passwd *
1174 getpwnam (char *name)
1176 struct passwd *pw;
1178 pw = getpwuid (getuid ());
1179 if (!pw)
1180 return pw;
1182 if (xstrcasecmp (name, pw->pw_name))
1183 return NULL;
1185 return pw;
1188 static void
1189 init_user_info (void)
1191 /* Find the user's real name by opening the process token and
1192 looking up the name associated with the user-sid in that token.
1194 Use the relative portion of the identifier authority value from
1195 the user-sid as the user id value (same for group id using the
1196 primary group sid from the process token). */
1198 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1199 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1200 DWORD glength = sizeof (gname);
1201 HANDLE token = NULL;
1202 SID_NAME_USE user_type;
1203 unsigned char *buf = NULL;
1204 DWORD blen = 0;
1205 TOKEN_USER user_token;
1206 TOKEN_PRIMARY_GROUP group_token;
1207 BOOL result;
1209 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1210 if (result)
1212 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1213 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1215 buf = xmalloc (blen);
1216 result = get_token_information (token, TokenUser,
1217 (LPVOID)buf, blen, &needed);
1218 if (result)
1220 memcpy (&user_token, buf, sizeof (user_token));
1221 result = lookup_account_sid (NULL, user_token.User.Sid,
1222 uname, &ulength,
1223 domain, &dlength, &user_type);
1226 else
1227 result = FALSE;
1229 if (result)
1231 strcpy (dflt_passwd.pw_name, uname);
1232 /* Determine a reasonable uid value. */
1233 if (xstrcasecmp ("administrator", uname) == 0)
1235 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1236 dflt_passwd.pw_gid = 513; /* well-known None gid */
1238 else
1240 /* Use the last sub-authority value of the RID, the relative
1241 portion of the SID, as user/group ID. */
1242 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1244 /* Get group id and name. */
1245 result = get_token_information (token, TokenPrimaryGroup,
1246 (LPVOID)buf, blen, &needed);
1247 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1249 buf = xrealloc (buf, blen = needed);
1250 result = get_token_information (token, TokenPrimaryGroup,
1251 (LPVOID)buf, blen, &needed);
1253 if (result)
1255 memcpy (&group_token, buf, sizeof (group_token));
1256 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1257 dlength = sizeof (domain);
1258 /* If we can get at the real Primary Group name, use that.
1259 Otherwise, the default group name was already set to
1260 "None" in globals_of_w32. */
1261 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1262 gname, &glength, NULL, &dlength,
1263 &user_type))
1264 strcpy (dflt_group_name, gname);
1266 else
1267 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1270 /* If security calls are not supported (presumably because we
1271 are running under Windows 9X), fallback to this: */
1272 else if (GetUserName (uname, &ulength))
1274 strcpy (dflt_passwd.pw_name, uname);
1275 if (xstrcasecmp ("administrator", uname) == 0)
1276 dflt_passwd.pw_uid = 0;
1277 else
1278 dflt_passwd.pw_uid = 123;
1279 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1281 else
1283 strcpy (dflt_passwd.pw_name, "unknown");
1284 dflt_passwd.pw_uid = 123;
1285 dflt_passwd.pw_gid = 123;
1287 dflt_group.gr_gid = dflt_passwd.pw_gid;
1289 /* Ensure HOME and SHELL are defined. */
1290 if (getenv ("HOME") == NULL)
1291 emacs_abort ();
1292 if (getenv ("SHELL") == NULL)
1293 emacs_abort ();
1295 /* Set dir and shell from environment variables. */
1296 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1297 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1299 xfree (buf);
1300 if (token)
1301 CloseHandle (token);
1305 random (void)
1307 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1308 return ((rand () << 15) | rand ());
1311 void
1312 srandom (int seed)
1314 srand (seed);
1318 /* Normalize filename by converting all path separators to
1319 the specified separator. Also conditionally convert upper
1320 case path name components to lower case. */
1322 static void
1323 normalize_filename (register char *fp, char path_sep)
1325 char sep;
1326 char *elem;
1328 /* Always lower-case drive letters a-z, even if the filesystem
1329 preserves case in filenames.
1330 This is so filenames can be compared by string comparison
1331 functions that are case-sensitive. Even case-preserving filesystems
1332 do not distinguish case in drive letters. */
1333 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
1335 *fp += 'a' - 'A';
1336 fp += 2;
1339 if (NILP (Vw32_downcase_file_names))
1341 while (*fp)
1343 if (*fp == '/' || *fp == '\\')
1344 *fp = path_sep;
1345 fp++;
1347 return;
1350 sep = path_sep; /* convert to this path separator */
1351 elem = fp; /* start of current path element */
1353 do {
1354 if (*fp >= 'a' && *fp <= 'z')
1355 elem = 0; /* don't convert this element */
1357 if (*fp == 0 || *fp == ':')
1359 sep = *fp; /* restore current separator (or 0) */
1360 *fp = '/'; /* after conversion of this element */
1363 if (*fp == '/' || *fp == '\\')
1365 if (elem && elem != fp)
1367 *fp = 0; /* temporary end of string */
1368 _strlwr (elem); /* while we convert to lower case */
1370 *fp = sep; /* convert (or restore) path separator */
1371 elem = fp + 1; /* next element starts after separator */
1372 sep = path_sep;
1374 } while (*fp++);
1377 /* Destructively turn backslashes into slashes. */
1378 void
1379 dostounix_filename (register char *p)
1381 normalize_filename (p, '/');
1384 /* Destructively turn slashes into backslashes. */
1385 void
1386 unixtodos_filename (register char *p)
1388 normalize_filename (p, '\\');
1391 /* Remove all CR's that are followed by a LF.
1392 (From msdos.c...probably should figure out a way to share it,
1393 although this code isn't going to ever change.) */
1394 static int
1395 crlf_to_lf (register int n, register unsigned char *buf)
1397 unsigned char *np = buf;
1398 unsigned char *startp = buf;
1399 unsigned char *endp = buf + n;
1401 if (n == 0)
1402 return n;
1403 while (buf < endp - 1)
1405 if (*buf == 0x0d)
1407 if (*(++buf) != 0x0a)
1408 *np++ = 0x0d;
1410 else
1411 *np++ = *buf++;
1413 if (buf < endp)
1414 *np++ = *buf++;
1415 return np - startp;
1418 /* Parse the root part of file name, if present. Return length and
1419 optionally store pointer to char after root. */
1420 static int
1421 parse_root (char * name, char ** pPath)
1423 char * start = name;
1425 if (name == NULL)
1426 return 0;
1428 /* find the root name of the volume if given */
1429 if (isalpha (name[0]) && name[1] == ':')
1431 /* skip past drive specifier */
1432 name += 2;
1433 if (IS_DIRECTORY_SEP (name[0]))
1434 name++;
1436 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1438 int slashes = 2;
1439 name += 2;
1442 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1443 break;
1444 name++;
1446 while ( *name );
1447 if (IS_DIRECTORY_SEP (name[0]))
1448 name++;
1451 if (pPath)
1452 *pPath = name;
1454 return name - start;
1457 /* Get long base name for name; name is assumed to be absolute. */
1458 static int
1459 get_long_basename (char * name, char * buf, int size)
1461 WIN32_FIND_DATA find_data;
1462 HANDLE dir_handle;
1463 int len = 0;
1465 /* must be valid filename, no wild cards or other invalid characters */
1466 if (_mbspbrk (name, "*?|<>\""))
1467 return 0;
1469 dir_handle = FindFirstFile (name, &find_data);
1470 if (dir_handle != INVALID_HANDLE_VALUE)
1472 if ((len = strlen (find_data.cFileName)) < size)
1473 memcpy (buf, find_data.cFileName, len + 1);
1474 else
1475 len = 0;
1476 FindClose (dir_handle);
1478 return len;
1481 /* Get long name for file, if possible (assumed to be absolute). */
1482 BOOL
1483 w32_get_long_filename (char * name, char * buf, int size)
1485 char * o = buf;
1486 char * p;
1487 char * q;
1488 char full[ MAX_PATH ];
1489 int len;
1491 len = strlen (name);
1492 if (len >= MAX_PATH)
1493 return FALSE;
1495 /* Use local copy for destructive modification. */
1496 memcpy (full, name, len+1);
1497 unixtodos_filename (full);
1499 /* Copy root part verbatim. */
1500 len = parse_root (full, &p);
1501 memcpy (o, full, len);
1502 o += len;
1503 *o = '\0';
1504 size -= len;
1506 while (p != NULL && *p)
1508 q = p;
1509 p = strchr (q, '\\');
1510 if (p) *p = '\0';
1511 len = get_long_basename (full, o, size);
1512 if (len > 0)
1514 o += len;
1515 size -= len;
1516 if (p != NULL)
1518 *p++ = '\\';
1519 if (size < 2)
1520 return FALSE;
1521 *o++ = '\\';
1522 size--;
1523 *o = '\0';
1526 else
1527 return FALSE;
1530 return TRUE;
1533 static int
1534 is_unc_volume (const char *filename)
1536 const char *ptr = filename;
1538 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1539 return 0;
1541 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1542 return 0;
1544 return 1;
1547 /* Emulate the Posix unsetenv. */
1549 unsetenv (const char *name)
1551 char *var;
1552 size_t name_len;
1553 int retval;
1555 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
1557 errno = EINVAL;
1558 return -1;
1560 name_len = strlen (name);
1561 /* MS docs says an environment variable cannot be longer than 32K. */
1562 if (name_len > 32767)
1564 errno = ENOMEM;
1565 return 0;
1567 /* It is safe to use 'alloca' with 32K size, since the stack is at
1568 least 2MB, and we set it to 8MB in the link command line. */
1569 var = alloca (name_len + 2);
1570 var[name_len++] = '=';
1571 var[name_len] = '\0';
1572 return _putenv (var);
1575 /* MS _putenv doesn't support removing a variable when the argument
1576 does not include the '=' character, so we fix that here. */
1578 sys_putenv (char *str)
1580 const char *const name_end = strchr (str, '=');
1582 if (name_end == NULL)
1584 /* Remove the variable from the environment. */
1585 return unsetenv (str);
1588 return _putenv (str);
1591 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1593 LPBYTE
1594 w32_get_resource (char *key, LPDWORD lpdwtype)
1596 LPBYTE lpvalue;
1597 HKEY hrootkey = NULL;
1598 DWORD cbData;
1600 /* Check both the current user and the local machine to see if
1601 we have any resources. */
1603 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1605 lpvalue = NULL;
1607 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1608 && (lpvalue = xmalloc (cbData)) != NULL
1609 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1611 RegCloseKey (hrootkey);
1612 return (lpvalue);
1615 xfree (lpvalue);
1617 RegCloseKey (hrootkey);
1620 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1622 lpvalue = NULL;
1624 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1625 && (lpvalue = xmalloc (cbData)) != NULL
1626 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1628 RegCloseKey (hrootkey);
1629 return (lpvalue);
1632 xfree (lpvalue);
1634 RegCloseKey (hrootkey);
1637 return (NULL);
1640 char *get_emacs_configuration (void);
1642 void
1643 init_environment (char ** argv)
1645 static const char * const tempdirs[] = {
1646 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1649 int i;
1651 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1653 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1654 temporary files and assume "/tmp" if $TMPDIR is unset, which
1655 will break on DOS/Windows. Refuse to work if we cannot find
1656 a directory, not even "c:/", usable for that purpose. */
1657 for (i = 0; i < imax ; i++)
1659 const char *tmp = tempdirs[i];
1661 if (*tmp == '$')
1662 tmp = getenv (tmp + 1);
1663 /* Note that `access' can lie to us if the directory resides on a
1664 read-only filesystem, like CD-ROM or a write-protected floppy.
1665 The only way to be really sure is to actually create a file and
1666 see if it succeeds. But I think that's too much to ask. */
1668 /* MSVCRT's _access crashes with D_OK. */
1669 if (tmp && faccessat (AT_FDCWD, tmp, D_OK, AT_EACCESS) == 0)
1671 char * var = alloca (strlen (tmp) + 8);
1672 sprintf (var, "TMPDIR=%s", tmp);
1673 _putenv (strdup (var));
1674 break;
1677 if (i >= imax)
1678 cmd_error_internal
1679 (Fcons (Qerror,
1680 Fcons (build_string ("no usable temporary directories found!!"),
1681 Qnil)),
1682 "While setting TMPDIR: ");
1684 /* Check for environment variables and use registry settings if they
1685 don't exist. Fallback on default values where applicable. */
1687 int i;
1688 LPBYTE lpval;
1689 DWORD dwType;
1690 char locale_name[32];
1691 char default_home[MAX_PATH];
1692 int appdata = 0;
1694 static const struct env_entry
1696 char * name;
1697 char * def_value;
1698 } dflt_envvars[] =
1700 /* If the default value is NULL, we will use the value from the
1701 outside environment or the Registry, but will not push the
1702 variable into the Emacs environment if it is defined neither
1703 in the Registry nor in the outside environment. */
1704 {"HOME", "C:/"},
1705 {"PRELOAD_WINSOCK", NULL},
1706 {"emacs_dir", "C:/emacs"},
1707 {"EMACSLOADPATH", NULL},
1708 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1709 {"EMACSDATA", NULL},
1710 {"EMACSPATH", NULL},
1711 {"INFOPATH", NULL},
1712 {"EMACSDOC", NULL},
1713 {"TERM", "cmd"},
1714 {"LANG", NULL},
1717 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1719 /* We need to copy dflt_envvars[] and work on the copy because we
1720 don't want the dumped Emacs to inherit the values of
1721 environment variables we saw during dumping (which could be on
1722 a different system). The defaults above must be left intact. */
1723 struct env_entry env_vars[N_ENV_VARS];
1725 for (i = 0; i < N_ENV_VARS; i++)
1726 env_vars[i] = dflt_envvars[i];
1728 /* For backwards compatibility, check if a .emacs file exists in C:/
1729 If not, then we can try to default to the appdata directory under the
1730 user's profile, which is more likely to be writable. */
1731 if (!check_existing ("C:/.emacs"))
1733 HRESULT profile_result;
1734 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1735 of Windows 95 and NT4 that have not been updated to include
1736 MSIE 5. */
1737 ShGetFolderPath_fn get_folder_path;
1738 get_folder_path = (ShGetFolderPath_fn)
1739 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1741 if (get_folder_path != NULL)
1743 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1744 0, default_home);
1746 /* If we can't get the appdata dir, revert to old behavior. */
1747 if (profile_result == S_OK)
1749 env_vars[0].def_value = default_home;
1750 appdata = 1;
1755 /* Get default locale info and use it for LANG. */
1756 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1757 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1758 locale_name, sizeof (locale_name)))
1760 for (i = 0; i < N_ENV_VARS; i++)
1762 if (strcmp (env_vars[i].name, "LANG") == 0)
1764 env_vars[i].def_value = locale_name;
1765 break;
1770 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1772 /* Treat emacs_dir specially: set it unconditionally based on our
1773 location. */
1775 char *p;
1776 char modname[MAX_PATH];
1778 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1779 emacs_abort ();
1780 if ((p = strrchr (modname, '\\')) == NULL)
1781 emacs_abort ();
1782 *p = 0;
1784 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1786 char buf[SET_ENV_BUF_SIZE];
1788 *p = 0;
1789 for (p = modname; *p; p++)
1790 if (*p == '\\') *p = '/';
1792 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1793 _putenv (strdup (buf));
1795 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1797 /* FIXME: should use substring of get_emacs_configuration ().
1798 But I don't think the Windows build supports alpha, mips etc
1799 anymore, so have taken the easy option for now. */
1800 else if (p && (xstrcasecmp (p, "\\i386") == 0
1801 || xstrcasecmp (p, "\\AMD64") == 0))
1803 *p = 0;
1804 p = strrchr (modname, '\\');
1805 if (p != NULL)
1807 *p = 0;
1808 p = strrchr (modname, '\\');
1809 if (p && xstrcasecmp (p, "\\src") == 0)
1811 char buf[SET_ENV_BUF_SIZE];
1813 *p = 0;
1814 for (p = modname; *p; p++)
1815 if (*p == '\\') *p = '/';
1817 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1818 _putenv (strdup (buf));
1824 for (i = 0; i < N_ENV_VARS; i++)
1826 if (!getenv (env_vars[i].name))
1828 int dont_free = 0;
1830 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1831 /* Also ignore empty environment variables. */
1832 || *lpval == 0)
1834 xfree (lpval);
1835 lpval = env_vars[i].def_value;
1836 dwType = REG_EXPAND_SZ;
1837 dont_free = 1;
1838 if (!strcmp (env_vars[i].name, "HOME") && !appdata)
1839 Vdelayed_warnings_list
1840 = Fcons (listn (CONSTYPE_HEAP, 2,
1841 intern ("initialization"),
1842 build_string ("Setting HOME to C:\\ by default is deprecated")),
1843 Vdelayed_warnings_list);
1846 if (lpval)
1848 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1850 if (dwType == REG_EXPAND_SZ)
1851 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
1852 else if (dwType == REG_SZ)
1853 strcpy (buf1, lpval);
1854 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1856 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
1857 buf1);
1858 _putenv (strdup (buf2));
1861 if (!dont_free)
1862 xfree (lpval);
1868 /* Rebuild system configuration to reflect invoking system. */
1869 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1871 /* Another special case: on NT, the PATH variable is actually named
1872 "Path" although cmd.exe (perhaps NT itself) arranges for
1873 environment variable lookup and setting to be case insensitive.
1874 However, Emacs assumes a fully case sensitive environment, so we
1875 need to change "Path" to "PATH" to match the expectations of
1876 various elisp packages. We do this by the sneaky method of
1877 modifying the string in the C runtime environ entry.
1879 The same applies to COMSPEC. */
1881 char ** envp;
1883 for (envp = environ; *envp; envp++)
1884 if (_strnicmp (*envp, "PATH=", 5) == 0)
1885 memcpy (*envp, "PATH=", 5);
1886 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1887 memcpy (*envp, "COMSPEC=", 8);
1890 /* Remember the initial working directory for getcwd. */
1891 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
1892 Does it matter anywhere in Emacs? */
1893 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1894 emacs_abort ();
1897 static char modname[MAX_PATH];
1899 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1900 emacs_abort ();
1901 argv[0] = modname;
1904 /* Determine if there is a middle mouse button, to allow parse_button
1905 to decide whether right mouse events should be mouse-2 or
1906 mouse-3. */
1907 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1909 init_user_info ();
1912 /* Called from expand-file-name when default-directory is not a string. */
1914 char *
1915 emacs_root_dir (void)
1917 static char root_dir[FILENAME_MAX];
1918 const char *p;
1920 p = getenv ("emacs_dir");
1921 if (p == NULL)
1922 emacs_abort ();
1923 strcpy (root_dir, p);
1924 root_dir[parse_root (root_dir, NULL)] = '\0';
1925 dostounix_filename (root_dir);
1926 return root_dir;
1929 /* We don't have scripts to automatically determine the system configuration
1930 for Emacs before it's compiled, and we don't want to have to make the
1931 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1932 routine. */
1934 char *
1935 get_emacs_configuration (void)
1937 char *arch, *oem, *os;
1938 int build_num;
1939 static char configuration_buffer[32];
1941 /* Determine the processor type. */
1942 switch (get_processor_type ())
1945 #ifdef PROCESSOR_INTEL_386
1946 case PROCESSOR_INTEL_386:
1947 case PROCESSOR_INTEL_486:
1948 case PROCESSOR_INTEL_PENTIUM:
1949 #ifdef _WIN64
1950 arch = "amd64";
1951 #else
1952 arch = "i386";
1953 #endif
1954 break;
1955 #endif
1956 #ifdef PROCESSOR_AMD_X8664
1957 case PROCESSOR_AMD_X8664:
1958 arch = "amd64";
1959 break;
1960 #endif
1962 #ifdef PROCESSOR_MIPS_R2000
1963 case PROCESSOR_MIPS_R2000:
1964 case PROCESSOR_MIPS_R3000:
1965 case PROCESSOR_MIPS_R4000:
1966 arch = "mips";
1967 break;
1968 #endif
1970 #ifdef PROCESSOR_ALPHA_21064
1971 case PROCESSOR_ALPHA_21064:
1972 arch = "alpha";
1973 break;
1974 #endif
1976 default:
1977 arch = "unknown";
1978 break;
1981 /* Use the OEM field to reflect the compiler/library combination. */
1982 #ifdef _MSC_VER
1983 #define COMPILER_NAME "msvc"
1984 #else
1985 #ifdef __GNUC__
1986 #define COMPILER_NAME "mingw"
1987 #else
1988 #define COMPILER_NAME "unknown"
1989 #endif
1990 #endif
1991 oem = COMPILER_NAME;
1993 switch (osinfo_cache.dwPlatformId) {
1994 case VER_PLATFORM_WIN32_NT:
1995 os = "nt";
1996 build_num = osinfo_cache.dwBuildNumber;
1997 break;
1998 case VER_PLATFORM_WIN32_WINDOWS:
1999 if (osinfo_cache.dwMinorVersion == 0) {
2000 os = "windows95";
2001 } else {
2002 os = "windows98";
2004 build_num = LOWORD (osinfo_cache.dwBuildNumber);
2005 break;
2006 case VER_PLATFORM_WIN32s:
2007 /* Not supported, should not happen. */
2008 os = "windows32s";
2009 build_num = LOWORD (osinfo_cache.dwBuildNumber);
2010 break;
2011 default:
2012 os = "unknown";
2013 build_num = 0;
2014 break;
2017 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
2018 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
2019 get_w32_major_version (), get_w32_minor_version (), build_num);
2020 } else {
2021 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
2024 return configuration_buffer;
2027 char *
2028 get_emacs_configuration_options (void)
2030 static char *options_buffer;
2031 char cv[32]; /* Enough for COMPILER_VERSION. */
2032 char *options[] = {
2033 cv, /* To be filled later. */
2034 #ifdef EMACSDEBUG
2035 " --no-opt",
2036 #endif
2037 #ifdef ENABLE_CHECKING
2038 " --enable-checking",
2039 #endif
2040 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
2041 with a starting space to save work here. */
2042 #ifdef USER_CFLAGS
2043 " --cflags", USER_CFLAGS,
2044 #endif
2045 #ifdef USER_LDFLAGS
2046 " --ldflags", USER_LDFLAGS,
2047 #endif
2048 NULL
2050 size_t size = 0;
2051 int i;
2053 /* Work out the effective configure options for this build. */
2054 #ifdef _MSC_VER
2055 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
2056 #else
2057 #ifdef __GNUC__
2058 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
2059 #else
2060 #define COMPILER_VERSION ""
2061 #endif
2062 #endif
2064 if (_snprintf (cv, sizeof (cv) - 1, COMPILER_VERSION) < 0)
2065 return "Error: not enough space for compiler version";
2066 cv[sizeof (cv) - 1] = '\0';
2068 for (i = 0; options[i]; i++)
2069 size += strlen (options[i]);
2071 options_buffer = xmalloc (size + 1);
2072 options_buffer[0] = '\0';
2074 for (i = 0; options[i]; i++)
2075 strcat (options_buffer, options[i]);
2077 return options_buffer;
2081 #include <sys/timeb.h>
2083 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2084 void
2085 gettimeofday (struct timeval *tv, struct timezone *tz)
2087 struct _timeb tb;
2088 _ftime (&tb);
2090 tv->tv_sec = tb.time;
2091 tv->tv_usec = tb.millitm * 1000L;
2092 /* Implementation note: _ftime sometimes doesn't update the dstflag
2093 according to the new timezone when the system timezone is
2094 changed. We could fix that by using GetSystemTime and
2095 GetTimeZoneInformation, but that doesn't seem necessary, since
2096 Emacs always calls gettimeofday with the 2nd argument NULL (see
2097 current_emacs_time). */
2098 if (tz)
2100 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2101 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2105 /* Emulate fdutimens. */
2107 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2108 TIMESPEC[0] and TIMESPEC[1], respectively.
2109 FD must be either negative -- in which case it is ignored --
2110 or a file descriptor that is open on FILE.
2111 If FD is nonnegative, then FILE can be NULL, which means
2112 use just futimes instead of utimes.
2113 If TIMESPEC is null, FAIL.
2114 Return 0 on success, -1 (setting errno) on failure. */
2117 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2119 struct _utimbuf ut;
2121 if (!timespec)
2123 errno = ENOSYS;
2124 return -1;
2126 if (fd < 0 && !file)
2128 errno = EBADF;
2129 return -1;
2131 ut.actime = timespec[0].tv_sec;
2132 ut.modtime = timespec[1].tv_sec;
2133 if (fd >= 0)
2134 return _futime (fd, &ut);
2135 else
2136 return _utime (file, &ut);
2140 /* ------------------------------------------------------------------------- */
2141 /* IO support and wrapper functions for the Windows API. */
2142 /* ------------------------------------------------------------------------- */
2144 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2145 on network directories, so we handle that case here.
2146 (Ulrich Leodolter, 1/11/95). */
2147 char *
2148 sys_ctime (const time_t *t)
2150 char *str = (char *) ctime (t);
2151 return (str ? str : "Sun Jan 01 00:00:00 1970");
2154 /* Emulate sleep...we could have done this with a define, but that
2155 would necessitate including windows.h in the files that used it.
2156 This is much easier. */
2157 void
2158 sys_sleep (int seconds)
2160 Sleep (seconds * 1000);
2163 /* Internal MSVC functions for low-level descriptor munging */
2164 extern int __cdecl _set_osfhnd (int fd, long h);
2165 extern int __cdecl _free_osfhnd (int fd);
2167 /* parallel array of private info on file handles */
2168 filedesc fd_info [ MAXDESC ];
2170 typedef struct volume_info_data {
2171 struct volume_info_data * next;
2173 /* time when info was obtained */
2174 DWORD timestamp;
2176 /* actual volume info */
2177 char * root_dir;
2178 DWORD serialnum;
2179 DWORD maxcomp;
2180 DWORD flags;
2181 char * name;
2182 char * type;
2183 } volume_info_data;
2185 /* Global referenced by various functions. */
2186 static volume_info_data volume_info;
2188 /* Vector to indicate which drives are local and fixed (for which cached
2189 data never expires). */
2190 static BOOL fixed_drives[26];
2192 /* Consider cached volume information to be stale if older than 10s,
2193 at least for non-local drives. Info for fixed drives is never stale. */
2194 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2195 #define VOLINFO_STILL_VALID( root_dir, info ) \
2196 ( ( isalpha (root_dir[0]) && \
2197 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2198 || GetTickCount () - info->timestamp < 10000 )
2200 /* Cache support functions. */
2202 /* Simple linked list with linear search is sufficient. */
2203 static volume_info_data *volume_cache = NULL;
2205 static volume_info_data *
2206 lookup_volume_info (char * root_dir)
2208 volume_info_data * info;
2210 for (info = volume_cache; info; info = info->next)
2211 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2212 break;
2213 return info;
2216 static void
2217 add_volume_info (char * root_dir, volume_info_data * info)
2219 info->root_dir = xstrdup (root_dir);
2220 info->next = volume_cache;
2221 volume_cache = info;
2225 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2226 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2227 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2228 static volume_info_data *
2229 GetCachedVolumeInformation (char * root_dir)
2231 volume_info_data * info;
2232 char default_root[ MAX_PATH ];
2234 /* NULL for root_dir means use root from current directory. */
2235 if (root_dir == NULL)
2237 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
2238 return NULL;
2239 parse_root (default_root, &root_dir);
2240 *root_dir = 0;
2241 root_dir = default_root;
2244 /* Local fixed drives can be cached permanently. Removable drives
2245 cannot be cached permanently, since the volume name and serial
2246 number (if nothing else) can change. Remote drives should be
2247 treated as if they are removable, since there is no sure way to
2248 tell whether they are or not. Also, the UNC association of drive
2249 letters mapped to remote volumes can be changed at any time (even
2250 by other processes) without notice.
2252 As a compromise, so we can benefit from caching info for remote
2253 volumes, we use a simple expiry mechanism to invalidate cache
2254 entries that are more than ten seconds old. */
2256 #if 0
2257 /* No point doing this, because WNetGetConnection is even slower than
2258 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2259 GetDriveType is about the only call of this type which does not
2260 involve network access, and so is extremely quick). */
2262 /* Map drive letter to UNC if remote. */
2263 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2265 char remote_name[ 256 ];
2266 char drive[3] = { root_dir[0], ':' };
2268 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2269 == NO_ERROR)
2270 /* do something */ ;
2272 #endif
2274 info = lookup_volume_info (root_dir);
2276 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2278 char name[ 256 ];
2279 DWORD serialnum;
2280 DWORD maxcomp;
2281 DWORD flags;
2282 char type[ 256 ];
2284 /* Info is not cached, or is stale. */
2285 if (!GetVolumeInformation (root_dir,
2286 name, sizeof (name),
2287 &serialnum,
2288 &maxcomp,
2289 &flags,
2290 type, sizeof (type)))
2291 return NULL;
2293 /* Cache the volume information for future use, overwriting existing
2294 entry if present. */
2295 if (info == NULL)
2297 info = xmalloc (sizeof (volume_info_data));
2298 add_volume_info (root_dir, info);
2300 else
2302 xfree (info->name);
2303 xfree (info->type);
2306 info->name = xstrdup (name);
2307 info->serialnum = serialnum;
2308 info->maxcomp = maxcomp;
2309 info->flags = flags;
2310 info->type = xstrdup (type);
2311 info->timestamp = GetTickCount ();
2314 return info;
2317 /* Get information on the volume where NAME is held; set path pointer to
2318 start of pathname in NAME (past UNC header\volume header if present),
2319 if pPath is non-NULL.
2321 Note: if NAME includes symlinks, the information is for the volume
2322 of the symlink, not of its target. That's because, even though
2323 GetVolumeInformation returns information about the symlink target
2324 of its argument, we only pass the root directory to
2325 GetVolumeInformation, not the full NAME. */
2326 static int
2327 get_volume_info (const char * name, const char ** pPath)
2329 char temp[MAX_PATH];
2330 char *rootname = NULL; /* default to current volume */
2331 volume_info_data * info;
2333 if (name == NULL)
2334 return FALSE;
2336 /* Find the root name of the volume if given. */
2337 if (isalpha (name[0]) && name[1] == ':')
2339 rootname = temp;
2340 temp[0] = *name++;
2341 temp[1] = *name++;
2342 temp[2] = '\\';
2343 temp[3] = 0;
2345 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2347 char *str = temp;
2348 int slashes = 4;
2349 rootname = temp;
2352 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2353 break;
2354 *str++ = *name++;
2356 while ( *name );
2358 *str++ = '\\';
2359 *str = 0;
2362 if (pPath)
2363 *pPath = name;
2365 info = GetCachedVolumeInformation (rootname);
2366 if (info != NULL)
2368 /* Set global referenced by other functions. */
2369 volume_info = *info;
2370 return TRUE;
2372 return FALSE;
2375 /* Determine if volume is FAT format (ie. only supports short 8.3
2376 names); also set path pointer to start of pathname in name, if
2377 pPath is non-NULL. */
2378 static int
2379 is_fat_volume (const char * name, const char ** pPath)
2381 if (get_volume_info (name, pPath))
2382 return (volume_info.maxcomp == 12);
2383 return FALSE;
2386 /* Map filename to a valid 8.3 name if necessary.
2387 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2388 const char *
2389 map_w32_filename (const char * name, const char ** pPath)
2391 static char shortname[MAX_PATH];
2392 char * str = shortname;
2393 char c;
2394 char * path;
2395 const char * save_name = name;
2397 if (strlen (name) >= MAX_PATH)
2399 /* Return a filename which will cause callers to fail. */
2400 strcpy (shortname, "?");
2401 return shortname;
2404 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2406 register int left = 8; /* maximum number of chars in part */
2407 register int extn = 0; /* extension added? */
2408 register int dots = 2; /* maximum number of dots allowed */
2410 while (name < path)
2411 *str++ = *name++; /* skip past UNC header */
2413 while ((c = *name++))
2415 switch ( c )
2417 case ':':
2418 case '\\':
2419 case '/':
2420 *str++ = (c == ':' ? ':' : '\\');
2421 extn = 0; /* reset extension flags */
2422 dots = 2; /* max 2 dots */
2423 left = 8; /* max length 8 for main part */
2424 break;
2425 case '.':
2426 if ( dots )
2428 /* Convert path components of the form .xxx to _xxx,
2429 but leave . and .. as they are. This allows .emacs
2430 to be read as _emacs, for example. */
2432 if (! *name ||
2433 *name == '.' ||
2434 IS_DIRECTORY_SEP (*name))
2436 *str++ = '.';
2437 dots--;
2439 else
2441 *str++ = '_';
2442 left--;
2443 dots = 0;
2446 else if ( !extn )
2448 *str++ = '.';
2449 extn = 1; /* we've got an extension */
2450 left = 3; /* 3 chars in extension */
2452 else
2454 /* any embedded dots after the first are converted to _ */
2455 *str++ = '_';
2457 break;
2458 case '~':
2459 case '#': /* don't lose these, they're important */
2460 if ( ! left )
2461 str[-1] = c; /* replace last character of part */
2462 /* FALLTHRU */
2463 default:
2464 if ( left )
2466 *str++ = tolower (c); /* map to lower case (looks nicer) */
2467 left--;
2468 dots = 0; /* started a path component */
2470 break;
2473 *str = '\0';
2475 else
2477 strcpy (shortname, name);
2478 unixtodos_filename (shortname);
2481 if (pPath)
2482 *pPath = shortname + (path - save_name);
2484 return shortname;
2487 static int
2488 is_exec (const char * name)
2490 char * p = strrchr (name, '.');
2491 return
2492 (p != NULL
2493 && (xstrcasecmp (p, ".exe") == 0 ||
2494 xstrcasecmp (p, ".com") == 0 ||
2495 xstrcasecmp (p, ".bat") == 0 ||
2496 xstrcasecmp (p, ".cmd") == 0));
2499 /* Emulate the Unix directory procedures opendir, closedir,
2500 and readdir. We can't use the procedures supplied in sysdep.c,
2501 so we provide them here. */
2503 struct dirent dir_static; /* simulated directory contents */
2504 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2505 static int dir_is_fat;
2506 static char dir_pathname[MAXPATHLEN+1];
2507 static WIN32_FIND_DATA dir_find_data;
2509 /* Support shares on a network resource as subdirectories of a read-only
2510 root directory. */
2511 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2512 static HANDLE open_unc_volume (const char *);
2513 static char *read_unc_volume (HANDLE, char *, int);
2514 static void close_unc_volume (HANDLE);
2516 DIR *
2517 opendir (char *filename)
2519 DIR *dirp;
2521 /* Opening is done by FindFirstFile. However, a read is inherent to
2522 this operation, so we defer the open until read time. */
2524 if (dir_find_handle != INVALID_HANDLE_VALUE)
2525 return NULL;
2526 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2527 return NULL;
2529 /* Note: We don't support traversal of UNC volumes via symlinks.
2530 Doing so would mean punishing 99.99% of use cases by resolving
2531 all the possible symlinks in FILENAME, recursively. */
2532 if (is_unc_volume (filename))
2534 wnet_enum_handle = open_unc_volume (filename);
2535 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2536 return NULL;
2539 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2540 return NULL;
2542 dirp->dd_fd = 0;
2543 dirp->dd_loc = 0;
2544 dirp->dd_size = 0;
2546 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2547 dir_pathname[MAXPATHLEN] = '\0';
2548 /* Note: We don't support symlinks to file names on FAT volumes.
2549 Doing so would mean punishing 99.99% of use cases by resolving
2550 all the possible symlinks in FILENAME, recursively. */
2551 dir_is_fat = is_fat_volume (filename, NULL);
2553 return dirp;
2556 void
2557 closedir (DIR *dirp)
2559 /* If we have a find-handle open, close it. */
2560 if (dir_find_handle != INVALID_HANDLE_VALUE)
2562 FindClose (dir_find_handle);
2563 dir_find_handle = INVALID_HANDLE_VALUE;
2565 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2567 close_unc_volume (wnet_enum_handle);
2568 wnet_enum_handle = INVALID_HANDLE_VALUE;
2570 xfree ((char *) dirp);
2573 struct dirent *
2574 readdir (DIR *dirp)
2576 int downcase = !NILP (Vw32_downcase_file_names);
2578 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2580 if (!read_unc_volume (wnet_enum_handle,
2581 dir_find_data.cFileName,
2582 MAX_PATH))
2583 return NULL;
2585 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2586 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2588 char filename[MAXNAMLEN + 3];
2589 int ln;
2591 strcpy (filename, dir_pathname);
2592 ln = strlen (filename) - 1;
2593 if (!IS_DIRECTORY_SEP (filename[ln]))
2594 strcat (filename, "\\");
2595 strcat (filename, "*");
2597 /* Note: No need to resolve symlinks in FILENAME, because
2598 FindFirst opens the directory that is the target of a
2599 symlink. */
2600 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2602 if (dir_find_handle == INVALID_HANDLE_VALUE)
2603 return NULL;
2605 else
2607 if (!FindNextFile (dir_find_handle, &dir_find_data))
2608 return NULL;
2611 /* Emacs never uses this value, so don't bother making it match
2612 value returned by stat(). */
2613 dir_static.d_ino = 1;
2615 strcpy (dir_static.d_name, dir_find_data.cFileName);
2617 /* If the file name in cFileName[] includes `?' characters, it means
2618 the original file name used characters that cannot be represented
2619 by the current ANSI codepage. To avoid total lossage, retrieve
2620 the short 8+3 alias of the long file name. */
2621 if (_mbspbrk (dir_static.d_name, "?"))
2623 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2624 downcase = 1; /* 8+3 aliases are returned in all caps */
2626 dir_static.d_namlen = strlen (dir_static.d_name);
2627 dir_static.d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
2628 dir_static.d_namlen - dir_static.d_namlen % 4;
2630 /* If the file name in cFileName[] includes `?' characters, it means
2631 the original file name used characters that cannot be represented
2632 by the current ANSI codepage. To avoid total lossage, retrieve
2633 the short 8+3 alias of the long file name. */
2634 if (_mbspbrk (dir_find_data.cFileName, "?"))
2636 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2637 /* 8+3 aliases are returned in all caps, which could break
2638 various alists that look at filenames' extensions. */
2639 downcase = 1;
2641 else
2642 strcpy (dir_static.d_name, dir_find_data.cFileName);
2643 dir_static.d_namlen = strlen (dir_static.d_name);
2644 if (dir_is_fat)
2645 _strlwr (dir_static.d_name);
2646 else if (downcase)
2648 register char *p;
2649 for (p = dir_static.d_name; *p; p++)
2650 if (*p >= 'a' && *p <= 'z')
2651 break;
2652 if (!*p)
2653 _strlwr (dir_static.d_name);
2656 return &dir_static;
2659 static HANDLE
2660 open_unc_volume (const char *path)
2662 NETRESOURCE nr;
2663 HANDLE henum;
2664 int result;
2666 nr.dwScope = RESOURCE_GLOBALNET;
2667 nr.dwType = RESOURCETYPE_DISK;
2668 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2669 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2670 nr.lpLocalName = NULL;
2671 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
2672 nr.lpComment = NULL;
2673 nr.lpProvider = NULL;
2675 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2676 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2678 if (result == NO_ERROR)
2679 return henum;
2680 else
2681 return INVALID_HANDLE_VALUE;
2684 static char *
2685 read_unc_volume (HANDLE henum, char *readbuf, int size)
2687 DWORD count;
2688 int result;
2689 DWORD bufsize = 512;
2690 char *buffer;
2691 char *ptr;
2693 count = 1;
2694 buffer = alloca (bufsize);
2695 result = WNetEnumResource (henum, &count, buffer, &bufsize);
2696 if (result != NO_ERROR)
2697 return NULL;
2699 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2700 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2701 ptr += 2;
2702 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2703 ptr++;
2705 strncpy (readbuf, ptr, size);
2706 return readbuf;
2709 static void
2710 close_unc_volume (HANDLE henum)
2712 if (henum != INVALID_HANDLE_VALUE)
2713 WNetCloseEnum (henum);
2716 static DWORD
2717 unc_volume_file_attributes (const char *path)
2719 HANDLE henum;
2720 DWORD attrs;
2722 henum = open_unc_volume (path);
2723 if (henum == INVALID_HANDLE_VALUE)
2724 return -1;
2726 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2728 close_unc_volume (henum);
2730 return attrs;
2733 /* Ensure a network connection is authenticated. */
2734 static void
2735 logon_network_drive (const char *path)
2737 NETRESOURCE resource;
2738 char share[MAX_PATH];
2739 int i, n_slashes;
2740 char drive[4];
2741 UINT drvtype;
2743 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
2744 drvtype = DRIVE_REMOTE;
2745 else if (path[0] == '\0' || path[1] != ':')
2746 drvtype = GetDriveType (NULL);
2747 else
2749 drive[0] = path[0];
2750 drive[1] = ':';
2751 drive[2] = '\\';
2752 drive[3] = '\0';
2753 drvtype = GetDriveType (drive);
2756 /* Only logon to networked drives. */
2757 if (drvtype != DRIVE_REMOTE)
2758 return;
2760 n_slashes = 2;
2761 strncpy (share, path, MAX_PATH);
2762 /* Truncate to just server and share name. */
2763 for (i = 2; i < MAX_PATH; i++)
2765 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2767 share[i] = '\0';
2768 break;
2772 resource.dwType = RESOURCETYPE_DISK;
2773 resource.lpLocalName = NULL;
2774 resource.lpRemoteName = share;
2775 resource.lpProvider = NULL;
2777 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2780 /* Emulate faccessat(2). */
2782 faccessat (int dirfd, const char * path, int mode, int flags)
2784 DWORD attributes;
2786 if (dirfd != AT_FDCWD
2787 && !(IS_DIRECTORY_SEP (path[0])
2788 || IS_DEVICE_SEP (path[1])))
2790 errno = EBADF;
2791 return -1;
2794 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
2795 newer versions blow up when passed D_OK. */
2796 path = map_w32_filename (path, NULL);
2797 /* If the last element of PATH is a symlink, we need to resolve it
2798 to get the attributes of its target file. Note: any symlinks in
2799 PATH elements other than the last one are transparently resolved
2800 by GetFileAttributes below. */
2801 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
2802 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
2803 path = chase_symlinks (path);
2805 if ((attributes = GetFileAttributes (path)) == -1)
2807 DWORD w32err = GetLastError ();
2809 switch (w32err)
2811 case ERROR_INVALID_NAME:
2812 case ERROR_BAD_PATHNAME:
2813 if (is_unc_volume (path))
2815 attributes = unc_volume_file_attributes (path);
2816 if (attributes == -1)
2818 errno = EACCES;
2819 return -1;
2821 break;
2823 /* FALLTHROUGH */
2824 case ERROR_FILE_NOT_FOUND:
2825 case ERROR_BAD_NETPATH:
2826 errno = ENOENT;
2827 break;
2828 default:
2829 errno = EACCES;
2830 break;
2832 return -1;
2834 if ((mode & X_OK) != 0
2835 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
2837 errno = EACCES;
2838 return -1;
2840 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2842 errno = EACCES;
2843 return -1;
2845 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2847 errno = EACCES;
2848 return -1;
2850 return 0;
2853 /* Shadow some MSVC runtime functions to map requests for long filenames
2854 to reasonable short names if necessary. This was originally added to
2855 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2856 long file names. */
2859 sys_chdir (const char * path)
2861 return _chdir (map_w32_filename (path, NULL));
2865 sys_chmod (const char * path, int mode)
2867 path = chase_symlinks (map_w32_filename (path, NULL));
2868 return _chmod (path, mode);
2872 sys_chown (const char *path, uid_t owner, gid_t group)
2874 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2875 return -1;
2876 return 0;
2880 sys_creat (const char * path, int mode)
2882 return _creat (map_w32_filename (path, NULL), mode);
2885 FILE *
2886 sys_fopen (const char * path, const char * mode)
2888 int fd;
2889 int oflag;
2890 const char * mode_save = mode;
2892 /* Force all file handles to be non-inheritable. This is necessary to
2893 ensure child processes don't unwittingly inherit handles that might
2894 prevent future file access. */
2896 if (mode[0] == 'r')
2897 oflag = O_RDONLY;
2898 else if (mode[0] == 'w' || mode[0] == 'a')
2899 oflag = O_WRONLY | O_CREAT | O_TRUNC;
2900 else
2901 return NULL;
2903 /* Only do simplistic option parsing. */
2904 while (*++mode)
2905 if (mode[0] == '+')
2907 oflag &= ~(O_RDONLY | O_WRONLY);
2908 oflag |= O_RDWR;
2910 else if (mode[0] == 'b')
2912 oflag &= ~O_TEXT;
2913 oflag |= O_BINARY;
2915 else if (mode[0] == 't')
2917 oflag &= ~O_BINARY;
2918 oflag |= O_TEXT;
2920 else break;
2922 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2923 if (fd < 0)
2924 return NULL;
2926 return _fdopen (fd, mode_save);
2929 /* This only works on NTFS volumes, but is useful to have. */
2931 sys_link (const char * old, const char * new)
2933 HANDLE fileh;
2934 int result = -1;
2935 char oldname[MAX_PATH], newname[MAX_PATH];
2937 if (old == NULL || new == NULL)
2939 errno = ENOENT;
2940 return -1;
2943 strcpy (oldname, map_w32_filename (old, NULL));
2944 strcpy (newname, map_w32_filename (new, NULL));
2946 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2947 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2948 if (fileh != INVALID_HANDLE_VALUE)
2950 int wlen;
2952 /* Confusingly, the "alternate" stream name field does not apply
2953 when restoring a hard link, and instead contains the actual
2954 stream data for the link (ie. the name of the link to create).
2955 The WIN32_STREAM_ID structure before the cStreamName field is
2956 the stream header, which is then immediately followed by the
2957 stream data. */
2959 struct {
2960 WIN32_STREAM_ID wid;
2961 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2962 } data;
2964 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2965 data.wid.cStreamName, MAX_PATH);
2966 if (wlen > 0)
2968 LPVOID context = NULL;
2969 DWORD wbytes = 0;
2971 data.wid.dwStreamId = BACKUP_LINK;
2972 data.wid.dwStreamAttributes = 0;
2973 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
2974 data.wid.Size.HighPart = 0;
2975 data.wid.dwStreamNameSize = 0;
2977 if (BackupWrite (fileh, (LPBYTE)&data,
2978 offsetof (WIN32_STREAM_ID, cStreamName)
2979 + data.wid.Size.LowPart,
2980 &wbytes, FALSE, FALSE, &context)
2981 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2983 /* succeeded */
2984 result = 0;
2986 else
2988 /* Should try mapping GetLastError to errno; for now just
2989 indicate a general error (eg. links not supported). */
2990 errno = EINVAL; // perhaps EMLINK?
2994 CloseHandle (fileh);
2996 else
2997 errno = ENOENT;
2999 return result;
3003 sys_mkdir (const char * path)
3005 return _mkdir (map_w32_filename (path, NULL));
3008 /* Because of long name mapping issues, we need to implement this
3009 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
3010 a unique name, instead of setting the input template to an empty
3011 string.
3013 Standard algorithm seems to be use pid or tid with a letter on the
3014 front (in place of the 6 X's) and cycle through the letters to find a
3015 unique name. We extend that to allow any reasonable character as the
3016 first of the 6 X's. */
3017 char *
3018 sys_mktemp (char * template)
3020 char * p;
3021 int i;
3022 unsigned uid = GetCurrentThreadId ();
3023 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3025 if (template == NULL)
3026 return NULL;
3027 p = template + strlen (template);
3028 i = 5;
3029 /* replace up to the last 5 X's with uid in decimal */
3030 while (--p >= template && p[0] == 'X' && --i >= 0)
3032 p[0] = '0' + uid % 10;
3033 uid /= 10;
3036 if (i < 0 && p[0] == 'X')
3038 i = 0;
3041 int save_errno = errno;
3042 p[0] = first_char[i];
3043 if (faccessat (AT_FDCWD, template, F_OK, AT_EACCESS) < 0)
3045 errno = save_errno;
3046 return template;
3049 while (++i < sizeof (first_char));
3052 /* Template is badly formed or else we can't generate a unique name,
3053 so return empty string */
3054 template[0] = 0;
3055 return template;
3059 sys_open (const char * path, int oflag, int mode)
3061 const char* mpath = map_w32_filename (path, NULL);
3062 /* Try to open file without _O_CREAT, to be able to write to hidden
3063 and system files. Force all file handles to be
3064 non-inheritable. */
3065 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
3066 if (res >= 0)
3067 return res;
3068 return _open (mpath, oflag | _O_NOINHERIT, mode);
3072 sys_rename (const char * oldname, const char * newname)
3074 BOOL result;
3075 char temp[MAX_PATH];
3076 int newname_dev;
3077 int oldname_dev;
3079 /* MoveFile on Windows 95 doesn't correctly change the short file name
3080 alias in a number of circumstances (it is not easy to predict when
3081 just by looking at oldname and newname, unfortunately). In these
3082 cases, renaming through a temporary name avoids the problem.
3084 A second problem on Windows 95 is that renaming through a temp name when
3085 newname is uppercase fails (the final long name ends up in
3086 lowercase, although the short alias might be uppercase) UNLESS the
3087 long temp name is not 8.3.
3089 So, on Windows 95 we always rename through a temp name, and we make sure
3090 the temp name has a long extension to ensure correct renaming. */
3092 strcpy (temp, map_w32_filename (oldname, NULL));
3094 /* volume_info is set indirectly by map_w32_filename. */
3095 oldname_dev = volume_info.serialnum;
3097 if (os_subtype == OS_9X)
3099 char * o;
3100 char * p;
3101 int i = 0;
3103 oldname = map_w32_filename (oldname, NULL);
3104 if ((o = strrchr (oldname, '\\')))
3105 o++;
3106 else
3107 o = (char *) oldname;
3109 if ((p = strrchr (temp, '\\')))
3110 p++;
3111 else
3112 p = temp;
3116 /* Force temp name to require a manufactured 8.3 alias - this
3117 seems to make the second rename work properly. */
3118 sprintf (p, "_.%s.%u", o, i);
3119 i++;
3120 result = rename (oldname, temp);
3122 /* This loop must surely terminate! */
3123 while (result < 0 && errno == EEXIST);
3124 if (result < 0)
3125 return -1;
3128 /* Emulate Unix behavior - newname is deleted if it already exists
3129 (at least if it is a file; don't do this for directories).
3131 Since we mustn't do this if we are just changing the case of the
3132 file name (we would end up deleting the file we are trying to
3133 rename!), we let rename detect if the destination file already
3134 exists - that way we avoid the possible pitfalls of trying to
3135 determine ourselves whether two names really refer to the same
3136 file, which is not always possible in the general case. (Consider
3137 all the permutations of shared or subst'd drives, etc.) */
3139 newname = map_w32_filename (newname, NULL);
3141 /* volume_info is set indirectly by map_w32_filename. */
3142 newname_dev = volume_info.serialnum;
3144 result = rename (temp, newname);
3146 if (result < 0)
3148 DWORD w32err = GetLastError ();
3150 if (errno == EACCES
3151 && newname_dev != oldname_dev)
3153 /* The implementation of `rename' on Windows does not return
3154 errno = EXDEV when you are moving a directory to a
3155 different storage device (ex. logical disk). It returns
3156 EACCES instead. So here we handle such situations and
3157 return EXDEV. */
3158 DWORD attributes;
3160 if ((attributes = GetFileAttributes (temp)) != -1
3161 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
3162 errno = EXDEV;
3164 else if (errno == EEXIST)
3166 if (_chmod (newname, 0666) != 0)
3167 return result;
3168 if (_unlink (newname) != 0)
3169 return result;
3170 result = rename (temp, newname);
3172 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
3173 && is_symlink (temp))
3175 /* This is Windows prohibiting the user from creating a
3176 symlink in another place, since that requires
3177 privileges. */
3178 errno = EPERM;
3182 return result;
3186 sys_rmdir (const char * path)
3188 return _rmdir (map_w32_filename (path, NULL));
3192 sys_unlink (const char * path)
3194 path = map_w32_filename (path, NULL);
3196 /* On Unix, unlink works without write permission. */
3197 _chmod (path, 0666);
3198 return _unlink (path);
3201 static FILETIME utc_base_ft;
3202 static ULONGLONG utc_base; /* In 100ns units */
3203 static int init = 0;
3205 #define FILETIME_TO_U64(result, ft) \
3206 do { \
3207 ULARGE_INTEGER uiTemp; \
3208 uiTemp.LowPart = (ft).dwLowDateTime; \
3209 uiTemp.HighPart = (ft).dwHighDateTime; \
3210 result = uiTemp.QuadPart; \
3211 } while (0)
3213 static void
3214 initialize_utc_base (void)
3216 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3217 SYSTEMTIME st;
3219 st.wYear = 1970;
3220 st.wMonth = 1;
3221 st.wDay = 1;
3222 st.wHour = 0;
3223 st.wMinute = 0;
3224 st.wSecond = 0;
3225 st.wMilliseconds = 0;
3227 SystemTimeToFileTime (&st, &utc_base_ft);
3228 FILETIME_TO_U64 (utc_base, utc_base_ft);
3231 static time_t
3232 convert_time (FILETIME ft)
3234 ULONGLONG tmp;
3236 if (!init)
3238 initialize_utc_base ();
3239 init = 1;
3242 if (CompareFileTime (&ft, &utc_base_ft) < 0)
3243 return 0;
3245 FILETIME_TO_U64 (tmp, ft);
3246 return (time_t) ((tmp - utc_base) / 10000000L);
3249 static void
3250 convert_from_time_t (time_t time, FILETIME * pft)
3252 ULARGE_INTEGER tmp;
3254 if (!init)
3256 initialize_utc_base ();
3257 init = 1;
3260 /* time in 100ns units since 1-Jan-1601 */
3261 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
3262 pft->dwHighDateTime = tmp.HighPart;
3263 pft->dwLowDateTime = tmp.LowPart;
3266 #if 0
3267 /* No reason to keep this; faking inode values either by hashing or even
3268 using the file index from GetInformationByHandle, is not perfect and
3269 so by default Emacs doesn't use the inode values on Windows.
3270 Instead, we now determine file-truename correctly (except for
3271 possible drive aliasing etc). */
3273 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3274 static unsigned
3275 hashval (const unsigned char * str)
3277 unsigned h = 0;
3278 while (*str)
3280 h = (h << 4) + *str++;
3281 h ^= (h >> 28);
3283 return h;
3286 /* Return the hash value of the canonical pathname, excluding the
3287 drive/UNC header, to get a hopefully unique inode number. */
3288 static DWORD
3289 generate_inode_val (const char * name)
3291 char fullname[ MAX_PATH ];
3292 char * p;
3293 unsigned hash;
3295 /* Get the truly canonical filename, if it exists. (Note: this
3296 doesn't resolve aliasing due to subst commands, or recognize hard
3297 links. */
3298 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3299 emacs_abort ();
3301 parse_root (fullname, &p);
3302 /* Normal W32 filesystems are still case insensitive. */
3303 _strlwr (p);
3304 return hashval (p);
3307 #endif
3309 static PSECURITY_DESCRIPTOR
3310 get_file_security_desc_by_handle (HANDLE h)
3312 PSECURITY_DESCRIPTOR psd = NULL;
3313 DWORD err;
3314 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3315 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3317 err = get_security_info (h, SE_FILE_OBJECT, si,
3318 NULL, NULL, NULL, NULL, &psd);
3319 if (err != ERROR_SUCCESS)
3320 return NULL;
3322 return psd;
3325 static PSECURITY_DESCRIPTOR
3326 get_file_security_desc_by_name (const char *fname)
3328 PSECURITY_DESCRIPTOR psd = NULL;
3329 DWORD sd_len, err;
3330 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3331 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3333 if (!get_file_security (fname, si, psd, 0, &sd_len))
3335 err = GetLastError ();
3336 if (err != ERROR_INSUFFICIENT_BUFFER)
3337 return NULL;
3340 psd = xmalloc (sd_len);
3341 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3343 xfree (psd);
3344 return NULL;
3347 return psd;
3350 static DWORD
3351 get_rid (PSID sid)
3353 unsigned n_subauthorities;
3355 /* Use the last sub-authority value of the RID, the relative
3356 portion of the SID, as user/group ID. */
3357 n_subauthorities = *get_sid_sub_authority_count (sid);
3358 if (n_subauthorities < 1)
3359 return 0; /* the "World" RID */
3360 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3363 /* Caching SID and account values for faster lokup. */
3365 #ifdef __GNUC__
3366 # define FLEXIBLE_ARRAY_MEMBER
3367 #else
3368 # define FLEXIBLE_ARRAY_MEMBER 1
3369 #endif
3371 struct w32_id {
3372 unsigned rid;
3373 struct w32_id *next;
3374 char name[GNLEN+1];
3375 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3378 static struct w32_id *w32_idlist;
3380 static int
3381 w32_cached_id (PSID sid, unsigned *id, char *name)
3383 struct w32_id *tail, *found;
3385 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3387 if (equal_sid ((PSID)tail->sid, sid))
3389 found = tail;
3390 break;
3393 if (found)
3395 *id = found->rid;
3396 strcpy (name, found->name);
3397 return 1;
3399 else
3400 return 0;
3403 static void
3404 w32_add_to_cache (PSID sid, unsigned id, char *name)
3406 DWORD sid_len;
3407 struct w32_id *new_entry;
3409 /* We don't want to leave behind stale cache from when Emacs was
3410 dumped. */
3411 if (initialized)
3413 sid_len = get_length_sid (sid);
3414 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3415 if (new_entry)
3417 new_entry->rid = id;
3418 strcpy (new_entry->name, name);
3419 copy_sid (sid_len, (PSID)new_entry->sid, sid);
3420 new_entry->next = w32_idlist;
3421 w32_idlist = new_entry;
3426 #define UID 1
3427 #define GID 2
3429 static int
3430 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
3431 unsigned *id, char *nm, int what)
3433 PSID sid = NULL;
3434 char machine[MAX_COMPUTERNAME_LENGTH+1];
3435 BOOL dflt;
3436 SID_NAME_USE ignore;
3437 char name[UNLEN+1];
3438 DWORD name_len = sizeof (name);
3439 char domain[1024];
3440 DWORD domain_len = sizeof (domain);
3441 char *mp = NULL;
3442 int use_dflt = 0;
3443 int result;
3445 if (what == UID)
3446 result = get_security_descriptor_owner (psd, &sid, &dflt);
3447 else if (what == GID)
3448 result = get_security_descriptor_group (psd, &sid, &dflt);
3449 else
3450 result = 0;
3452 if (!result || !is_valid_sid (sid))
3453 use_dflt = 1;
3454 else if (!w32_cached_id (sid, id, nm))
3456 /* If FNAME is a UNC, we need to lookup account on the
3457 specified machine. */
3458 if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
3459 && fname[2] != '\0')
3461 const char *s;
3462 char *p;
3464 for (s = fname + 2, p = machine;
3465 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
3466 *p = *s;
3467 *p = '\0';
3468 mp = machine;
3471 if (!lookup_account_sid (mp, sid, name, &name_len,
3472 domain, &domain_len, &ignore)
3473 || name_len > UNLEN+1)
3474 use_dflt = 1;
3475 else
3477 *id = get_rid (sid);
3478 strcpy (nm, name);
3479 w32_add_to_cache (sid, *id, name);
3482 return use_dflt;
3485 static void
3486 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd,
3487 const char *fname,
3488 struct stat *st)
3490 int dflt_usr = 0, dflt_grp = 0;
3492 if (!psd)
3494 dflt_usr = 1;
3495 dflt_grp = 1;
3497 else
3499 if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
3500 dflt_usr = 1;
3501 if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
3502 dflt_grp = 1;
3504 /* Consider files to belong to current user/group, if we cannot get
3505 more accurate information. */
3506 if (dflt_usr)
3508 st->st_uid = dflt_passwd.pw_uid;
3509 strcpy (st->st_uname, dflt_passwd.pw_name);
3511 if (dflt_grp)
3513 st->st_gid = dflt_passwd.pw_gid;
3514 strcpy (st->st_gname, dflt_group.gr_name);
3518 /* Return non-zero if NAME is a potentially slow filesystem. */
3520 is_slow_fs (const char *name)
3522 char drive_root[4];
3523 UINT devtype;
3525 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
3526 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
3527 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
3528 devtype = GetDriveType (NULL); /* use root of current drive */
3529 else
3531 /* GetDriveType needs the root directory of the drive. */
3532 strncpy (drive_root, name, 2);
3533 drive_root[2] = '\\';
3534 drive_root[3] = '\0';
3535 devtype = GetDriveType (drive_root);
3537 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
3540 /* MSVC stat function can't cope with UNC names and has other bugs, so
3541 replace it with our own. This also allows us to calculate consistent
3542 inode values and owner/group without hacks in the main Emacs code. */
3544 static int
3545 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
3547 char *name, *save_name, *r;
3548 WIN32_FIND_DATA wfd;
3549 HANDLE fh;
3550 unsigned __int64 fake_inode = 0;
3551 int permission;
3552 int len;
3553 int rootdir = FALSE;
3554 PSECURITY_DESCRIPTOR psd = NULL;
3555 int is_a_symlink = 0;
3556 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
3557 DWORD access_rights = 0;
3558 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
3559 FILETIME ctime, atime, wtime;
3561 if (path == NULL || buf == NULL)
3563 errno = EFAULT;
3564 return -1;
3567 save_name = name = (char *) map_w32_filename (path, &path);
3568 /* Must be valid filename, no wild cards or other invalid
3569 characters. We use _mbspbrk to support multibyte strings that
3570 might look to strpbrk as if they included literal *, ?, and other
3571 characters mentioned below that are disallowed by Windows
3572 filesystems. */
3573 if (_mbspbrk (name, "*?|<>\""))
3575 errno = ENOENT;
3576 return -1;
3579 /* Remove trailing directory separator, unless name is the root
3580 directory of a drive or UNC volume in which case ensure there
3581 is a trailing separator. */
3582 len = strlen (name);
3583 name = strcpy (alloca (len + 2), name);
3585 /* Avoid a somewhat costly call to is_symlink if the filesystem
3586 doesn't support symlinks. */
3587 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
3588 is_a_symlink = is_symlink (name);
3590 /* Plan A: Open the file and get all the necessary information via
3591 the resulting handle. This solves several issues in one blow:
3593 . retrieves attributes for the target of a symlink, if needed
3594 . gets attributes of root directories and symlinks pointing to
3595 root directories, thus avoiding the need for special-casing
3596 these and detecting them by examining the file-name format
3597 . retrieves more accurate attributes (e.g., non-zero size for
3598 some directories, esp. directories that are junction points)
3599 . correctly resolves "c:/..", "/.." and similar file names
3600 . avoids run-time penalties for 99% of use cases
3602 Plan A is always tried first, unless the user asked not to (but
3603 if the file is a symlink and we need to follow links, we try Plan
3604 A even if the user asked not to).
3606 If Plan A fails, we go to Plan B (below), where various
3607 potentially expensive techniques must be used to handle "special"
3608 files such as UNC volumes etc. */
3609 if (!(NILP (Vw32_get_true_file_attributes)
3610 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
3611 /* Following symlinks requires getting the info by handle. */
3612 || (is_a_symlink && follow_symlinks))
3614 BY_HANDLE_FILE_INFORMATION info;
3616 if (is_a_symlink && !follow_symlinks)
3617 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
3618 /* READ_CONTROL access rights are required to get security info
3619 by handle. But if the OS doesn't support security in the
3620 first place, we don't need to try. */
3621 if (is_windows_9x () != TRUE)
3622 access_rights |= READ_CONTROL;
3624 fh = CreateFile (name, access_rights, 0, NULL, OPEN_EXISTING,
3625 file_flags, NULL);
3626 /* If CreateFile fails with READ_CONTROL, try again with zero as
3627 access rights. */
3628 if (fh == INVALID_HANDLE_VALUE && access_rights)
3629 fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
3630 file_flags, NULL);
3631 if (fh == INVALID_HANDLE_VALUE)
3632 goto no_true_file_attributes;
3634 /* This is more accurate in terms of getting the correct number
3635 of links, but is quite slow (it is noticeable when Emacs is
3636 making a list of file name completions). */
3637 if (GetFileInformationByHandle (fh, &info))
3639 nlinks = info.nNumberOfLinks;
3640 /* Might as well use file index to fake inode values, but this
3641 is not guaranteed to be unique unless we keep a handle open
3642 all the time (even then there are situations where it is
3643 not unique). Reputedly, there are at most 48 bits of info
3644 (on NTFS, presumably less on FAT). */
3645 fake_inode = info.nFileIndexHigh;
3646 fake_inode <<= 32;
3647 fake_inode += info.nFileIndexLow;
3648 serialnum = info.dwVolumeSerialNumber;
3649 fs_high = info.nFileSizeHigh;
3650 fs_low = info.nFileSizeLow;
3651 ctime = info.ftCreationTime;
3652 atime = info.ftLastAccessTime;
3653 wtime = info.ftLastWriteTime;
3654 fattrs = info.dwFileAttributes;
3656 else
3658 /* We don't go to Plan B here, because it's not clear that
3659 it's a good idea. The only known use case where
3660 CreateFile succeeds, but GetFileInformationByHandle fails
3661 (with ERROR_INVALID_FUNCTION) is for character devices
3662 such as NUL, PRN, etc. For these, switching to Plan B is
3663 a net loss, because we lose the character device
3664 attribute returned by GetFileType below (FindFirstFile
3665 doesn't set that bit in the attributes), and the other
3666 fields don't make sense for character devices anyway.
3667 Emacs doesn't really care for non-file entities in the
3668 context of l?stat, so neither do we. */
3670 /* w32err is assigned so one could put a breakpoint here and
3671 examine its value, when GetFileInformationByHandle
3672 fails. */
3673 DWORD w32err = GetLastError ();
3675 switch (w32err)
3677 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
3678 errno = ENOENT;
3679 return -1;
3683 /* Test for a symlink before testing for a directory, since
3684 symlinks to directories have the directory bit set, but we
3685 don't want them to appear as directories. */
3686 if (is_a_symlink && !follow_symlinks)
3687 buf->st_mode = S_IFLNK;
3688 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3689 buf->st_mode = S_IFDIR;
3690 else
3692 DWORD ftype = GetFileType (fh);
3694 switch (ftype)
3696 case FILE_TYPE_DISK:
3697 buf->st_mode = S_IFREG;
3698 break;
3699 case FILE_TYPE_PIPE:
3700 buf->st_mode = S_IFIFO;
3701 break;
3702 case FILE_TYPE_CHAR:
3703 case FILE_TYPE_UNKNOWN:
3704 default:
3705 buf->st_mode = S_IFCHR;
3708 /* We produce the fallback owner and group data, based on the
3709 current user that runs Emacs, in the following cases:
3711 . this is Windows 9X
3712 . getting security by handle failed, and we need to produce
3713 information for the target of a symlink (this is better
3714 than producing a potentially misleading info about the
3715 symlink itself)
3717 If getting security by handle fails, and we don't need to
3718 resolve symlinks, we try getting security by name. */
3719 if (is_windows_9x () != TRUE)
3720 psd = get_file_security_desc_by_handle (fh);
3721 if (psd)
3723 get_file_owner_and_group (psd, name, buf);
3724 LocalFree (psd);
3726 else if (is_windows_9x () == TRUE)
3727 get_file_owner_and_group (NULL, name, buf);
3728 else if (!(is_a_symlink && follow_symlinks))
3730 psd = get_file_security_desc_by_name (name);
3731 get_file_owner_and_group (psd, name, buf);
3732 xfree (psd);
3734 else
3735 get_file_owner_and_group (NULL, name, buf);
3736 CloseHandle (fh);
3738 else
3740 no_true_file_attributes:
3741 /* Plan B: Either getting a handle on the file failed, or the
3742 caller explicitly asked us to not bother making this
3743 information more accurate.
3745 Implementation note: In Plan B, we never bother to resolve
3746 symlinks, even if we got here because we tried Plan A and
3747 failed. That's because, even if the caller asked for extra
3748 precision by setting Vw32_get_true_file_attributes to t,
3749 resolving symlinks requires acquiring a file handle to the
3750 symlink, which we already know will fail. And if the user
3751 did not ask for extra precision, resolving symlinks will fly
3752 in the face of that request, since the user then wants the
3753 lightweight version of the code. */
3754 rootdir = (path >= save_name + len - 1
3755 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3757 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3758 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3759 if (IS_DIRECTORY_SEP (r[0])
3760 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3761 r[1] = r[2] = '\0';
3763 /* Note: If NAME is a symlink to the root of a UNC volume
3764 (i.e. "\\SERVER"), we will not detect that here, and we will
3765 return data about the symlink as result of FindFirst below.
3766 This is unfortunate, but that marginal use case does not
3767 justify a call to chase_symlinks which would impose a penalty
3768 on all the other use cases. (We get here for symlinks to
3769 roots of UNC volumes because CreateFile above fails for them,
3770 unlike with symlinks to root directories X:\ of drives.) */
3771 if (is_unc_volume (name))
3773 fattrs = unc_volume_file_attributes (name);
3774 if (fattrs == -1)
3775 return -1;
3777 ctime = atime = wtime = utc_base_ft;
3779 else if (rootdir)
3781 if (!IS_DIRECTORY_SEP (name[len-1]))
3782 strcat (name, "\\");
3783 if (GetDriveType (name) < 2)
3785 errno = ENOENT;
3786 return -1;
3789 fattrs = FILE_ATTRIBUTE_DIRECTORY;
3790 ctime = atime = wtime = utc_base_ft;
3792 else
3794 if (IS_DIRECTORY_SEP (name[len-1]))
3795 name[len - 1] = 0;
3797 /* (This is hacky, but helps when doing file completions on
3798 network drives.) Optimize by using information available from
3799 active readdir if possible. */
3800 len = strlen (dir_pathname);
3801 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3802 len--;
3803 if (dir_find_handle != INVALID_HANDLE_VALUE
3804 && !(is_a_symlink && follow_symlinks)
3805 && strnicmp (save_name, dir_pathname, len) == 0
3806 && IS_DIRECTORY_SEP (name[len])
3807 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3809 /* This was the last entry returned by readdir. */
3810 wfd = dir_find_data;
3812 else
3814 logon_network_drive (name);
3816 fh = FindFirstFile (name, &wfd);
3817 if (fh == INVALID_HANDLE_VALUE)
3819 errno = ENOENT;
3820 return -1;
3822 FindClose (fh);
3824 /* Note: if NAME is a symlink, the information we get from
3825 FindFirstFile is for the symlink, not its target. */
3826 fattrs = wfd.dwFileAttributes;
3827 ctime = wfd.ftCreationTime;
3828 atime = wfd.ftLastAccessTime;
3829 wtime = wfd.ftLastWriteTime;
3830 fs_high = wfd.nFileSizeHigh;
3831 fs_low = wfd.nFileSizeLow;
3832 fake_inode = 0;
3833 nlinks = 1;
3834 serialnum = volume_info.serialnum;
3836 if (is_a_symlink && !follow_symlinks)
3837 buf->st_mode = S_IFLNK;
3838 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3839 buf->st_mode = S_IFDIR;
3840 else
3841 buf->st_mode = S_IFREG;
3843 get_file_owner_and_group (NULL, name, buf);
3846 #if 0
3847 /* Not sure if there is any point in this. */
3848 if (!NILP (Vw32_generate_fake_inodes))
3849 fake_inode = generate_inode_val (name);
3850 else if (fake_inode == 0)
3852 /* For want of something better, try to make everything unique. */
3853 static DWORD gen_num = 0;
3854 fake_inode = ++gen_num;
3856 #endif
3858 buf->st_ino = fake_inode;
3860 buf->st_dev = serialnum;
3861 buf->st_rdev = serialnum;
3863 buf->st_size = fs_high;
3864 buf->st_size <<= 32;
3865 buf->st_size += fs_low;
3866 buf->st_nlink = nlinks;
3868 /* Convert timestamps to Unix format. */
3869 buf->st_mtime = convert_time (wtime);
3870 buf->st_atime = convert_time (atime);
3871 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3872 buf->st_ctime = convert_time (ctime);
3873 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3875 /* determine rwx permissions */
3876 if (is_a_symlink && !follow_symlinks)
3877 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
3878 else
3880 if (fattrs & FILE_ATTRIBUTE_READONLY)
3881 permission = S_IREAD;
3882 else
3883 permission = S_IREAD | S_IWRITE;
3885 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3886 permission |= S_IEXEC;
3887 else if (is_exec (name))
3888 permission |= S_IEXEC;
3891 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3893 return 0;
3897 stat (const char * path, struct stat * buf)
3899 return stat_worker (path, buf, 1);
3903 lstat (const char * path, struct stat * buf)
3905 return stat_worker (path, buf, 0);
3908 /* Provide fstat and utime as well as stat for consistent handling of
3909 file timestamps. */
3911 fstat (int desc, struct stat * buf)
3913 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3914 BY_HANDLE_FILE_INFORMATION info;
3915 unsigned __int64 fake_inode;
3916 int permission;
3918 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3920 case FILE_TYPE_DISK:
3921 buf->st_mode = S_IFREG;
3922 if (!GetFileInformationByHandle (fh, &info))
3924 errno = EACCES;
3925 return -1;
3927 break;
3928 case FILE_TYPE_PIPE:
3929 buf->st_mode = S_IFIFO;
3930 goto non_disk;
3931 case FILE_TYPE_CHAR:
3932 case FILE_TYPE_UNKNOWN:
3933 default:
3934 buf->st_mode = S_IFCHR;
3935 non_disk:
3936 memset (&info, 0, sizeof (info));
3937 info.dwFileAttributes = 0;
3938 info.ftCreationTime = utc_base_ft;
3939 info.ftLastAccessTime = utc_base_ft;
3940 info.ftLastWriteTime = utc_base_ft;
3943 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3944 buf->st_mode = S_IFDIR;
3946 buf->st_nlink = info.nNumberOfLinks;
3947 /* Might as well use file index to fake inode values, but this
3948 is not guaranteed to be unique unless we keep a handle open
3949 all the time (even then there are situations where it is
3950 not unique). Reputedly, there are at most 48 bits of info
3951 (on NTFS, presumably less on FAT). */
3952 fake_inode = info.nFileIndexHigh;
3953 fake_inode <<= 32;
3954 fake_inode += info.nFileIndexLow;
3956 /* MSVC defines _ino_t to be short; other libc's might not. */
3957 if (sizeof (buf->st_ino) == 2)
3958 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3959 else
3960 buf->st_ino = fake_inode;
3962 /* Consider files to belong to current user.
3963 FIXME: this should use GetSecurityInfo API, but it is only
3964 available for _WIN32_WINNT >= 0x501. */
3965 buf->st_uid = dflt_passwd.pw_uid;
3966 buf->st_gid = dflt_passwd.pw_gid;
3967 strcpy (buf->st_uname, dflt_passwd.pw_name);
3968 strcpy (buf->st_gname, dflt_group.gr_name);
3970 buf->st_dev = info.dwVolumeSerialNumber;
3971 buf->st_rdev = info.dwVolumeSerialNumber;
3973 buf->st_size = info.nFileSizeHigh;
3974 buf->st_size <<= 32;
3975 buf->st_size += info.nFileSizeLow;
3977 /* Convert timestamps to Unix format. */
3978 buf->st_mtime = convert_time (info.ftLastWriteTime);
3979 buf->st_atime = convert_time (info.ftLastAccessTime);
3980 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3981 buf->st_ctime = convert_time (info.ftCreationTime);
3982 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3984 /* determine rwx permissions */
3985 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3986 permission = S_IREAD;
3987 else
3988 permission = S_IREAD | S_IWRITE;
3990 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3991 permission |= S_IEXEC;
3992 else
3994 #if 0 /* no way of knowing the filename */
3995 char * p = strrchr (name, '.');
3996 if (p != NULL &&
3997 (xstrcasecmp (p, ".exe") == 0 ||
3998 xstrcasecmp (p, ".com") == 0 ||
3999 xstrcasecmp (p, ".bat") == 0 ||
4000 xstrcasecmp (p, ".cmd") == 0))
4001 permission |= S_IEXEC;
4002 #endif
4005 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
4007 return 0;
4011 utime (const char *name, struct utimbuf *times)
4013 struct utimbuf deftime;
4014 HANDLE fh;
4015 FILETIME mtime;
4016 FILETIME atime;
4018 if (times == NULL)
4020 deftime.modtime = deftime.actime = time (NULL);
4021 times = &deftime;
4024 /* Need write access to set times. */
4025 fh = CreateFile (name, FILE_WRITE_ATTRIBUTES,
4026 /* If NAME specifies a directory, FILE_SHARE_DELETE
4027 allows other processes to delete files inside it,
4028 while we have the directory open. */
4029 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4030 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
4031 if (fh != INVALID_HANDLE_VALUE)
4033 convert_from_time_t (times->actime, &atime);
4034 convert_from_time_t (times->modtime, &mtime);
4035 if (!SetFileTime (fh, NULL, &atime, &mtime))
4037 CloseHandle (fh);
4038 errno = EACCES;
4039 return -1;
4041 CloseHandle (fh);
4043 else
4045 errno = EINVAL;
4046 return -1;
4048 return 0;
4052 /* Symlink-related functions. */
4053 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4054 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4055 #endif
4058 symlink (char const *filename, char const *linkname)
4060 char linkfn[MAX_PATH], *tgtfn;
4061 DWORD flags = 0;
4062 int dir_access, filename_ends_in_slash;
4064 /* Diagnostics follows Posix as much as possible. */
4065 if (filename == NULL || linkname == NULL)
4067 errno = EFAULT;
4068 return -1;
4070 if (!*filename)
4072 errno = ENOENT;
4073 return -1;
4075 if (strlen (filename) > MAX_PATH || strlen (linkname) > MAX_PATH)
4077 errno = ENAMETOOLONG;
4078 return -1;
4081 strcpy (linkfn, map_w32_filename (linkname, NULL));
4082 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
4084 errno = EPERM;
4085 return -1;
4088 /* Note: since empty FILENAME was already rejected, we can safely
4089 refer to FILENAME[1]. */
4090 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
4092 /* Non-absolute FILENAME is understood as being relative to
4093 LINKNAME's directory. We need to prepend that directory to
4094 FILENAME to get correct results from faccessat below, since
4095 otherwise it will interpret FILENAME relative to the
4096 directory where the Emacs process runs. Note that
4097 make-symbolic-link always makes sure LINKNAME is a fully
4098 expanded file name. */
4099 char tem[MAX_PATH];
4100 char *p = linkfn + strlen (linkfn);
4102 while (p > linkfn && !IS_ANY_SEP (p[-1]))
4103 p--;
4104 if (p > linkfn)
4105 strncpy (tem, linkfn, p - linkfn);
4106 tem[p - linkfn] = '\0';
4107 strcat (tem, filename);
4108 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
4110 else
4111 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
4113 /* Since Windows distinguishes between symlinks to directories and
4114 to files, we provide a kludgy feature: if FILENAME doesn't
4115 exist, but ends in a slash, we create a symlink to directory. If
4116 FILENAME exists and is a directory, we always create a symlink to
4117 directory. */
4118 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
4119 if (dir_access == 0 || filename_ends_in_slash)
4120 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
4122 tgtfn = (char *)map_w32_filename (filename, NULL);
4123 if (filename_ends_in_slash)
4124 tgtfn[strlen (tgtfn) - 1] = '\0';
4126 errno = 0;
4127 if (!create_symbolic_link (linkfn, tgtfn, flags))
4129 /* ENOSYS is set by create_symbolic_link, when it detects that
4130 the OS doesn't support the CreateSymbolicLink API. */
4131 if (errno != ENOSYS)
4133 DWORD w32err = GetLastError ();
4135 switch (w32err)
4137 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4138 TGTFN point to the same file name, go figure. */
4139 case ERROR_SUCCESS:
4140 case ERROR_FILE_EXISTS:
4141 errno = EEXIST;
4142 break;
4143 case ERROR_ACCESS_DENIED:
4144 errno = EACCES;
4145 break;
4146 case ERROR_FILE_NOT_FOUND:
4147 case ERROR_PATH_NOT_FOUND:
4148 case ERROR_BAD_NETPATH:
4149 case ERROR_INVALID_REPARSE_DATA:
4150 errno = ENOENT;
4151 break;
4152 case ERROR_DIRECTORY:
4153 errno = EISDIR;
4154 break;
4155 case ERROR_PRIVILEGE_NOT_HELD:
4156 case ERROR_NOT_ALL_ASSIGNED:
4157 errno = EPERM;
4158 break;
4159 case ERROR_DISK_FULL:
4160 errno = ENOSPC;
4161 break;
4162 default:
4163 errno = EINVAL;
4164 break;
4167 return -1;
4169 return 0;
4172 /* A quick inexpensive test of whether FILENAME identifies a file that
4173 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4174 must already be in the normalized form returned by
4175 map_w32_filename.
4177 Note: for repeated operations on many files, it is best to test
4178 whether the underlying volume actually supports symlinks, by
4179 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4180 avoid the call to this function if it doesn't. That's because the
4181 call to GetFileAttributes takes a non-negligible time, especially
4182 on non-local or removable filesystems. See stat_worker for an
4183 example of how to do that. */
4184 static int
4185 is_symlink (const char *filename)
4187 DWORD attrs;
4188 WIN32_FIND_DATA wfd;
4189 HANDLE fh;
4191 attrs = GetFileAttributes (filename);
4192 if (attrs == -1)
4194 DWORD w32err = GetLastError ();
4196 switch (w32err)
4198 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
4199 break;
4200 case ERROR_ACCESS_DENIED:
4201 errno = EACCES;
4202 break;
4203 case ERROR_FILE_NOT_FOUND:
4204 case ERROR_PATH_NOT_FOUND:
4205 default:
4206 errno = ENOENT;
4207 break;
4209 return 0;
4211 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
4212 return 0;
4213 logon_network_drive (filename);
4214 fh = FindFirstFile (filename, &wfd);
4215 if (fh == INVALID_HANDLE_VALUE)
4216 return 0;
4217 FindClose (fh);
4218 return (wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
4219 && (wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
4222 /* If NAME identifies a symbolic link, copy into BUF the file name of
4223 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4224 null-terminate the target name, even if it fits. Return the number
4225 of bytes copied, or -1 if NAME is not a symlink or any error was
4226 encountered while resolving it. The file name copied into BUF is
4227 encoded in the current ANSI codepage. */
4228 ssize_t
4229 readlink (const char *name, char *buf, size_t buf_size)
4231 const char *path;
4232 TOKEN_PRIVILEGES privs;
4233 int restore_privs = 0;
4234 HANDLE sh;
4235 ssize_t retval;
4237 if (name == NULL)
4239 errno = EFAULT;
4240 return -1;
4242 if (!*name)
4244 errno = ENOENT;
4245 return -1;
4248 path = map_w32_filename (name, NULL);
4250 if (strlen (path) > MAX_PATH)
4252 errno = ENAMETOOLONG;
4253 return -1;
4256 errno = 0;
4257 if (is_windows_9x () == TRUE
4258 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
4259 || !is_symlink (path))
4261 if (!errno)
4262 errno = EINVAL; /* not a symlink */
4263 return -1;
4266 /* Done with simple tests, now we're in for some _real_ work. */
4267 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
4268 restore_privs = 1;
4269 /* Implementation note: From here and onward, don't return early,
4270 since that will fail to restore the original set of privileges of
4271 the calling thread. */
4273 retval = -1; /* not too optimistic, are we? */
4275 /* Note: In the next call to CreateFile, we use zero as the 2nd
4276 argument because, when the symlink is a hidden/system file,
4277 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4278 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4279 and directory symlinks. */
4280 sh = CreateFile (path, 0, 0, NULL, OPEN_EXISTING,
4281 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
4282 NULL);
4283 if (sh != INVALID_HANDLE_VALUE)
4285 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
4286 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
4287 DWORD retbytes;
4289 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
4290 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
4291 &retbytes, NULL))
4292 errno = EIO;
4293 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
4294 errno = EINVAL;
4295 else
4297 /* Copy the link target name, in wide characters, fro
4298 reparse_data, then convert it to multibyte encoding in
4299 the current locale's codepage. */
4300 WCHAR *lwname;
4301 BYTE lname[MAX_PATH];
4302 USHORT lname_len;
4303 USHORT lwname_len =
4304 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
4305 WCHAR *lwname_src =
4306 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
4307 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
4309 /* According to MSDN, PrintNameLength does not include the
4310 terminating null character. */
4311 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
4312 memcpy (lwname, lwname_src, lwname_len);
4313 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
4315 /* FIXME: Should we use the current file-name coding system
4316 instead of the fixed value of the ANSI codepage? */
4317 lname_len = WideCharToMultiByte (w32_ansi_code_page, 0, lwname, -1,
4318 lname, MAX_PATH, NULL, NULL);
4319 if (!lname_len)
4321 /* WideCharToMultiByte failed. */
4322 DWORD w32err1 = GetLastError ();
4324 switch (w32err1)
4326 case ERROR_INSUFFICIENT_BUFFER:
4327 errno = ENAMETOOLONG;
4328 break;
4329 case ERROR_INVALID_PARAMETER:
4330 errno = EFAULT;
4331 break;
4332 case ERROR_NO_UNICODE_TRANSLATION:
4333 errno = ENOENT;
4334 break;
4335 default:
4336 errno = EINVAL;
4337 break;
4340 else
4342 size_t size_to_copy = buf_size;
4343 BYTE *p = lname;
4344 BYTE *pend = p + lname_len;
4346 /* Normalize like dostounix_filename does, but we don't
4347 want to assume that lname is null-terminated. */
4348 if (*p && p[1] == ':' && *p >= 'A' && *p <= 'Z')
4349 *p += 'a' - 'A';
4350 while (p <= pend)
4352 if (*p == '\\')
4353 *p = '/';
4354 ++p;
4356 /* Testing for null-terminated LNAME is paranoia:
4357 WideCharToMultiByte should always return a
4358 null-terminated string when its 4th argument is -1
4359 and its 3rd argument is null-terminated (which they
4360 are, see above). */
4361 if (lname[lname_len - 1] == '\0')
4362 lname_len--;
4363 if (lname_len <= buf_size)
4364 size_to_copy = lname_len;
4365 strncpy (buf, lname, size_to_copy);
4366 /* Success! */
4367 retval = size_to_copy;
4370 CloseHandle (sh);
4372 else
4374 /* CreateFile failed. */
4375 DWORD w32err2 = GetLastError ();
4377 switch (w32err2)
4379 case ERROR_FILE_NOT_FOUND:
4380 case ERROR_PATH_NOT_FOUND:
4381 errno = ENOENT;
4382 break;
4383 case ERROR_ACCESS_DENIED:
4384 case ERROR_TOO_MANY_OPEN_FILES:
4385 errno = EACCES;
4386 break;
4387 default:
4388 errno = EPERM;
4389 break;
4392 if (restore_privs)
4394 restore_privilege (&privs);
4395 revert_to_self ();
4398 return retval;
4401 /* If FILE is a symlink, return its target (stored in a static
4402 buffer); otherwise return FILE.
4404 This function repeatedly resolves symlinks in the last component of
4405 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4406 until it arrives at a file whose last component is not a symlink,
4407 or some error occurs. It returns the target of the last
4408 successfully resolved symlink in the chain. If it succeeds to
4409 resolve even a single symlink, the value returned is an absolute
4410 file name with backslashes (result of GetFullPathName). By
4411 contrast, if the original FILE is returned, it is unaltered.
4413 Note: This function can set errno even if it succeeds.
4415 Implementation note: we only resolve the last portion ("basename")
4416 of the argument FILE and of each following file in the chain,
4417 disregarding any possible symlinks in its leading directories.
4418 This is because Windows system calls and library functions
4419 transparently resolve symlinks in leading directories and return
4420 correct information, as long as the basename is not a symlink. */
4421 static char *
4422 chase_symlinks (const char *file)
4424 static char target[MAX_PATH];
4425 char link[MAX_PATH];
4426 ssize_t res, link_len;
4427 int loop_count = 0;
4429 if (is_windows_9x () == TRUE || !is_symlink (file))
4430 return (char *)file;
4432 if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0)
4433 return (char *)file;
4435 target[0] = '\0';
4436 do {
4438 /* Remove trailing slashes, as we want to resolve the last
4439 non-trivial part of the link name. */
4440 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
4441 link[link_len--] = '\0';
4443 res = readlink (link, target, MAX_PATH);
4444 if (res > 0)
4446 target[res] = '\0';
4447 if (!(IS_DEVICE_SEP (target[1])
4448 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
4450 /* Target is relative. Append it to the directory part of
4451 the symlink, then copy the result back to target. */
4452 char *p = link + link_len;
4454 while (p > link && !IS_ANY_SEP (p[-1]))
4455 p--;
4456 strcpy (p, target);
4457 strcpy (target, link);
4459 /* Resolve any "." and ".." to get a fully-qualified file name
4460 in link[] again. */
4461 link_len = GetFullPathName (target, MAX_PATH, link, NULL);
4463 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
4465 if (loop_count > 100)
4466 errno = ELOOP;
4468 if (target[0] == '\0') /* not a single call to readlink succeeded */
4469 return (char *)file;
4470 return target;
4473 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
4474 have a fixed max size for file names, so we don't need the kind of
4475 alloc/malloc/realloc dance the gnulib version does. We also don't
4476 support FD-relative symlinks. */
4477 char *
4478 careadlinkat (int fd, char const *filename,
4479 char *buffer, size_t buffer_size,
4480 struct allocator const *alloc,
4481 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
4483 char linkname[MAX_PATH];
4484 ssize_t link_size;
4486 if (fd != AT_FDCWD)
4488 errno = EINVAL;
4489 return NULL;
4492 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
4494 if (link_size > 0)
4496 char *retval = buffer;
4498 linkname[link_size++] = '\0';
4499 if (link_size > buffer_size)
4500 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
4501 if (retval)
4502 memcpy (retval, linkname, link_size);
4504 return retval;
4506 return NULL;
4509 ssize_t
4510 careadlinkatcwd (int fd, char const *filename, char *buffer,
4511 size_t buffer_size)
4513 (void) fd;
4514 return readlink (filename, buffer, buffer_size);
4518 /* Support for browsing other processes and their attributes. See
4519 process.c for the Lisp bindings. */
4521 /* Helper wrapper functions. */
4523 static HANDLE WINAPI
4524 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
4526 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
4528 if (g_b_init_create_toolhelp32_snapshot == 0)
4530 g_b_init_create_toolhelp32_snapshot = 1;
4531 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
4532 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4533 "CreateToolhelp32Snapshot");
4535 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
4537 return INVALID_HANDLE_VALUE;
4539 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
4542 static BOOL WINAPI
4543 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
4545 static Process32First_Proc s_pfn_Process32_First = NULL;
4547 if (g_b_init_process32_first == 0)
4549 g_b_init_process32_first = 1;
4550 s_pfn_Process32_First = (Process32First_Proc)
4551 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4552 "Process32First");
4554 if (s_pfn_Process32_First == NULL)
4556 return FALSE;
4558 return (s_pfn_Process32_First (hSnapshot, lppe));
4561 static BOOL WINAPI
4562 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
4564 static Process32Next_Proc s_pfn_Process32_Next = NULL;
4566 if (g_b_init_process32_next == 0)
4568 g_b_init_process32_next = 1;
4569 s_pfn_Process32_Next = (Process32Next_Proc)
4570 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4571 "Process32Next");
4573 if (s_pfn_Process32_Next == NULL)
4575 return FALSE;
4577 return (s_pfn_Process32_Next (hSnapshot, lppe));
4580 static BOOL WINAPI
4581 open_thread_token (HANDLE ThreadHandle,
4582 DWORD DesiredAccess,
4583 BOOL OpenAsSelf,
4584 PHANDLE TokenHandle)
4586 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
4587 HMODULE hm_advapi32 = NULL;
4588 if (is_windows_9x () == TRUE)
4590 SetLastError (ERROR_NOT_SUPPORTED);
4591 return FALSE;
4593 if (g_b_init_open_thread_token == 0)
4595 g_b_init_open_thread_token = 1;
4596 hm_advapi32 = LoadLibrary ("Advapi32.dll");
4597 s_pfn_Open_Thread_Token =
4598 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
4600 if (s_pfn_Open_Thread_Token == NULL)
4602 SetLastError (ERROR_NOT_SUPPORTED);
4603 return FALSE;
4605 return (
4606 s_pfn_Open_Thread_Token (
4607 ThreadHandle,
4608 DesiredAccess,
4609 OpenAsSelf,
4610 TokenHandle)
4614 static BOOL WINAPI
4615 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
4617 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
4618 HMODULE hm_advapi32 = NULL;
4619 if (is_windows_9x () == TRUE)
4621 return FALSE;
4623 if (g_b_init_impersonate_self == 0)
4625 g_b_init_impersonate_self = 1;
4626 hm_advapi32 = LoadLibrary ("Advapi32.dll");
4627 s_pfn_Impersonate_Self =
4628 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
4630 if (s_pfn_Impersonate_Self == NULL)
4632 return FALSE;
4634 return s_pfn_Impersonate_Self (ImpersonationLevel);
4637 static BOOL WINAPI
4638 revert_to_self (void)
4640 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
4641 HMODULE hm_advapi32 = NULL;
4642 if (is_windows_9x () == TRUE)
4644 return FALSE;
4646 if (g_b_init_revert_to_self == 0)
4648 g_b_init_revert_to_self = 1;
4649 hm_advapi32 = LoadLibrary ("Advapi32.dll");
4650 s_pfn_Revert_To_Self =
4651 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
4653 if (s_pfn_Revert_To_Self == NULL)
4655 return FALSE;
4657 return s_pfn_Revert_To_Self ();
4660 static BOOL WINAPI
4661 get_process_memory_info (HANDLE h_proc,
4662 PPROCESS_MEMORY_COUNTERS mem_counters,
4663 DWORD bufsize)
4665 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
4666 HMODULE hm_psapi = NULL;
4667 if (is_windows_9x () == TRUE)
4669 return FALSE;
4671 if (g_b_init_get_process_memory_info == 0)
4673 g_b_init_get_process_memory_info = 1;
4674 hm_psapi = LoadLibrary ("Psapi.dll");
4675 if (hm_psapi)
4676 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
4677 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
4679 if (s_pfn_Get_Process_Memory_Info == NULL)
4681 return FALSE;
4683 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
4686 static BOOL WINAPI
4687 get_process_working_set_size (HANDLE h_proc,
4688 PSIZE_T minrss,
4689 PSIZE_T maxrss)
4691 static GetProcessWorkingSetSize_Proc
4692 s_pfn_Get_Process_Working_Set_Size = NULL;
4694 if (is_windows_9x () == TRUE)
4696 return FALSE;
4698 if (g_b_init_get_process_working_set_size == 0)
4700 g_b_init_get_process_working_set_size = 1;
4701 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
4702 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4703 "GetProcessWorkingSetSize");
4705 if (s_pfn_Get_Process_Working_Set_Size == NULL)
4707 return FALSE;
4709 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
4712 static BOOL WINAPI
4713 global_memory_status (MEMORYSTATUS *buf)
4715 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
4717 if (is_windows_9x () == TRUE)
4719 return FALSE;
4721 if (g_b_init_global_memory_status == 0)
4723 g_b_init_global_memory_status = 1;
4724 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
4725 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4726 "GlobalMemoryStatus");
4728 if (s_pfn_Global_Memory_Status == NULL)
4730 return FALSE;
4732 return s_pfn_Global_Memory_Status (buf);
4735 static BOOL WINAPI
4736 global_memory_status_ex (MEMORY_STATUS_EX *buf)
4738 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
4740 if (is_windows_9x () == TRUE)
4742 return FALSE;
4744 if (g_b_init_global_memory_status_ex == 0)
4746 g_b_init_global_memory_status_ex = 1;
4747 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
4748 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4749 "GlobalMemoryStatusEx");
4751 if (s_pfn_Global_Memory_Status_Ex == NULL)
4753 return FALSE;
4755 return s_pfn_Global_Memory_Status_Ex (buf);
4758 Lisp_Object
4759 list_system_processes (void)
4761 struct gcpro gcpro1;
4762 Lisp_Object proclist = Qnil;
4763 HANDLE h_snapshot;
4765 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4767 if (h_snapshot != INVALID_HANDLE_VALUE)
4769 PROCESSENTRY32 proc_entry;
4770 DWORD proc_id;
4771 BOOL res;
4773 GCPRO1 (proclist);
4775 proc_entry.dwSize = sizeof (PROCESSENTRY32);
4776 for (res = process32_first (h_snapshot, &proc_entry); res;
4777 res = process32_next (h_snapshot, &proc_entry))
4779 proc_id = proc_entry.th32ProcessID;
4780 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
4783 CloseHandle (h_snapshot);
4784 UNGCPRO;
4785 proclist = Fnreverse (proclist);
4788 return proclist;
4791 static int
4792 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
4794 TOKEN_PRIVILEGES priv;
4795 DWORD priv_size = sizeof (priv);
4796 DWORD opriv_size = sizeof (*old_priv);
4797 HANDLE h_token = NULL;
4798 HANDLE h_thread = GetCurrentThread ();
4799 int ret_val = 0;
4800 BOOL res;
4802 res = open_thread_token (h_thread,
4803 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4804 FALSE, &h_token);
4805 if (!res && GetLastError () == ERROR_NO_TOKEN)
4807 if (impersonate_self (SecurityImpersonation))
4808 res = open_thread_token (h_thread,
4809 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4810 FALSE, &h_token);
4812 if (res)
4814 priv.PrivilegeCount = 1;
4815 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
4816 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
4817 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
4818 old_priv, &opriv_size)
4819 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
4820 ret_val = 1;
4822 if (h_token)
4823 CloseHandle (h_token);
4825 return ret_val;
4828 static int
4829 restore_privilege (TOKEN_PRIVILEGES *priv)
4831 DWORD priv_size = sizeof (*priv);
4832 HANDLE h_token = NULL;
4833 int ret_val = 0;
4835 if (open_thread_token (GetCurrentThread (),
4836 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4837 FALSE, &h_token))
4839 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
4840 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
4841 ret_val = 1;
4843 if (h_token)
4844 CloseHandle (h_token);
4846 return ret_val;
4849 static Lisp_Object
4850 ltime (ULONGLONG time_100ns)
4852 ULONGLONG time_sec = time_100ns / 10000000;
4853 int subsec = time_100ns % 10000000;
4854 return list4 (make_number (time_sec >> 16),
4855 make_number (time_sec & 0xffff),
4856 make_number (subsec / 10),
4857 make_number (subsec % 10 * 100000));
4860 #define U64_TO_LISP_TIME(time) ltime (time)
4862 static int
4863 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
4864 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
4865 double *pcpu)
4867 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
4868 ULONGLONG tem1, tem2, tem3, tem;
4870 if (!h_proc
4871 || !get_process_times_fn
4872 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
4873 &ft_kernel, &ft_user))
4874 return 0;
4876 GetSystemTimeAsFileTime (&ft_current);
4878 FILETIME_TO_U64 (tem1, ft_kernel);
4879 *stime = U64_TO_LISP_TIME (tem1);
4881 FILETIME_TO_U64 (tem2, ft_user);
4882 *utime = U64_TO_LISP_TIME (tem2);
4884 tem3 = tem1 + tem2;
4885 *ttime = U64_TO_LISP_TIME (tem3);
4887 FILETIME_TO_U64 (tem, ft_creation);
4888 /* Process no 4 (System) returns zero creation time. */
4889 if (tem)
4890 tem -= utc_base;
4891 *ctime = U64_TO_LISP_TIME (tem);
4893 if (tem)
4895 FILETIME_TO_U64 (tem3, ft_current);
4896 tem = (tem3 - utc_base) - tem;
4898 *etime = U64_TO_LISP_TIME (tem);
4900 if (tem)
4902 *pcpu = 100.0 * (tem1 + tem2) / tem;
4903 if (*pcpu > 100)
4904 *pcpu = 100.0;
4906 else
4907 *pcpu = 0;
4909 return 1;
4912 Lisp_Object
4913 system_process_attributes (Lisp_Object pid)
4915 struct gcpro gcpro1, gcpro2, gcpro3;
4916 Lisp_Object attrs = Qnil;
4917 Lisp_Object cmd_str, decoded_cmd, tem;
4918 HANDLE h_snapshot, h_proc;
4919 DWORD proc_id;
4920 int found_proc = 0;
4921 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
4922 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
4923 DWORD glength = sizeof (gname);
4924 HANDLE token = NULL;
4925 SID_NAME_USE user_type;
4926 unsigned char *buf = NULL;
4927 DWORD blen = 0;
4928 TOKEN_USER user_token;
4929 TOKEN_PRIMARY_GROUP group_token;
4930 unsigned euid;
4931 unsigned egid;
4932 PROCESS_MEMORY_COUNTERS mem;
4933 PROCESS_MEMORY_COUNTERS_EX mem_ex;
4934 SIZE_T minrss, maxrss;
4935 MEMORYSTATUS memst;
4936 MEMORY_STATUS_EX memstex;
4937 double totphys = 0.0;
4938 Lisp_Object ctime, stime, utime, etime, ttime;
4939 double pcpu;
4940 BOOL result = FALSE;
4942 CHECK_NUMBER_OR_FLOAT (pid);
4943 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
4945 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4947 GCPRO3 (attrs, decoded_cmd, tem);
4949 if (h_snapshot != INVALID_HANDLE_VALUE)
4951 PROCESSENTRY32 pe;
4952 BOOL res;
4954 pe.dwSize = sizeof (PROCESSENTRY32);
4955 for (res = process32_first (h_snapshot, &pe); res;
4956 res = process32_next (h_snapshot, &pe))
4958 if (proc_id == pe.th32ProcessID)
4960 if (proc_id == 0)
4961 decoded_cmd = build_string ("Idle");
4962 else
4964 /* Decode the command name from locale-specific
4965 encoding. */
4966 cmd_str = make_unibyte_string (pe.szExeFile,
4967 strlen (pe.szExeFile));
4968 decoded_cmd =
4969 code_convert_string_norecord (cmd_str,
4970 Vlocale_coding_system, 0);
4972 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
4973 attrs = Fcons (Fcons (Qppid,
4974 make_fixnum_or_float (pe.th32ParentProcessID)),
4975 attrs);
4976 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
4977 attrs);
4978 attrs = Fcons (Fcons (Qthcount,
4979 make_fixnum_or_float (pe.cntThreads)),
4980 attrs);
4981 found_proc = 1;
4982 break;
4986 CloseHandle (h_snapshot);
4989 if (!found_proc)
4991 UNGCPRO;
4992 return Qnil;
4995 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4996 FALSE, proc_id);
4997 /* If we were denied a handle to the process, try again after
4998 enabling the SeDebugPrivilege in our process. */
4999 if (!h_proc)
5001 TOKEN_PRIVILEGES priv_current;
5003 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
5005 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
5006 FALSE, proc_id);
5007 restore_privilege (&priv_current);
5008 revert_to_self ();
5011 if (h_proc)
5013 result = open_process_token (h_proc, TOKEN_QUERY, &token);
5014 if (result)
5016 result = get_token_information (token, TokenUser, NULL, 0, &blen);
5017 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
5019 buf = xmalloc (blen);
5020 result = get_token_information (token, TokenUser,
5021 (LPVOID)buf, blen, &needed);
5022 if (result)
5024 memcpy (&user_token, buf, sizeof (user_token));
5025 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
5027 euid = get_rid (user_token.User.Sid);
5028 result = lookup_account_sid (NULL, user_token.User.Sid,
5029 uname, &ulength,
5030 domain, &dlength,
5031 &user_type);
5032 if (result)
5033 w32_add_to_cache (user_token.User.Sid, euid, uname);
5034 else
5036 strcpy (uname, "unknown");
5037 result = TRUE;
5040 ulength = strlen (uname);
5044 if (result)
5046 /* Determine a reasonable euid and gid values. */
5047 if (xstrcasecmp ("administrator", uname) == 0)
5049 euid = 500; /* well-known Administrator uid */
5050 egid = 513; /* well-known None gid */
5052 else
5054 /* Get group id and name. */
5055 result = get_token_information (token, TokenPrimaryGroup,
5056 (LPVOID)buf, blen, &needed);
5057 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
5059 buf = xrealloc (buf, blen = needed);
5060 result = get_token_information (token, TokenPrimaryGroup,
5061 (LPVOID)buf, blen, &needed);
5063 if (result)
5065 memcpy (&group_token, buf, sizeof (group_token));
5066 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
5068 egid = get_rid (group_token.PrimaryGroup);
5069 dlength = sizeof (domain);
5070 result =
5071 lookup_account_sid (NULL, group_token.PrimaryGroup,
5072 gname, &glength, NULL, &dlength,
5073 &user_type);
5074 if (result)
5075 w32_add_to_cache (group_token.PrimaryGroup,
5076 egid, gname);
5077 else
5079 strcpy (gname, "None");
5080 result = TRUE;
5083 glength = strlen (gname);
5087 xfree (buf);
5089 if (!result)
5091 if (!is_windows_9x ())
5093 /* We couldn't open the process token, presumably because of
5094 insufficient access rights. Assume this process is run
5095 by the system. */
5096 strcpy (uname, "SYSTEM");
5097 strcpy (gname, "None");
5098 euid = 18; /* SYSTEM */
5099 egid = 513; /* None */
5100 glength = strlen (gname);
5101 ulength = strlen (uname);
5103 /* If we are running under Windows 9X, where security calls are
5104 not supported, we assume all processes are run by the current
5105 user. */
5106 else if (GetUserName (uname, &ulength))
5108 if (xstrcasecmp ("administrator", uname) == 0)
5109 euid = 0;
5110 else
5111 euid = 123;
5112 egid = euid;
5113 strcpy (gname, "None");
5114 glength = strlen (gname);
5115 ulength = strlen (uname);
5117 else
5119 euid = 123;
5120 egid = 123;
5121 strcpy (uname, "administrator");
5122 ulength = strlen (uname);
5123 strcpy (gname, "None");
5124 glength = strlen (gname);
5126 if (token)
5127 CloseHandle (token);
5130 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
5131 tem = make_unibyte_string (uname, ulength);
5132 attrs = Fcons (Fcons (Quser,
5133 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
5134 attrs);
5135 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
5136 tem = make_unibyte_string (gname, glength);
5137 attrs = Fcons (Fcons (Qgroup,
5138 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
5139 attrs);
5141 if (global_memory_status_ex (&memstex))
5142 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
5143 totphys = memstex.ullTotalPhys / 1024.0;
5144 #else
5145 /* Visual Studio 6 cannot convert an unsigned __int64 type to
5146 double, so we need to do this for it... */
5148 DWORD tot_hi = memstex.ullTotalPhys >> 32;
5149 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
5150 DWORD tot_lo = memstex.ullTotalPhys % 1024;
5152 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
5154 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5155 else if (global_memory_status (&memst))
5156 totphys = memst.dwTotalPhys / 1024.0;
5158 if (h_proc
5159 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
5160 sizeof (mem_ex)))
5162 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
5164 attrs = Fcons (Fcons (Qmajflt,
5165 make_fixnum_or_float (mem_ex.PageFaultCount)),
5166 attrs);
5167 attrs = Fcons (Fcons (Qvsize,
5168 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
5169 attrs);
5170 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
5171 if (totphys)
5172 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
5174 else if (h_proc
5175 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
5177 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
5179 attrs = Fcons (Fcons (Qmajflt,
5180 make_fixnum_or_float (mem.PageFaultCount)),
5181 attrs);
5182 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
5183 if (totphys)
5184 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
5186 else if (h_proc
5187 && get_process_working_set_size (h_proc, &minrss, &maxrss))
5189 DWORD rss = maxrss / 1024;
5191 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
5192 if (totphys)
5193 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
5196 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
5198 attrs = Fcons (Fcons (Qutime, utime), attrs);
5199 attrs = Fcons (Fcons (Qstime, stime), attrs);
5200 attrs = Fcons (Fcons (Qtime, ttime), attrs);
5201 attrs = Fcons (Fcons (Qstart, ctime), attrs);
5202 attrs = Fcons (Fcons (Qetime, etime), attrs);
5203 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
5206 /* FIXME: Retrieve command line by walking the PEB of the process. */
5208 if (h_proc)
5209 CloseHandle (h_proc);
5210 UNGCPRO;
5211 return attrs;
5215 /* Wrappers for winsock functions to map between our file descriptors
5216 and winsock's handles; also set h_errno for convenience.
5218 To allow Emacs to run on systems which don't have winsock support
5219 installed, we dynamically link to winsock on startup if present, and
5220 otherwise provide the minimum necessary functionality
5221 (eg. gethostname). */
5223 /* function pointers for relevant socket functions */
5224 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
5225 void (PASCAL *pfn_WSASetLastError) (int iError);
5226 int (PASCAL *pfn_WSAGetLastError) (void);
5227 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
5228 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
5229 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
5230 int (PASCAL *pfn_socket) (int af, int type, int protocol);
5231 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
5232 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
5233 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
5234 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
5235 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
5236 int (PASCAL *pfn_closesocket) (SOCKET s);
5237 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
5238 int (PASCAL *pfn_WSACleanup) (void);
5240 u_short (PASCAL *pfn_htons) (u_short hostshort);
5241 u_short (PASCAL *pfn_ntohs) (u_short netshort);
5242 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
5243 int (PASCAL *pfn_gethostname) (char * name, int namelen);
5244 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
5245 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
5246 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
5247 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
5248 const char * optval, int optlen);
5249 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
5250 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
5251 int * namelen);
5252 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
5253 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
5254 struct sockaddr * from, int * fromlen);
5255 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
5256 const struct sockaddr * to, int tolen);
5258 /* SetHandleInformation is only needed to make sockets non-inheritable. */
5259 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
5260 #ifndef HANDLE_FLAG_INHERIT
5261 #define HANDLE_FLAG_INHERIT 1
5262 #endif
5264 HANDLE winsock_lib;
5265 static int winsock_inuse;
5267 BOOL
5268 term_winsock (void)
5270 if (winsock_lib != NULL && winsock_inuse == 0)
5272 /* Not sure what would cause WSAENETDOWN, or even if it can happen
5273 after WSAStartup returns successfully, but it seems reasonable
5274 to allow unloading winsock anyway in that case. */
5275 if (pfn_WSACleanup () == 0 ||
5276 pfn_WSAGetLastError () == WSAENETDOWN)
5278 if (FreeLibrary (winsock_lib))
5279 winsock_lib = NULL;
5280 return TRUE;
5283 return FALSE;
5286 BOOL
5287 init_winsock (int load_now)
5289 WSADATA winsockData;
5291 if (winsock_lib != NULL)
5292 return TRUE;
5294 pfn_SetHandleInformation
5295 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
5296 "SetHandleInformation");
5298 winsock_lib = LoadLibrary ("Ws2_32.dll");
5300 if (winsock_lib != NULL)
5302 /* dynamically link to socket functions */
5304 #define LOAD_PROC(fn) \
5305 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
5306 goto fail;
5308 LOAD_PROC (WSAStartup);
5309 LOAD_PROC (WSASetLastError);
5310 LOAD_PROC (WSAGetLastError);
5311 LOAD_PROC (WSAEventSelect);
5312 LOAD_PROC (WSACreateEvent);
5313 LOAD_PROC (WSACloseEvent);
5314 LOAD_PROC (socket);
5315 LOAD_PROC (bind);
5316 LOAD_PROC (connect);
5317 LOAD_PROC (ioctlsocket);
5318 LOAD_PROC (recv);
5319 LOAD_PROC (send);
5320 LOAD_PROC (closesocket);
5321 LOAD_PROC (shutdown);
5322 LOAD_PROC (htons);
5323 LOAD_PROC (ntohs);
5324 LOAD_PROC (inet_addr);
5325 LOAD_PROC (gethostname);
5326 LOAD_PROC (gethostbyname);
5327 LOAD_PROC (getservbyname);
5328 LOAD_PROC (getpeername);
5329 LOAD_PROC (WSACleanup);
5330 LOAD_PROC (setsockopt);
5331 LOAD_PROC (listen);
5332 LOAD_PROC (getsockname);
5333 LOAD_PROC (accept);
5334 LOAD_PROC (recvfrom);
5335 LOAD_PROC (sendto);
5336 #undef LOAD_PROC
5338 /* specify version 1.1 of winsock */
5339 if (pfn_WSAStartup (0x101, &winsockData) == 0)
5341 if (winsockData.wVersion != 0x101)
5342 goto fail;
5344 if (!load_now)
5346 /* Report that winsock exists and is usable, but leave
5347 socket functions disabled. I am assuming that calling
5348 WSAStartup does not require any network interaction,
5349 and in particular does not cause or require a dial-up
5350 connection to be established. */
5352 pfn_WSACleanup ();
5353 FreeLibrary (winsock_lib);
5354 winsock_lib = NULL;
5356 winsock_inuse = 0;
5357 return TRUE;
5360 fail:
5361 FreeLibrary (winsock_lib);
5362 winsock_lib = NULL;
5365 return FALSE;
5369 int h_errno = 0;
5371 /* function to set h_errno for compatibility; map winsock error codes to
5372 normal system codes where they overlap (non-overlapping definitions
5373 are already in <sys/socket.h> */
5374 static void
5375 set_errno (void)
5377 if (winsock_lib == NULL)
5378 h_errno = EINVAL;
5379 else
5380 h_errno = pfn_WSAGetLastError ();
5382 switch (h_errno)
5384 case WSAEACCES: h_errno = EACCES; break;
5385 case WSAEBADF: h_errno = EBADF; break;
5386 case WSAEFAULT: h_errno = EFAULT; break;
5387 case WSAEINTR: h_errno = EINTR; break;
5388 case WSAEINVAL: h_errno = EINVAL; break;
5389 case WSAEMFILE: h_errno = EMFILE; break;
5390 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
5391 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
5393 errno = h_errno;
5396 static void
5397 check_errno (void)
5399 if (h_errno == 0 && winsock_lib != NULL)
5400 pfn_WSASetLastError (0);
5403 /* Extend strerror to handle the winsock-specific error codes. */
5404 struct {
5405 int errnum;
5406 char * msg;
5407 } _wsa_errlist[] = {
5408 {WSAEINTR , "Interrupted function call"},
5409 {WSAEBADF , "Bad file descriptor"},
5410 {WSAEACCES , "Permission denied"},
5411 {WSAEFAULT , "Bad address"},
5412 {WSAEINVAL , "Invalid argument"},
5413 {WSAEMFILE , "Too many open files"},
5415 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
5416 {WSAEINPROGRESS , "Operation now in progress"},
5417 {WSAEALREADY , "Operation already in progress"},
5418 {WSAENOTSOCK , "Socket operation on non-socket"},
5419 {WSAEDESTADDRREQ , "Destination address required"},
5420 {WSAEMSGSIZE , "Message too long"},
5421 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
5422 {WSAENOPROTOOPT , "Bad protocol option"},
5423 {WSAEPROTONOSUPPORT , "Protocol not supported"},
5424 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
5425 {WSAEOPNOTSUPP , "Operation not supported"},
5426 {WSAEPFNOSUPPORT , "Protocol family not supported"},
5427 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
5428 {WSAEADDRINUSE , "Address already in use"},
5429 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
5430 {WSAENETDOWN , "Network is down"},
5431 {WSAENETUNREACH , "Network is unreachable"},
5432 {WSAENETRESET , "Network dropped connection on reset"},
5433 {WSAECONNABORTED , "Software caused connection abort"},
5434 {WSAECONNRESET , "Connection reset by peer"},
5435 {WSAENOBUFS , "No buffer space available"},
5436 {WSAEISCONN , "Socket is already connected"},
5437 {WSAENOTCONN , "Socket is not connected"},
5438 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
5439 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
5440 {WSAETIMEDOUT , "Connection timed out"},
5441 {WSAECONNREFUSED , "Connection refused"},
5442 {WSAELOOP , "Network loop"}, /* not sure */
5443 {WSAENAMETOOLONG , "Name is too long"},
5444 {WSAEHOSTDOWN , "Host is down"},
5445 {WSAEHOSTUNREACH , "No route to host"},
5446 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
5447 {WSAEPROCLIM , "Too many processes"},
5448 {WSAEUSERS , "Too many users"}, /* not sure */
5449 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
5450 {WSAESTALE , "Data is stale"}, /* not sure */
5451 {WSAEREMOTE , "Remote error"}, /* not sure */
5453 {WSASYSNOTREADY , "Network subsystem is unavailable"},
5454 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
5455 {WSANOTINITIALISED , "Winsock not initialized successfully"},
5456 {WSAEDISCON , "Graceful shutdown in progress"},
5457 #ifdef WSAENOMORE
5458 {WSAENOMORE , "No more operations allowed"}, /* not sure */
5459 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
5460 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
5461 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
5462 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
5463 {WSASYSCALLFAILURE , "System call failure"},
5464 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
5465 {WSATYPE_NOT_FOUND , "Class type not found"},
5466 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
5467 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
5468 {WSAEREFUSED , "Operation refused"}, /* not sure */
5469 #endif
5471 {WSAHOST_NOT_FOUND , "Host not found"},
5472 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
5473 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
5474 {WSANO_DATA , "Valid name, no data record of requested type"},
5476 {-1, NULL}
5479 char *
5480 sys_strerror (int error_no)
5482 int i;
5483 static char unknown_msg[40];
5485 if (error_no >= 0 && error_no < sys_nerr)
5486 return sys_errlist[error_no];
5488 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
5489 if (_wsa_errlist[i].errnum == error_no)
5490 return _wsa_errlist[i].msg;
5492 sprintf (unknown_msg, "Unidentified error: %d", error_no);
5493 return unknown_msg;
5496 /* [andrewi 3-May-96] I've had conflicting results using both methods,
5497 but I believe the method of keeping the socket handle separate (and
5498 insuring it is not inheritable) is the correct one. */
5500 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
5502 static int socket_to_fd (SOCKET s);
5505 sys_socket (int af, int type, int protocol)
5507 SOCKET s;
5509 if (winsock_lib == NULL)
5511 h_errno = ENETDOWN;
5512 return INVALID_SOCKET;
5515 check_errno ();
5517 /* call the real socket function */
5518 s = pfn_socket (af, type, protocol);
5520 if (s != INVALID_SOCKET)
5521 return socket_to_fd (s);
5523 set_errno ();
5524 return -1;
5527 /* Convert a SOCKET to a file descriptor. */
5528 static int
5529 socket_to_fd (SOCKET s)
5531 int fd;
5532 child_process * cp;
5534 /* Although under NT 3.5 _open_osfhandle will accept a socket
5535 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
5536 that does not work under NT 3.1. However, we can get the same
5537 effect by using a backdoor function to replace an existing
5538 descriptor handle with the one we want. */
5540 /* allocate a file descriptor (with appropriate flags) */
5541 fd = _open ("NUL:", _O_RDWR);
5542 if (fd >= 0)
5544 /* Make a non-inheritable copy of the socket handle. Note
5545 that it is possible that sockets aren't actually kernel
5546 handles, which appears to be the case on Windows 9x when
5547 the MS Proxy winsock client is installed. */
5549 /* Apparently there is a bug in NT 3.51 with some service
5550 packs, which prevents using DuplicateHandle to make a
5551 socket handle non-inheritable (causes WSACleanup to
5552 hang). The work-around is to use SetHandleInformation
5553 instead if it is available and implemented. */
5554 if (pfn_SetHandleInformation)
5556 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
5558 else
5560 HANDLE parent = GetCurrentProcess ();
5561 HANDLE new_s = INVALID_HANDLE_VALUE;
5563 if (DuplicateHandle (parent,
5564 (HANDLE) s,
5565 parent,
5566 &new_s,
5568 FALSE,
5569 DUPLICATE_SAME_ACCESS))
5571 /* It is possible that DuplicateHandle succeeds even
5572 though the socket wasn't really a kernel handle,
5573 because a real handle has the same value. So
5574 test whether the new handle really is a socket. */
5575 long nonblocking = 0;
5576 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
5578 pfn_closesocket (s);
5579 s = (SOCKET) new_s;
5581 else
5583 CloseHandle (new_s);
5588 fd_info[fd].hnd = (HANDLE) s;
5590 /* set our own internal flags */
5591 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
5593 cp = new_child ();
5594 if (cp)
5596 cp->fd = fd;
5597 cp->status = STATUS_READ_ACKNOWLEDGED;
5599 /* attach child_process to fd_info */
5600 if (fd_info[ fd ].cp != NULL)
5602 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
5603 emacs_abort ();
5606 fd_info[ fd ].cp = cp;
5608 /* success! */
5609 winsock_inuse++; /* count open sockets */
5610 return fd;
5613 /* clean up */
5614 _close (fd);
5616 pfn_closesocket (s);
5617 h_errno = EMFILE;
5618 return -1;
5622 sys_bind (int s, const struct sockaddr * addr, int namelen)
5624 if (winsock_lib == NULL)
5626 h_errno = ENOTSOCK;
5627 return SOCKET_ERROR;
5630 check_errno ();
5631 if (fd_info[s].flags & FILE_SOCKET)
5633 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
5634 if (rc == SOCKET_ERROR)
5635 set_errno ();
5636 return rc;
5638 h_errno = ENOTSOCK;
5639 return SOCKET_ERROR;
5643 sys_connect (int s, const struct sockaddr * name, int namelen)
5645 if (winsock_lib == NULL)
5647 h_errno = ENOTSOCK;
5648 return SOCKET_ERROR;
5651 check_errno ();
5652 if (fd_info[s].flags & FILE_SOCKET)
5654 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
5655 if (rc == SOCKET_ERROR)
5656 set_errno ();
5657 return rc;
5659 h_errno = ENOTSOCK;
5660 return SOCKET_ERROR;
5663 u_short
5664 sys_htons (u_short hostshort)
5666 return (winsock_lib != NULL) ?
5667 pfn_htons (hostshort) : hostshort;
5670 u_short
5671 sys_ntohs (u_short netshort)
5673 return (winsock_lib != NULL) ?
5674 pfn_ntohs (netshort) : netshort;
5677 unsigned long
5678 sys_inet_addr (const char * cp)
5680 return (winsock_lib != NULL) ?
5681 pfn_inet_addr (cp) : INADDR_NONE;
5685 sys_gethostname (char * name, int namelen)
5687 if (winsock_lib != NULL)
5688 return pfn_gethostname (name, namelen);
5690 if (namelen > MAX_COMPUTERNAME_LENGTH)
5691 return !GetComputerName (name, (DWORD *)&namelen);
5693 h_errno = EFAULT;
5694 return SOCKET_ERROR;
5697 struct hostent *
5698 sys_gethostbyname (const char * name)
5700 struct hostent * host;
5702 if (winsock_lib == NULL)
5704 h_errno = ENETDOWN;
5705 return NULL;
5708 check_errno ();
5709 host = pfn_gethostbyname (name);
5710 if (!host)
5711 set_errno ();
5712 return host;
5715 struct servent *
5716 sys_getservbyname (const char * name, const char * proto)
5718 struct servent * serv;
5720 if (winsock_lib == NULL)
5722 h_errno = ENETDOWN;
5723 return NULL;
5726 check_errno ();
5727 serv = pfn_getservbyname (name, proto);
5728 if (!serv)
5729 set_errno ();
5730 return serv;
5734 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
5736 if (winsock_lib == NULL)
5738 h_errno = ENETDOWN;
5739 return SOCKET_ERROR;
5742 check_errno ();
5743 if (fd_info[s].flags & FILE_SOCKET)
5745 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
5746 if (rc == SOCKET_ERROR)
5747 set_errno ();
5748 return rc;
5750 h_errno = ENOTSOCK;
5751 return SOCKET_ERROR;
5755 sys_shutdown (int s, int how)
5757 if (winsock_lib == NULL)
5759 h_errno = ENETDOWN;
5760 return SOCKET_ERROR;
5763 check_errno ();
5764 if (fd_info[s].flags & FILE_SOCKET)
5766 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
5767 if (rc == SOCKET_ERROR)
5768 set_errno ();
5769 return rc;
5771 h_errno = ENOTSOCK;
5772 return SOCKET_ERROR;
5776 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
5778 if (winsock_lib == NULL)
5780 h_errno = ENETDOWN;
5781 return SOCKET_ERROR;
5784 check_errno ();
5785 if (fd_info[s].flags & FILE_SOCKET)
5787 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
5788 (const char *)optval, optlen);
5789 if (rc == SOCKET_ERROR)
5790 set_errno ();
5791 return rc;
5793 h_errno = ENOTSOCK;
5794 return SOCKET_ERROR;
5798 sys_listen (int s, int backlog)
5800 if (winsock_lib == NULL)
5802 h_errno = ENETDOWN;
5803 return SOCKET_ERROR;
5806 check_errno ();
5807 if (fd_info[s].flags & FILE_SOCKET)
5809 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
5810 if (rc == SOCKET_ERROR)
5811 set_errno ();
5812 else
5813 fd_info[s].flags |= FILE_LISTEN;
5814 return rc;
5816 h_errno = ENOTSOCK;
5817 return SOCKET_ERROR;
5821 sys_getsockname (int s, struct sockaddr * name, int * namelen)
5823 if (winsock_lib == NULL)
5825 h_errno = ENETDOWN;
5826 return SOCKET_ERROR;
5829 check_errno ();
5830 if (fd_info[s].flags & FILE_SOCKET)
5832 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
5833 if (rc == SOCKET_ERROR)
5834 set_errno ();
5835 return rc;
5837 h_errno = ENOTSOCK;
5838 return SOCKET_ERROR;
5842 sys_accept (int s, struct sockaddr * addr, int * addrlen)
5844 if (winsock_lib == NULL)
5846 h_errno = ENETDOWN;
5847 return -1;
5850 check_errno ();
5851 if (fd_info[s].flags & FILE_LISTEN)
5853 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
5854 int fd = -1;
5855 if (t == INVALID_SOCKET)
5856 set_errno ();
5857 else
5858 fd = socket_to_fd (t);
5860 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
5861 ResetEvent (fd_info[s].cp->char_avail);
5862 return fd;
5864 h_errno = ENOTSOCK;
5865 return -1;
5869 sys_recvfrom (int s, char * buf, int len, int flags,
5870 struct sockaddr * from, int * fromlen)
5872 if (winsock_lib == NULL)
5874 h_errno = ENETDOWN;
5875 return SOCKET_ERROR;
5878 check_errno ();
5879 if (fd_info[s].flags & FILE_SOCKET)
5881 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
5882 if (rc == SOCKET_ERROR)
5883 set_errno ();
5884 return rc;
5886 h_errno = ENOTSOCK;
5887 return SOCKET_ERROR;
5891 sys_sendto (int s, const char * buf, int len, int flags,
5892 const struct sockaddr * to, int tolen)
5894 if (winsock_lib == NULL)
5896 h_errno = ENETDOWN;
5897 return SOCKET_ERROR;
5900 check_errno ();
5901 if (fd_info[s].flags & FILE_SOCKET)
5903 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
5904 if (rc == SOCKET_ERROR)
5905 set_errno ();
5906 return rc;
5908 h_errno = ENOTSOCK;
5909 return SOCKET_ERROR;
5912 /* Windows does not have an fcntl function. Provide an implementation
5913 solely for making sockets non-blocking. */
5915 fcntl (int s, int cmd, int options)
5917 if (winsock_lib == NULL)
5919 h_errno = ENETDOWN;
5920 return -1;
5923 check_errno ();
5924 if (fd_info[s].flags & FILE_SOCKET)
5926 if (cmd == F_SETFL && options == O_NONBLOCK)
5928 unsigned long nblock = 1;
5929 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
5930 if (rc == SOCKET_ERROR)
5931 set_errno ();
5932 /* Keep track of the fact that we set this to non-blocking. */
5933 fd_info[s].flags |= FILE_NDELAY;
5934 return rc;
5936 else
5938 h_errno = EINVAL;
5939 return SOCKET_ERROR;
5942 h_errno = ENOTSOCK;
5943 return SOCKET_ERROR;
5947 /* Shadow main io functions: we need to handle pipes and sockets more
5948 intelligently, and implement non-blocking mode as well. */
5951 sys_close (int fd)
5953 int rc;
5955 if (fd < 0)
5957 errno = EBADF;
5958 return -1;
5961 if (fd < MAXDESC && fd_info[fd].cp)
5963 child_process * cp = fd_info[fd].cp;
5965 fd_info[fd].cp = NULL;
5967 if (CHILD_ACTIVE (cp))
5969 /* if last descriptor to active child_process then cleanup */
5970 int i;
5971 for (i = 0; i < MAXDESC; i++)
5973 if (i == fd)
5974 continue;
5975 if (fd_info[i].cp == cp)
5976 break;
5978 if (i == MAXDESC)
5980 if (fd_info[fd].flags & FILE_SOCKET)
5982 if (winsock_lib == NULL) emacs_abort ();
5984 pfn_shutdown (SOCK_HANDLE (fd), 2);
5985 rc = pfn_closesocket (SOCK_HANDLE (fd));
5987 winsock_inuse--; /* count open sockets */
5989 delete_child (cp);
5994 /* Note that sockets do not need special treatment here (at least on
5995 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5996 closesocket is equivalent to CloseHandle, which is to be expected
5997 because socket handles are fully fledged kernel handles. */
5998 rc = _close (fd);
6000 if (rc == 0 && fd < MAXDESC)
6001 fd_info[fd].flags = 0;
6003 return rc;
6007 sys_dup (int fd)
6009 int new_fd;
6011 new_fd = _dup (fd);
6012 if (new_fd >= 0 && new_fd < MAXDESC)
6014 /* duplicate our internal info as well */
6015 fd_info[new_fd] = fd_info[fd];
6017 return new_fd;
6021 sys_dup2 (int src, int dst)
6023 int rc;
6025 if (dst < 0 || dst >= MAXDESC)
6027 errno = EBADF;
6028 return -1;
6031 /* make sure we close the destination first if it's a pipe or socket */
6032 if (src != dst && fd_info[dst].flags != 0)
6033 sys_close (dst);
6035 rc = _dup2 (src, dst);
6036 if (rc == 0)
6038 /* duplicate our internal info as well */
6039 fd_info[dst] = fd_info[src];
6041 return rc;
6044 /* Unix pipe() has only one arg */
6046 sys_pipe (int * phandles)
6048 int rc;
6049 unsigned flags;
6051 /* make pipe handles non-inheritable; when we spawn a child, we
6052 replace the relevant handle with an inheritable one. Also put
6053 pipes into binary mode; we will do text mode translation ourselves
6054 if required. */
6055 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
6057 if (rc == 0)
6059 /* Protect against overflow, since Windows can open more handles than
6060 our fd_info array has room for. */
6061 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
6063 _close (phandles[0]);
6064 _close (phandles[1]);
6065 rc = -1;
6067 else
6069 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
6070 fd_info[phandles[0]].flags = flags;
6072 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
6073 fd_info[phandles[1]].flags = flags;
6077 return rc;
6080 /* Function to do blocking read of one byte, needed to implement
6081 select. It is only allowed on sockets and pipes. */
6083 _sys_read_ahead (int fd)
6085 child_process * cp;
6086 int rc;
6088 if (fd < 0 || fd >= MAXDESC)
6089 return STATUS_READ_ERROR;
6091 cp = fd_info[fd].cp;
6093 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
6094 return STATUS_READ_ERROR;
6096 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
6097 || (fd_info[fd].flags & FILE_READ) == 0)
6099 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
6100 emacs_abort ();
6103 cp->status = STATUS_READ_IN_PROGRESS;
6105 if (fd_info[fd].flags & FILE_PIPE)
6107 rc = _read (fd, &cp->chr, sizeof (char));
6109 /* Give subprocess time to buffer some more output for us before
6110 reporting that input is available; we need this because Windows 95
6111 connects DOS programs to pipes by making the pipe appear to be
6112 the normal console stdout - as a result most DOS programs will
6113 write to stdout without buffering, ie. one character at a
6114 time. Even some W32 programs do this - "dir" in a command
6115 shell on NT is very slow if we don't do this. */
6116 if (rc > 0)
6118 int wait = w32_pipe_read_delay;
6120 if (wait > 0)
6121 Sleep (wait);
6122 else if (wait < 0)
6123 while (++wait <= 0)
6124 /* Yield remainder of our time slice, effectively giving a
6125 temporary priority boost to the child process. */
6126 Sleep (0);
6129 else if (fd_info[fd].flags & FILE_SERIAL)
6131 HANDLE hnd = fd_info[fd].hnd;
6132 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
6133 COMMTIMEOUTS ct;
6135 /* Configure timeouts for blocking read. */
6136 if (!GetCommTimeouts (hnd, &ct))
6137 return STATUS_READ_ERROR;
6138 ct.ReadIntervalTimeout = 0;
6139 ct.ReadTotalTimeoutMultiplier = 0;
6140 ct.ReadTotalTimeoutConstant = 0;
6141 if (!SetCommTimeouts (hnd, &ct))
6142 return STATUS_READ_ERROR;
6144 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
6146 if (GetLastError () != ERROR_IO_PENDING)
6147 return STATUS_READ_ERROR;
6148 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
6149 return STATUS_READ_ERROR;
6152 else if (fd_info[fd].flags & FILE_SOCKET)
6154 unsigned long nblock = 0;
6155 /* We always want this to block, so temporarily disable NDELAY. */
6156 if (fd_info[fd].flags & FILE_NDELAY)
6157 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6159 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
6161 if (fd_info[fd].flags & FILE_NDELAY)
6163 nblock = 1;
6164 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6168 if (rc == sizeof (char))
6169 cp->status = STATUS_READ_SUCCEEDED;
6170 else
6171 cp->status = STATUS_READ_FAILED;
6173 return cp->status;
6177 _sys_wait_accept (int fd)
6179 HANDLE hEv;
6180 child_process * cp;
6181 int rc;
6183 if (fd < 0 || fd >= MAXDESC)
6184 return STATUS_READ_ERROR;
6186 cp = fd_info[fd].cp;
6188 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
6189 return STATUS_READ_ERROR;
6191 cp->status = STATUS_READ_FAILED;
6193 hEv = pfn_WSACreateEvent ();
6194 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
6195 if (rc != SOCKET_ERROR)
6197 rc = WaitForSingleObject (hEv, INFINITE);
6198 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
6199 if (rc == WAIT_OBJECT_0)
6200 cp->status = STATUS_READ_SUCCEEDED;
6202 pfn_WSACloseEvent (hEv);
6204 return cp->status;
6208 sys_read (int fd, char * buffer, unsigned int count)
6210 int nchars;
6211 int to_read;
6212 DWORD waiting;
6213 char * orig_buffer = buffer;
6215 if (fd < 0)
6217 errno = EBADF;
6218 return -1;
6221 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
6223 child_process *cp = fd_info[fd].cp;
6225 if ((fd_info[fd].flags & FILE_READ) == 0)
6227 errno = EBADF;
6228 return -1;
6231 nchars = 0;
6233 /* re-read CR carried over from last read */
6234 if (fd_info[fd].flags & FILE_LAST_CR)
6236 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
6237 *buffer++ = 0x0d;
6238 count--;
6239 nchars++;
6240 fd_info[fd].flags &= ~FILE_LAST_CR;
6243 /* presence of a child_process structure means we are operating in
6244 non-blocking mode - otherwise we just call _read directly.
6245 Note that the child_process structure might be missing because
6246 reap_subprocess has been called; in this case the pipe is
6247 already broken, so calling _read on it is okay. */
6248 if (cp)
6250 int current_status = cp->status;
6252 switch (current_status)
6254 case STATUS_READ_FAILED:
6255 case STATUS_READ_ERROR:
6256 /* report normal EOF if nothing in buffer */
6257 if (nchars <= 0)
6258 fd_info[fd].flags |= FILE_AT_EOF;
6259 return nchars;
6261 case STATUS_READ_READY:
6262 case STATUS_READ_IN_PROGRESS:
6263 DebPrint (("sys_read called when read is in progress\n"));
6264 errno = EWOULDBLOCK;
6265 return -1;
6267 case STATUS_READ_SUCCEEDED:
6268 /* consume read-ahead char */
6269 *buffer++ = cp->chr;
6270 count--;
6271 nchars++;
6272 cp->status = STATUS_READ_ACKNOWLEDGED;
6273 ResetEvent (cp->char_avail);
6275 case STATUS_READ_ACKNOWLEDGED:
6276 break;
6278 default:
6279 DebPrint (("sys_read: bad status %d\n", current_status));
6280 errno = EBADF;
6281 return -1;
6284 if (fd_info[fd].flags & FILE_PIPE)
6286 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
6287 to_read = min (waiting, (DWORD) count);
6289 if (to_read > 0)
6290 nchars += _read (fd, buffer, to_read);
6292 else if (fd_info[fd].flags & FILE_SERIAL)
6294 HANDLE hnd = fd_info[fd].hnd;
6295 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
6296 int rc = 0;
6297 COMMTIMEOUTS ct;
6299 if (count > 0)
6301 /* Configure timeouts for non-blocking read. */
6302 if (!GetCommTimeouts (hnd, &ct))
6304 errno = EIO;
6305 return -1;
6307 ct.ReadIntervalTimeout = MAXDWORD;
6308 ct.ReadTotalTimeoutMultiplier = 0;
6309 ct.ReadTotalTimeoutConstant = 0;
6310 if (!SetCommTimeouts (hnd, &ct))
6312 errno = EIO;
6313 return -1;
6316 if (!ResetEvent (ovl->hEvent))
6318 errno = EIO;
6319 return -1;
6321 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
6323 if (GetLastError () != ERROR_IO_PENDING)
6325 errno = EIO;
6326 return -1;
6328 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
6330 errno = EIO;
6331 return -1;
6334 nchars += rc;
6337 else /* FILE_SOCKET */
6339 if (winsock_lib == NULL) emacs_abort ();
6341 /* do the equivalent of a non-blocking read */
6342 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
6343 if (waiting == 0 && nchars == 0)
6345 h_errno = errno = EWOULDBLOCK;
6346 return -1;
6349 if (waiting)
6351 /* always use binary mode for sockets */
6352 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
6353 if (res == SOCKET_ERROR)
6355 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
6356 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
6357 set_errno ();
6358 return -1;
6360 nchars += res;
6364 else
6366 int nread = _read (fd, buffer, count);
6367 if (nread >= 0)
6368 nchars += nread;
6369 else if (nchars == 0)
6370 nchars = nread;
6373 if (nchars <= 0)
6374 fd_info[fd].flags |= FILE_AT_EOF;
6375 /* Perform text mode translation if required. */
6376 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
6378 nchars = crlf_to_lf (nchars, orig_buffer);
6379 /* If buffer contains only CR, return that. To be absolutely
6380 sure we should attempt to read the next char, but in
6381 practice a CR to be followed by LF would not appear by
6382 itself in the buffer. */
6383 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
6385 fd_info[fd].flags |= FILE_LAST_CR;
6386 nchars--;
6390 else
6391 nchars = _read (fd, buffer, count);
6393 return nchars;
6396 /* From w32xfns.c */
6397 extern HANDLE interrupt_handle;
6399 /* For now, don't bother with a non-blocking mode */
6401 sys_write (int fd, const void * buffer, unsigned int count)
6403 int nchars;
6405 if (fd < 0)
6407 errno = EBADF;
6408 return -1;
6411 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
6413 if ((fd_info[fd].flags & FILE_WRITE) == 0)
6415 errno = EBADF;
6416 return -1;
6419 /* Perform text mode translation if required. */
6420 if ((fd_info[fd].flags & FILE_BINARY) == 0)
6422 char * tmpbuf = alloca (count * 2);
6423 unsigned char * src = (void *)buffer;
6424 unsigned char * dst = tmpbuf;
6425 int nbytes = count;
6427 while (1)
6429 unsigned char *next;
6430 /* copy next line or remaining bytes */
6431 next = _memccpy (dst, src, '\n', nbytes);
6432 if (next)
6434 /* copied one line ending with '\n' */
6435 int copied = next - dst;
6436 nbytes -= copied;
6437 src += copied;
6438 /* insert '\r' before '\n' */
6439 next[-1] = '\r';
6440 next[0] = '\n';
6441 dst = next + 1;
6442 count++;
6444 else
6445 /* copied remaining partial line -> now finished */
6446 break;
6448 buffer = tmpbuf;
6452 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
6454 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
6455 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
6456 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
6457 DWORD active = 0;
6459 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
6461 if (GetLastError () != ERROR_IO_PENDING)
6463 errno = EIO;
6464 return -1;
6466 if (detect_input_pending ())
6467 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
6468 QS_ALLINPUT);
6469 else
6470 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
6471 if (active == WAIT_OBJECT_0)
6472 { /* User pressed C-g, cancel write, then leave. Don't bother
6473 cleaning up as we may only get stuck in buggy drivers. */
6474 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
6475 CancelIo (hnd);
6476 errno = EIO;
6477 return -1;
6479 if (active == WAIT_OBJECT_0 + 1
6480 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
6482 errno = EIO;
6483 return -1;
6487 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
6489 unsigned long nblock = 0;
6490 if (winsock_lib == NULL) emacs_abort ();
6492 /* TODO: implement select() properly so non-blocking I/O works. */
6493 /* For now, make sure the write blocks. */
6494 if (fd_info[fd].flags & FILE_NDELAY)
6495 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6497 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
6499 /* Set the socket back to non-blocking if it was before,
6500 for other operations that support it. */
6501 if (fd_info[fd].flags & FILE_NDELAY)
6503 nblock = 1;
6504 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6507 if (nchars == SOCKET_ERROR)
6509 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
6510 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
6511 set_errno ();
6514 else
6516 /* Some networked filesystems don't like too large writes, so
6517 break them into smaller chunks. See the Comments section of
6518 the MSDN documentation of WriteFile for details behind the
6519 choice of the value of CHUNK below. See also the thread
6520 http://thread.gmane.org/gmane.comp.version-control.git/145294
6521 in the git mailing list. */
6522 const unsigned char *p = buffer;
6523 const unsigned chunk = 30 * 1024 * 1024;
6525 nchars = 0;
6526 while (count > 0)
6528 unsigned this_chunk = count < chunk ? count : chunk;
6529 int n = _write (fd, p, this_chunk);
6531 nchars += n;
6532 if (n < 0)
6534 nchars = n;
6535 break;
6537 else if (n < this_chunk)
6538 break;
6539 count -= n;
6540 p += n;
6544 return nchars;
6547 /* The Windows CRT functions are "optimized for speed", so they don't
6548 check for timezone and DST changes if they were last called less
6549 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
6550 all Emacs features that repeatedly call time functions (e.g.,
6551 display-time) are in real danger of missing timezone and DST
6552 changes. Calling tzset before each localtime call fixes that. */
6553 struct tm *
6554 sys_localtime (const time_t *t)
6556 tzset ();
6557 return localtime (t);
6562 /* Try loading LIBRARY_ID from the file(s) specified in
6563 Vdynamic_library_alist. If the library is loaded successfully,
6564 return the handle of the DLL, and record the filename in the
6565 property :loaded-from of LIBRARY_ID. If the library could not be
6566 found, or when it was already loaded (because the handle is not
6567 recorded anywhere, and so is lost after use), return NULL.
6569 We could also save the handle in :loaded-from, but currently
6570 there's no use case for it. */
6571 HMODULE
6572 w32_delayed_load (Lisp_Object library_id)
6574 HMODULE library_dll = NULL;
6576 CHECK_SYMBOL (library_id);
6578 if (CONSP (Vdynamic_library_alist)
6579 && NILP (Fassq (library_id, Vlibrary_cache)))
6581 Lisp_Object found = Qnil;
6582 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
6584 if (CONSP (dlls))
6585 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
6587 CHECK_STRING_CAR (dlls);
6588 if ((library_dll = LoadLibrary (SDATA (XCAR (dlls)))))
6590 char name[MAX_PATH];
6591 DWORD len;
6593 len = GetModuleFileNameA (library_dll, name, sizeof (name));
6594 found = Fcons (XCAR (dlls),
6595 (len > 0)
6596 /* Possibly truncated */
6597 ? make_specified_string (name, -1, len, 1)
6598 : Qnil);
6599 break;
6603 Fput (library_id, QCloaded_from, found);
6606 return library_dll;
6610 void
6611 check_windows_init_file (void)
6613 /* A common indication that Emacs is not installed properly is when
6614 it cannot find the Windows installation file. If this file does
6615 not exist in the expected place, tell the user. */
6617 if (!noninteractive && !inhibit_window_system
6618 /* Vload_path is not yet initialized when we are loading
6619 loadup.el. */
6620 && NILP (Vpurify_flag))
6622 Lisp_Object init_file;
6623 int fd;
6625 init_file = build_string ("term/w32-win");
6626 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
6627 if (fd < 0)
6629 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
6630 char *init_file_name = SDATA (init_file);
6631 char *load_path = SDATA (load_path_print);
6632 char *buffer = alloca (1024
6633 + strlen (init_file_name)
6634 + strlen (load_path));
6636 sprintf (buffer,
6637 "The Emacs Windows initialization file \"%s.el\" "
6638 "could not be found in your Emacs installation. "
6639 "Emacs checked the following directories for this file:\n"
6640 "\n%s\n\n"
6641 "When Emacs cannot find this file, it usually means that it "
6642 "was not installed properly, or its distribution file was "
6643 "not unpacked properly.\nSee the README.W32 file in the "
6644 "top-level Emacs directory for more information.",
6645 init_file_name, load_path);
6646 MessageBox (NULL,
6647 buffer,
6648 "Emacs Abort Dialog",
6649 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
6650 /* Use the low-level system abort. */
6651 abort ();
6653 else
6655 _close (fd);
6660 void
6661 term_ntproc (int ignored)
6663 (void)ignored;
6665 term_timers ();
6667 /* shutdown the socket interface if necessary */
6668 term_winsock ();
6670 term_w32select ();
6673 void
6674 init_ntproc (int dumping)
6676 sigset_t initial_mask = 0;
6678 /* Initialize the socket interface now if available and requested by
6679 the user by defining PRELOAD_WINSOCK; otherwise loading will be
6680 delayed until open-network-stream is called (w32-has-winsock can
6681 also be used to dynamically load or reload winsock).
6683 Conveniently, init_environment is called before us, so
6684 PRELOAD_WINSOCK can be set in the registry. */
6686 /* Always initialize this correctly. */
6687 winsock_lib = NULL;
6689 if (getenv ("PRELOAD_WINSOCK") != NULL)
6690 init_winsock (TRUE);
6692 /* Initial preparation for subprocess support: replace our standard
6693 handles with non-inheritable versions. */
6695 HANDLE parent;
6696 HANDLE stdin_save = INVALID_HANDLE_VALUE;
6697 HANDLE stdout_save = INVALID_HANDLE_VALUE;
6698 HANDLE stderr_save = INVALID_HANDLE_VALUE;
6700 parent = GetCurrentProcess ();
6702 /* ignore errors when duplicating and closing; typically the
6703 handles will be invalid when running as a gui program. */
6704 DuplicateHandle (parent,
6705 GetStdHandle (STD_INPUT_HANDLE),
6706 parent,
6707 &stdin_save,
6709 FALSE,
6710 DUPLICATE_SAME_ACCESS);
6712 DuplicateHandle (parent,
6713 GetStdHandle (STD_OUTPUT_HANDLE),
6714 parent,
6715 &stdout_save,
6717 FALSE,
6718 DUPLICATE_SAME_ACCESS);
6720 DuplicateHandle (parent,
6721 GetStdHandle (STD_ERROR_HANDLE),
6722 parent,
6723 &stderr_save,
6725 FALSE,
6726 DUPLICATE_SAME_ACCESS);
6728 fclose (stdin);
6729 fclose (stdout);
6730 fclose (stderr);
6732 if (stdin_save != INVALID_HANDLE_VALUE)
6733 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
6734 else
6735 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
6736 _fdopen (0, "r");
6738 if (stdout_save != INVALID_HANDLE_VALUE)
6739 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
6740 else
6741 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
6742 _fdopen (1, "w");
6744 if (stderr_save != INVALID_HANDLE_VALUE)
6745 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
6746 else
6747 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
6748 _fdopen (2, "w");
6751 /* unfortunately, atexit depends on implementation of malloc */
6752 /* atexit (term_ntproc); */
6753 if (!dumping)
6755 /* Make sure we start with all signals unblocked. */
6756 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
6757 signal (SIGABRT, term_ntproc);
6759 init_timers ();
6761 /* determine which drives are fixed, for GetCachedVolumeInformation */
6763 /* GetDriveType must have trailing backslash. */
6764 char drive[] = "A:\\";
6766 /* Loop over all possible drive letters */
6767 while (*drive <= 'Z')
6769 /* Record if this drive letter refers to a fixed drive. */
6770 fixed_drives[DRIVE_INDEX (*drive)] =
6771 (GetDriveType (drive) == DRIVE_FIXED);
6773 (*drive)++;
6776 /* Reset the volume info cache. */
6777 volume_cache = NULL;
6782 shutdown_handler ensures that buffers' autosave files are
6783 up to date when the user logs off, or the system shuts down.
6785 static BOOL WINAPI
6786 shutdown_handler (DWORD type)
6788 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
6789 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
6790 || type == CTRL_LOGOFF_EVENT /* User logs off. */
6791 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
6793 /* Shut down cleanly, making sure autosave files are up to date. */
6794 shut_down_emacs (0, Qnil);
6797 /* Allow other handlers to handle this signal. */
6798 return FALSE;
6802 globals_of_w32 is used to initialize those global variables that
6803 must always be initialized on startup even when the global variable
6804 initialized is non zero (see the function main in emacs.c).
6806 void
6807 globals_of_w32 (void)
6809 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
6811 get_process_times_fn = (GetProcessTimes_Proc)
6812 GetProcAddress (kernel32, "GetProcessTimes");
6814 DEFSYM (QCloaded_from, ":loaded-from");
6816 g_b_init_is_windows_9x = 0;
6817 g_b_init_open_process_token = 0;
6818 g_b_init_get_token_information = 0;
6819 g_b_init_lookup_account_sid = 0;
6820 g_b_init_get_sid_sub_authority = 0;
6821 g_b_init_get_sid_sub_authority_count = 0;
6822 g_b_init_get_security_info = 0;
6823 g_b_init_get_file_security = 0;
6824 g_b_init_get_security_descriptor_owner = 0;
6825 g_b_init_get_security_descriptor_group = 0;
6826 g_b_init_is_valid_sid = 0;
6827 g_b_init_create_toolhelp32_snapshot = 0;
6828 g_b_init_process32_first = 0;
6829 g_b_init_process32_next = 0;
6830 g_b_init_open_thread_token = 0;
6831 g_b_init_impersonate_self = 0;
6832 g_b_init_revert_to_self = 0;
6833 g_b_init_get_process_memory_info = 0;
6834 g_b_init_get_process_working_set_size = 0;
6835 g_b_init_global_memory_status = 0;
6836 g_b_init_global_memory_status_ex = 0;
6837 g_b_init_equal_sid = 0;
6838 g_b_init_copy_sid = 0;
6839 g_b_init_get_length_sid = 0;
6840 g_b_init_get_native_system_info = 0;
6841 g_b_init_get_system_times = 0;
6842 g_b_init_create_symbolic_link = 0;
6843 num_of_processors = 0;
6844 /* The following sets a handler for shutdown notifications for
6845 console apps. This actually applies to Emacs in both console and
6846 GUI modes, since we had to fool windows into thinking emacs is a
6847 console application to get console mode to work. */
6848 SetConsoleCtrlHandler (shutdown_handler, TRUE);
6850 /* "None" is the default group name on standalone workstations. */
6851 strcpy (dflt_group_name, "None");
6854 /* For make-serial-process */
6856 serial_open (char *port)
6858 HANDLE hnd;
6859 child_process *cp;
6860 int fd = -1;
6862 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
6863 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
6864 if (hnd == INVALID_HANDLE_VALUE)
6865 error ("Could not open %s", port);
6866 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
6867 if (fd == -1)
6868 error ("Could not open %s", port);
6870 cp = new_child ();
6871 if (!cp)
6872 error ("Could not create child process");
6873 cp->fd = fd;
6874 cp->status = STATUS_READ_ACKNOWLEDGED;
6875 fd_info[ fd ].hnd = hnd;
6876 fd_info[ fd ].flags |=
6877 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
6878 if (fd_info[ fd ].cp != NULL)
6880 error ("fd_info[fd = %d] is already in use", fd);
6882 fd_info[ fd ].cp = cp;
6883 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
6884 if (cp->ovl_read.hEvent == NULL)
6885 error ("Could not create read event");
6886 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
6887 if (cp->ovl_write.hEvent == NULL)
6888 error ("Could not create write event");
6890 return fd;
6893 /* For serial-process-configure */
6894 void
6895 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
6897 Lisp_Object childp2 = Qnil;
6898 Lisp_Object tem = Qnil;
6899 HANDLE hnd;
6900 DCB dcb;
6901 COMMTIMEOUTS ct;
6902 char summary[4] = "???"; /* This usually becomes "8N1". */
6904 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
6905 error ("Not a serial process");
6906 hnd = fd_info[ p->outfd ].hnd;
6908 childp2 = Fcopy_sequence (p->childp);
6910 /* Initialize timeouts for blocking read and blocking write. */
6911 if (!GetCommTimeouts (hnd, &ct))
6912 error ("GetCommTimeouts() failed");
6913 ct.ReadIntervalTimeout = 0;
6914 ct.ReadTotalTimeoutMultiplier = 0;
6915 ct.ReadTotalTimeoutConstant = 0;
6916 ct.WriteTotalTimeoutMultiplier = 0;
6917 ct.WriteTotalTimeoutConstant = 0;
6918 if (!SetCommTimeouts (hnd, &ct))
6919 error ("SetCommTimeouts() failed");
6920 /* Read port attributes and prepare default configuration. */
6921 memset (&dcb, 0, sizeof (dcb));
6922 dcb.DCBlength = sizeof (DCB);
6923 if (!GetCommState (hnd, &dcb))
6924 error ("GetCommState() failed");
6925 dcb.fBinary = TRUE;
6926 dcb.fNull = FALSE;
6927 dcb.fAbortOnError = FALSE;
6928 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6929 dcb.ErrorChar = 0;
6930 dcb.EofChar = 0;
6931 dcb.EvtChar = 0;
6933 /* Configure speed. */
6934 if (!NILP (Fplist_member (contact, QCspeed)))
6935 tem = Fplist_get (contact, QCspeed);
6936 else
6937 tem = Fplist_get (p->childp, QCspeed);
6938 CHECK_NUMBER (tem);
6939 dcb.BaudRate = XINT (tem);
6940 childp2 = Fplist_put (childp2, QCspeed, tem);
6942 /* Configure bytesize. */
6943 if (!NILP (Fplist_member (contact, QCbytesize)))
6944 tem = Fplist_get (contact, QCbytesize);
6945 else
6946 tem = Fplist_get (p->childp, QCbytesize);
6947 if (NILP (tem))
6948 tem = make_number (8);
6949 CHECK_NUMBER (tem);
6950 if (XINT (tem) != 7 && XINT (tem) != 8)
6951 error (":bytesize must be nil (8), 7, or 8");
6952 dcb.ByteSize = XINT (tem);
6953 summary[0] = XINT (tem) + '0';
6954 childp2 = Fplist_put (childp2, QCbytesize, tem);
6956 /* Configure parity. */
6957 if (!NILP (Fplist_member (contact, QCparity)))
6958 tem = Fplist_get (contact, QCparity);
6959 else
6960 tem = Fplist_get (p->childp, QCparity);
6961 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
6962 error (":parity must be nil (no parity), `even', or `odd'");
6963 dcb.fParity = FALSE;
6964 dcb.Parity = NOPARITY;
6965 dcb.fErrorChar = FALSE;
6966 if (NILP (tem))
6968 summary[1] = 'N';
6970 else if (EQ (tem, Qeven))
6972 summary[1] = 'E';
6973 dcb.fParity = TRUE;
6974 dcb.Parity = EVENPARITY;
6975 dcb.fErrorChar = TRUE;
6977 else if (EQ (tem, Qodd))
6979 summary[1] = 'O';
6980 dcb.fParity = TRUE;
6981 dcb.Parity = ODDPARITY;
6982 dcb.fErrorChar = TRUE;
6984 childp2 = Fplist_put (childp2, QCparity, tem);
6986 /* Configure stopbits. */
6987 if (!NILP (Fplist_member (contact, QCstopbits)))
6988 tem = Fplist_get (contact, QCstopbits);
6989 else
6990 tem = Fplist_get (p->childp, QCstopbits);
6991 if (NILP (tem))
6992 tem = make_number (1);
6993 CHECK_NUMBER (tem);
6994 if (XINT (tem) != 1 && XINT (tem) != 2)
6995 error (":stopbits must be nil (1 stopbit), 1, or 2");
6996 summary[2] = XINT (tem) + '0';
6997 if (XINT (tem) == 1)
6998 dcb.StopBits = ONESTOPBIT;
6999 else if (XINT (tem) == 2)
7000 dcb.StopBits = TWOSTOPBITS;
7001 childp2 = Fplist_put (childp2, QCstopbits, tem);
7003 /* Configure flowcontrol. */
7004 if (!NILP (Fplist_member (contact, QCflowcontrol)))
7005 tem = Fplist_get (contact, QCflowcontrol);
7006 else
7007 tem = Fplist_get (p->childp, QCflowcontrol);
7008 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
7009 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
7010 dcb.fOutxCtsFlow = FALSE;
7011 dcb.fOutxDsrFlow = FALSE;
7012 dcb.fDtrControl = DTR_CONTROL_DISABLE;
7013 dcb.fDsrSensitivity = FALSE;
7014 dcb.fTXContinueOnXoff = FALSE;
7015 dcb.fOutX = FALSE;
7016 dcb.fInX = FALSE;
7017 dcb.fRtsControl = RTS_CONTROL_DISABLE;
7018 dcb.XonChar = 17; /* Control-Q */
7019 dcb.XoffChar = 19; /* Control-S */
7020 if (NILP (tem))
7022 /* Already configured. */
7024 else if (EQ (tem, Qhw))
7026 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
7027 dcb.fOutxCtsFlow = TRUE;
7029 else if (EQ (tem, Qsw))
7031 dcb.fOutX = TRUE;
7032 dcb.fInX = TRUE;
7034 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
7036 /* Activate configuration. */
7037 if (!SetCommState (hnd, &dcb))
7038 error ("SetCommState() failed");
7040 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
7041 pset_childp (p, childp2);
7044 #ifdef HAVE_GNUTLS
7046 ssize_t
7047 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
7049 int n, sc, err;
7050 SELECT_TYPE fdset;
7051 EMACS_TIME timeout;
7052 struct Lisp_Process *process = (struct Lisp_Process *)p;
7053 int fd = process->infd;
7055 for (;;)
7057 n = sys_read (fd, (char*)buf, sz);
7059 if (n >= 0)
7060 return n;
7062 err = errno;
7064 if (err == EWOULDBLOCK)
7066 /* Set a small timeout. */
7067 timeout = make_emacs_time (1, 0);
7068 FD_ZERO (&fdset);
7069 FD_SET ((int)fd, &fdset);
7071 /* Use select with the timeout to poll the selector. */
7072 sc = select (fd + 1, &fdset, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
7073 &timeout, NULL);
7075 if (sc > 0)
7076 continue; /* Try again. */
7078 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
7079 Also accept select return 0 as an indicator to EAGAIN. */
7080 if (sc == 0 || errno == EWOULDBLOCK)
7081 err = EAGAIN;
7082 else
7083 err = errno; /* Other errors are just passed on. */
7086 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
7088 return -1;
7092 ssize_t
7093 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
7095 struct Lisp_Process *process = (struct Lisp_Process *)p;
7096 int fd = process->outfd;
7097 ssize_t n = sys_write (fd, buf, sz);
7099 /* 0 or more bytes written means everything went fine. */
7100 if (n >= 0)
7101 return n;
7103 /* Negative bytes written means we got an error in errno.
7104 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7105 emacs_gnutls_transport_set_errno (process->gnutls_state,
7106 errno == EWOULDBLOCK ? EAGAIN : errno);
7108 return -1;
7110 #endif /* HAVE_GNUTLS */
7112 /* end of w32.c */