Support MS-Windows file names encoded in multibyte encodings.
[emacs.git] / src / w32.c
blob98ec573f55312992387b1f97da04a93a07d0a5e5
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
2 Copyright (C) 1994-1995, 2000-2013 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, _mbslwr, _mbsrchr, ... */
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 "ndir.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 getwd (char *dir)
921 #if 0
922 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
923 return dir;
924 return NULL;
925 #else
926 /* Emacs doesn't actually change directory itself, it stays in the
927 same directory where it was started. */
928 strcpy (dir, startup_dir);
929 return dir;
930 #endif
933 /* Emulate getloadavg. */
935 struct load_sample {
936 time_t sample_time;
937 ULONGLONG idle;
938 ULONGLONG kernel;
939 ULONGLONG user;
942 /* Number of processors on this machine. */
943 static unsigned num_of_processors;
945 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
946 static struct load_sample samples[16*60];
947 static int first_idx = -1, last_idx = -1;
948 static int max_idx = sizeof (samples) / sizeof (samples[0]);
950 static int
951 buf_next (int from)
953 int next_idx = from + 1;
955 if (next_idx >= max_idx)
956 next_idx = 0;
958 return next_idx;
961 static int
962 buf_prev (int from)
964 int prev_idx = from - 1;
966 if (prev_idx < 0)
967 prev_idx = max_idx - 1;
969 return prev_idx;
972 static void
973 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
975 SYSTEM_INFO sysinfo;
976 FILETIME ft_idle, ft_user, ft_kernel;
978 /* Initialize the number of processors on this machine. */
979 if (num_of_processors <= 0)
981 get_native_system_info (&sysinfo);
982 num_of_processors = sysinfo.dwNumberOfProcessors;
983 if (num_of_processors <= 0)
985 GetSystemInfo (&sysinfo);
986 num_of_processors = sysinfo.dwNumberOfProcessors;
988 if (num_of_processors <= 0)
989 num_of_processors = 1;
992 /* TODO: Take into account threads that are ready to run, by
993 sampling the "\System\Processor Queue Length" performance
994 counter. The code below accounts only for threads that are
995 actually running. */
997 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
999 ULARGE_INTEGER uidle, ukernel, uuser;
1001 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1002 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1003 memcpy (&uuser, &ft_user, sizeof (ft_user));
1004 *idle = uidle.QuadPart;
1005 *kernel = ukernel.QuadPart;
1006 *user = uuser.QuadPart;
1008 else
1010 *idle = 0;
1011 *kernel = 0;
1012 *user = 0;
1016 /* Produce the load average for a given time interval, using the
1017 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1018 1-minute, 5-minute, or 15-minute average, respectively. */
1019 static double
1020 getavg (int which)
1022 double retval = -1.0;
1023 double tdiff;
1024 int idx;
1025 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1026 time_t now = samples[last_idx].sample_time;
1028 if (first_idx != last_idx)
1030 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1032 tdiff = difftime (now, samples[idx].sample_time);
1033 if (tdiff >= span - 2*DBL_EPSILON*now)
1035 long double sys =
1036 samples[last_idx].kernel + samples[last_idx].user
1037 - (samples[idx].kernel + samples[idx].user);
1038 long double idl = samples[last_idx].idle - samples[idx].idle;
1040 retval = (1.0 - idl / sys) * num_of_processors;
1041 break;
1043 if (idx == first_idx)
1044 break;
1048 return retval;
1052 getloadavg (double loadavg[], int nelem)
1054 int elem;
1055 ULONGLONG idle, kernel, user;
1056 time_t now = time (NULL);
1058 /* Store another sample. We ignore samples that are less than 1 sec
1059 apart. */
1060 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
1062 sample_system_load (&idle, &kernel, &user);
1063 last_idx = buf_next (last_idx);
1064 samples[last_idx].sample_time = now;
1065 samples[last_idx].idle = idle;
1066 samples[last_idx].kernel = kernel;
1067 samples[last_idx].user = user;
1068 /* If the buffer has more that 15 min worth of samples, discard
1069 the old ones. */
1070 if (first_idx == -1)
1071 first_idx = last_idx;
1072 while (first_idx != last_idx
1073 && (difftime (now, samples[first_idx].sample_time)
1074 >= 15.0*60 + 2*DBL_EPSILON*now))
1075 first_idx = buf_next (first_idx);
1078 for (elem = 0; elem < nelem; elem++)
1080 double avg = getavg (elem);
1082 if (avg < 0)
1083 break;
1084 loadavg[elem] = avg;
1087 return elem;
1090 /* Emulate getpwuid, getpwnam and others. */
1092 #define PASSWD_FIELD_SIZE 256
1094 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1095 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1096 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1097 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
1098 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
1100 static struct passwd dflt_passwd =
1102 dflt_passwd_name,
1103 dflt_passwd_passwd,
1107 dflt_passwd_gecos,
1108 dflt_passwd_dir,
1109 dflt_passwd_shell,
1112 static char dflt_group_name[GNLEN+1];
1114 static struct group dflt_group =
1116 /* When group information is not available, we return this as the
1117 group for all files. */
1118 dflt_group_name,
1122 unsigned
1123 getuid (void)
1125 return dflt_passwd.pw_uid;
1128 unsigned
1129 geteuid (void)
1131 /* I could imagine arguing for checking to see whether the user is
1132 in the Administrators group and returning a UID of 0 for that
1133 case, but I don't know how wise that would be in the long run. */
1134 return getuid ();
1137 unsigned
1138 getgid (void)
1140 return dflt_passwd.pw_gid;
1143 unsigned
1144 getegid (void)
1146 return getgid ();
1149 struct passwd *
1150 getpwuid (unsigned uid)
1152 if (uid == dflt_passwd.pw_uid)
1153 return &dflt_passwd;
1154 return NULL;
1157 struct group *
1158 getgrgid (gid_t gid)
1160 return &dflt_group;
1163 struct passwd *
1164 getpwnam (char *name)
1166 struct passwd *pw;
1168 pw = getpwuid (getuid ());
1169 if (!pw)
1170 return pw;
1172 if (xstrcasecmp (name, pw->pw_name))
1173 return NULL;
1175 return pw;
1178 static void
1179 init_user_info (void)
1181 /* Find the user's real name by opening the process token and
1182 looking up the name associated with the user-sid in that token.
1184 Use the relative portion of the identifier authority value from
1185 the user-sid as the user id value (same for group id using the
1186 primary group sid from the process token). */
1188 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1189 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1190 DWORD glength = sizeof (gname);
1191 HANDLE token = NULL;
1192 SID_NAME_USE user_type;
1193 unsigned char *buf = NULL;
1194 DWORD blen = 0;
1195 TOKEN_USER user_token;
1196 TOKEN_PRIMARY_GROUP group_token;
1197 BOOL result;
1199 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1200 if (result)
1202 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1203 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1205 buf = xmalloc (blen);
1206 result = get_token_information (token, TokenUser,
1207 (LPVOID)buf, blen, &needed);
1208 if (result)
1210 memcpy (&user_token, buf, sizeof (user_token));
1211 result = lookup_account_sid (NULL, user_token.User.Sid,
1212 uname, &ulength,
1213 domain, &dlength, &user_type);
1216 else
1217 result = FALSE;
1219 if (result)
1221 strcpy (dflt_passwd.pw_name, uname);
1222 /* Determine a reasonable uid value. */
1223 if (xstrcasecmp ("administrator", uname) == 0)
1225 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1226 dflt_passwd.pw_gid = 513; /* well-known None gid */
1228 else
1230 /* Use the last sub-authority value of the RID, the relative
1231 portion of the SID, as user/group ID. */
1232 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1234 /* Get group id and name. */
1235 result = get_token_information (token, TokenPrimaryGroup,
1236 (LPVOID)buf, blen, &needed);
1237 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1239 buf = xrealloc (buf, blen = needed);
1240 result = get_token_information (token, TokenPrimaryGroup,
1241 (LPVOID)buf, blen, &needed);
1243 if (result)
1245 memcpy (&group_token, buf, sizeof (group_token));
1246 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1247 dlength = sizeof (domain);
1248 /* If we can get at the real Primary Group name, use that.
1249 Otherwise, the default group name was already set to
1250 "None" in globals_of_w32. */
1251 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1252 gname, &glength, NULL, &dlength,
1253 &user_type))
1254 strcpy (dflt_group_name, gname);
1256 else
1257 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1260 /* If security calls are not supported (presumably because we
1261 are running under Windows 9X), fallback to this: */
1262 else if (GetUserName (uname, &ulength))
1264 strcpy (dflt_passwd.pw_name, uname);
1265 if (xstrcasecmp ("administrator", uname) == 0)
1266 dflt_passwd.pw_uid = 0;
1267 else
1268 dflt_passwd.pw_uid = 123;
1269 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1271 else
1273 strcpy (dflt_passwd.pw_name, "unknown");
1274 dflt_passwd.pw_uid = 123;
1275 dflt_passwd.pw_gid = 123;
1277 dflt_group.gr_gid = dflt_passwd.pw_gid;
1279 /* Ensure HOME and SHELL are defined. */
1280 if (getenv ("HOME") == NULL)
1281 emacs_abort ();
1282 if (getenv ("SHELL") == NULL)
1283 emacs_abort ();
1285 /* Set dir and shell from environment variables. */
1286 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1287 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1289 xfree (buf);
1290 if (token)
1291 CloseHandle (token);
1295 random (void)
1297 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1298 return ((rand () << 15) | rand ());
1301 void
1302 srandom (int seed)
1304 srand (seed);
1307 /* Current codepage for encoding file names. */
1308 static int file_name_codepage;
1310 /* Return the maximum length in bytes of a multibyte character
1311 sequence encoded in the current ANSI codepage. This is required to
1312 correctly walk the encoded file names one character at a time. */
1313 static int
1314 max_filename_mbslen (void)
1316 /* A simple cache to avoid calling GetCPInfo every time we need to
1317 normalize a file name. The file-name encoding is not supposed to
1318 be changed too frequently, if ever. */
1319 static Lisp_Object last_file_name_encoding;
1320 static int last_max_mbslen;
1321 Lisp_Object current_encoding;
1323 current_encoding = Vfile_name_coding_system;
1324 if (NILP (current_encoding))
1325 current_encoding = Vdefault_file_name_coding_system;
1327 if (!EQ (last_file_name_encoding, current_encoding))
1329 CPINFO cp_info;
1331 last_file_name_encoding = current_encoding;
1332 /* Default to the current ANSI codepage. */
1333 file_name_codepage = w32_ansi_code_page;
1334 if (!NILP (current_encoding))
1336 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1337 char *cp = NULL, *end;
1338 int cpnum;
1340 if (strncmp (cpname, "cp", 2) == 0)
1341 cp = cpname + 2;
1342 else if (strncmp (cpname, "windows-", 8) == 0)
1343 cp = cpname + 8;
1345 if (cp)
1347 end = cp;
1348 cpnum = strtol (cp, &end, 10);
1349 if (cpnum && *end == '\0' && end - cp >= 2)
1350 file_name_codepage = cpnum;
1354 if (!file_name_codepage)
1355 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1357 if (!GetCPInfo (file_name_codepage, &cp_info))
1359 file_name_codepage = CP_ACP;
1360 if (!GetCPInfo (file_name_codepage, &cp_info))
1361 emacs_abort ();
1363 last_max_mbslen = cp_info.MaxCharSize;
1366 return last_max_mbslen;
1369 /* Normalize filename by converting all path separators to
1370 the specified separator. Also conditionally convert upper
1371 case path name components to lower case. */
1373 static void
1374 normalize_filename (register char *fp, char path_sep)
1376 char sep;
1377 char *elem, *p2;
1378 int dbcs_p = max_filename_mbslen () > 1;
1380 /* Always lower-case drive letters a-z, even if the filesystem
1381 preserves case in filenames.
1382 This is so filenames can be compared by string comparison
1383 functions that are case-sensitive. Even case-preserving filesystems
1384 do not distinguish case in drive letters. */
1385 if (dbcs_p)
1386 p2 = CharNextExA (file_name_codepage, fp, 0);
1387 else
1388 p2 = fp + 1;
1390 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
1392 *fp += 'a' - 'A';
1393 fp += 2;
1396 if (NILP (Vw32_downcase_file_names))
1398 while (*fp)
1400 if (*fp == '/' || *fp == '\\')
1401 *fp = path_sep;
1402 if (!dbcs_p)
1403 fp++;
1404 else
1405 fp = CharNextExA (file_name_codepage, fp, 0);
1407 return;
1410 sep = path_sep; /* convert to this path separator */
1411 elem = fp; /* start of current path element */
1413 do {
1414 if (*fp >= 'a' && *fp <= 'z')
1415 elem = 0; /* don't convert this element */
1417 if (*fp == 0 || *fp == ':')
1419 sep = *fp; /* restore current separator (or 0) */
1420 *fp = '/'; /* after conversion of this element */
1423 if (*fp == '/' || *fp == '\\')
1425 if (elem && elem != fp)
1427 *fp = 0; /* temporary end of string */
1428 _mbslwr (elem); /* while we convert to lower case */
1430 *fp = sep; /* convert (or restore) path separator */
1431 elem = fp + 1; /* next element starts after separator */
1432 sep = path_sep;
1434 if (*fp)
1436 if (!dbcs_p)
1437 fp++;
1438 else
1439 fp = CharNextExA (file_name_codepage, fp, 0);
1441 } while (*fp);
1444 /* Destructively turn backslashes into slashes. */
1445 void
1446 dostounix_filename (register char *p)
1448 normalize_filename (p, '/');
1451 /* Destructively turn slashes into backslashes. */
1452 void
1453 unixtodos_filename (register char *p)
1455 normalize_filename (p, '\\');
1458 /* Remove all CR's that are followed by a LF.
1459 (From msdos.c...probably should figure out a way to share it,
1460 although this code isn't going to ever change.) */
1461 static int
1462 crlf_to_lf (register int n, register unsigned char *buf)
1464 unsigned char *np = buf;
1465 unsigned char *startp = buf;
1466 unsigned char *endp = buf + n;
1468 if (n == 0)
1469 return n;
1470 while (buf < endp - 1)
1472 if (*buf == 0x0d)
1474 if (*(++buf) != 0x0a)
1475 *np++ = 0x0d;
1477 else
1478 *np++ = *buf++;
1480 if (buf < endp)
1481 *np++ = *buf++;
1482 return np - startp;
1485 /* Parse the root part of file name, if present. Return length and
1486 optionally store pointer to char after root. */
1487 static int
1488 parse_root (char * name, char ** pPath)
1490 char * start = name;
1492 if (name == NULL)
1493 return 0;
1495 /* find the root name of the volume if given */
1496 if (isalpha (name[0]) && name[1] == ':')
1498 /* skip past drive specifier */
1499 name += 2;
1500 if (IS_DIRECTORY_SEP (name[0]))
1501 name++;
1503 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1505 int slashes = 2;
1506 name += 2;
1509 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1510 break;
1511 name++;
1513 while ( *name );
1514 if (IS_DIRECTORY_SEP (name[0]))
1515 name++;
1518 if (pPath)
1519 *pPath = name;
1521 return name - start;
1524 /* Get long base name for name; name is assumed to be absolute. */
1525 static int
1526 get_long_basename (char * name, char * buf, int size)
1528 WIN32_FIND_DATA find_data;
1529 HANDLE dir_handle;
1530 int len = 0;
1532 /* must be valid filename, no wild cards or other invalid characters */
1533 if (_mbspbrk (name, "*?|<>\""))
1534 return 0;
1536 dir_handle = FindFirstFile (name, &find_data);
1537 if (dir_handle != INVALID_HANDLE_VALUE)
1539 if ((len = strlen (find_data.cFileName)) < size)
1540 memcpy (buf, find_data.cFileName, len + 1);
1541 else
1542 len = 0;
1543 FindClose (dir_handle);
1545 return len;
1548 /* Get long name for file, if possible (assumed to be absolute). */
1549 BOOL
1550 w32_get_long_filename (char * name, char * buf, int size)
1552 char * o = buf;
1553 char * p;
1554 char * q;
1555 char full[ MAX_PATH ];
1556 int len;
1558 len = strlen (name);
1559 if (len >= MAX_PATH)
1560 return FALSE;
1562 /* Use local copy for destructive modification. */
1563 memcpy (full, name, len+1);
1564 unixtodos_filename (full);
1566 /* Copy root part verbatim. */
1567 len = parse_root (full, &p);
1568 memcpy (o, full, len);
1569 o += len;
1570 *o = '\0';
1571 size -= len;
1573 while (p != NULL && *p)
1575 q = p;
1576 p = _mbschr (q, '\\');
1577 if (p) *p = '\0';
1578 len = get_long_basename (full, o, size);
1579 if (len > 0)
1581 o += len;
1582 size -= len;
1583 if (p != NULL)
1585 *p++ = '\\';
1586 if (size < 2)
1587 return FALSE;
1588 *o++ = '\\';
1589 size--;
1590 *o = '\0';
1593 else
1594 return FALSE;
1597 return TRUE;
1600 static int
1601 is_unc_volume (const char *filename)
1603 const char *ptr = filename;
1605 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1606 return 0;
1608 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1609 return 0;
1611 return 1;
1614 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1616 LPBYTE
1617 w32_get_resource (char *key, LPDWORD lpdwtype)
1619 LPBYTE lpvalue;
1620 HKEY hrootkey = NULL;
1621 DWORD cbData;
1623 /* Check both the current user and the local machine to see if
1624 we have any resources. */
1626 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1628 lpvalue = NULL;
1630 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1631 && (lpvalue = xmalloc (cbData)) != NULL
1632 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1634 RegCloseKey (hrootkey);
1635 return (lpvalue);
1638 xfree (lpvalue);
1640 RegCloseKey (hrootkey);
1643 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1645 lpvalue = NULL;
1647 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1648 && (lpvalue = xmalloc (cbData)) != NULL
1649 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1651 RegCloseKey (hrootkey);
1652 return (lpvalue);
1655 xfree (lpvalue);
1657 RegCloseKey (hrootkey);
1660 return (NULL);
1663 char *get_emacs_configuration (void);
1665 void
1666 init_environment (char ** argv)
1668 static const char * const tempdirs[] = {
1669 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1672 int i;
1674 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1676 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1677 temporary files and assume "/tmp" if $TMPDIR is unset, which
1678 will break on DOS/Windows. Refuse to work if we cannot find
1679 a directory, not even "c:/", usable for that purpose. */
1680 for (i = 0; i < imax ; i++)
1682 const char *tmp = tempdirs[i];
1684 if (*tmp == '$')
1685 tmp = getenv (tmp + 1);
1686 /* Note that `access' can lie to us if the directory resides on a
1687 read-only filesystem, like CD-ROM or a write-protected floppy.
1688 The only way to be really sure is to actually create a file and
1689 see if it succeeds. But I think that's too much to ask. */
1691 /* MSVCRT's _access crashes with D_OK. */
1692 if (tmp && sys_access (tmp, D_OK) == 0)
1694 char * var = alloca (strlen (tmp) + 8);
1695 sprintf (var, "TMPDIR=%s", tmp);
1696 _putenv (strdup (var));
1697 break;
1700 if (i >= imax)
1701 cmd_error_internal
1702 (Fcons (Qerror,
1703 Fcons (build_string ("no usable temporary directories found!!"),
1704 Qnil)),
1705 "While setting TMPDIR: ");
1707 /* Check for environment variables and use registry settings if they
1708 don't exist. Fallback on default values where applicable. */
1710 int i;
1711 LPBYTE lpval;
1712 DWORD dwType;
1713 char locale_name[32];
1714 char default_home[MAX_PATH];
1715 int appdata = 0;
1717 static const struct env_entry
1719 char * name;
1720 char * def_value;
1721 } dflt_envvars[] =
1723 /* If the default value is NULL, we will use the value from the
1724 outside environment or the Registry, but will not push the
1725 variable into the Emacs environment if it is defined neither
1726 in the Registry nor in the outside environment. */
1727 {"HOME", "C:/"},
1728 {"PRELOAD_WINSOCK", NULL},
1729 {"emacs_dir", "C:/emacs"},
1730 {"EMACSLOADPATH", NULL},
1731 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1732 {"EMACSDATA", NULL},
1733 {"EMACSPATH", NULL},
1734 {"INFOPATH", NULL},
1735 {"EMACSDOC", NULL},
1736 {"TERM", "cmd"},
1737 {"LANG", NULL},
1740 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1742 /* We need to copy dflt_envvars[] and work on the copy because we
1743 don't want the dumped Emacs to inherit the values of
1744 environment variables we saw during dumping (which could be on
1745 a different system). The defaults above must be left intact. */
1746 struct env_entry env_vars[N_ENV_VARS];
1748 for (i = 0; i < N_ENV_VARS; i++)
1749 env_vars[i] = dflt_envvars[i];
1751 /* For backwards compatibility, check if a .emacs file exists in C:/
1752 If not, then we can try to default to the appdata directory under the
1753 user's profile, which is more likely to be writable. */
1754 if (!check_existing ("C:/.emacs"))
1756 HRESULT profile_result;
1757 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1758 of Windows 95 and NT4 that have not been updated to include
1759 MSIE 5. */
1760 ShGetFolderPath_fn get_folder_path;
1761 get_folder_path = (ShGetFolderPath_fn)
1762 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1764 if (get_folder_path != NULL)
1766 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1767 0, default_home);
1769 /* If we can't get the appdata dir, revert to old behavior. */
1770 if (profile_result == S_OK)
1772 env_vars[0].def_value = default_home;
1773 appdata = 1;
1778 /* Get default locale info and use it for LANG. */
1779 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1780 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1781 locale_name, sizeof (locale_name)))
1783 for (i = 0; i < N_ENV_VARS; i++)
1785 if (strcmp (env_vars[i].name, "LANG") == 0)
1787 env_vars[i].def_value = locale_name;
1788 break;
1793 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1795 /* Treat emacs_dir specially: set it unconditionally based on our
1796 location. */
1798 char *p;
1799 char modname[MAX_PATH];
1801 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1802 emacs_abort ();
1803 if ((p = _mbsrchr (modname, '\\')) == NULL)
1804 emacs_abort ();
1805 *p = 0;
1807 if ((p = _mbsrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1809 char buf[SET_ENV_BUF_SIZE];
1811 *p = 0;
1812 for (p = modname; *p; p = CharNext (p))
1813 if (*p == '\\') *p = '/';
1815 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1816 _putenv (strdup (buf));
1818 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1820 /* FIXME: should use substring of get_emacs_configuration ().
1821 But I don't think the Windows build supports alpha, mips etc
1822 anymore, so have taken the easy option for now. */
1823 else if (p && (xstrcasecmp (p, "\\i386") == 0
1824 || xstrcasecmp (p, "\\AMD64") == 0))
1826 *p = 0;
1827 p = _mbsrchr (modname, '\\');
1828 if (p != NULL)
1830 *p = 0;
1831 p = _mbsrchr (modname, '\\');
1832 if (p && xstrcasecmp (p, "\\src") == 0)
1834 char buf[SET_ENV_BUF_SIZE];
1836 *p = 0;
1837 for (p = modname; *p; p = CharNext (p))
1838 if (*p == '\\') *p = '/';
1840 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1841 _putenv (strdup (buf));
1847 for (i = 0; i < N_ENV_VARS; i++)
1849 if (!getenv (env_vars[i].name))
1851 int dont_free = 0;
1853 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1854 /* Also ignore empty environment variables. */
1855 || *lpval == 0)
1857 xfree (lpval);
1858 lpval = env_vars[i].def_value;
1859 dwType = REG_EXPAND_SZ;
1860 dont_free = 1;
1861 if (!strcmp (env_vars[i].name, "HOME") && !appdata)
1862 Vdelayed_warnings_list
1863 = Fcons (listn (CONSTYPE_HEAP, 2,
1864 intern ("initialization"),
1865 build_string ("Setting HOME to C:\\ by default is deprecated")),
1866 Vdelayed_warnings_list);
1869 if (lpval)
1871 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1873 if (dwType == REG_EXPAND_SZ)
1874 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
1875 else if (dwType == REG_SZ)
1876 strcpy (buf1, lpval);
1877 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1879 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
1880 buf1);
1881 _putenv (strdup (buf2));
1884 if (!dont_free)
1885 xfree (lpval);
1891 /* Rebuild system configuration to reflect invoking system. */
1892 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1894 /* Another special case: on NT, the PATH variable is actually named
1895 "Path" although cmd.exe (perhaps NT itself) arranges for
1896 environment variable lookup and setting to be case insensitive.
1897 However, Emacs assumes a fully case sensitive environment, so we
1898 need to change "Path" to "PATH" to match the expectations of
1899 various elisp packages. We do this by the sneaky method of
1900 modifying the string in the C runtime environ entry.
1902 The same applies to COMSPEC. */
1904 char ** envp;
1906 for (envp = environ; *envp; envp++)
1907 if (_strnicmp (*envp, "PATH=", 5) == 0)
1908 memcpy (*envp, "PATH=", 5);
1909 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1910 memcpy (*envp, "COMSPEC=", 8);
1913 /* Remember the initial working directory for getwd. */
1914 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
1915 Does it matter anywhere in Emacs? */
1916 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1917 emacs_abort ();
1920 static char modname[MAX_PATH];
1922 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1923 emacs_abort ();
1924 argv[0] = modname;
1927 /* Determine if there is a middle mouse button, to allow parse_button
1928 to decide whether right mouse events should be mouse-2 or
1929 mouse-3. */
1930 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1932 init_user_info ();
1935 /* Called from expand-file-name when default-directory is not a string. */
1937 char *
1938 emacs_root_dir (void)
1940 static char root_dir[FILENAME_MAX];
1941 const char *p;
1943 p = getenv ("emacs_dir");
1944 if (p == NULL)
1945 emacs_abort ();
1946 strcpy (root_dir, p);
1947 root_dir[parse_root (root_dir, NULL)] = '\0';
1948 dostounix_filename (root_dir);
1949 return root_dir;
1952 /* We don't have scripts to automatically determine the system configuration
1953 for Emacs before it's compiled, and we don't want to have to make the
1954 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1955 routine. */
1957 char *
1958 get_emacs_configuration (void)
1960 char *arch, *oem, *os;
1961 int build_num;
1962 static char configuration_buffer[32];
1964 /* Determine the processor type. */
1965 switch (get_processor_type ())
1968 #ifdef PROCESSOR_INTEL_386
1969 case PROCESSOR_INTEL_386:
1970 case PROCESSOR_INTEL_486:
1971 case PROCESSOR_INTEL_PENTIUM:
1972 #ifdef _WIN64
1973 arch = "amd64";
1974 #else
1975 arch = "i386";
1976 #endif
1977 break;
1978 #endif
1979 #ifdef PROCESSOR_AMD_X8664
1980 case PROCESSOR_AMD_X8664:
1981 arch = "amd64";
1982 break;
1983 #endif
1985 #ifdef PROCESSOR_MIPS_R2000
1986 case PROCESSOR_MIPS_R2000:
1987 case PROCESSOR_MIPS_R3000:
1988 case PROCESSOR_MIPS_R4000:
1989 arch = "mips";
1990 break;
1991 #endif
1993 #ifdef PROCESSOR_ALPHA_21064
1994 case PROCESSOR_ALPHA_21064:
1995 arch = "alpha";
1996 break;
1997 #endif
1999 default:
2000 arch = "unknown";
2001 break;
2004 /* Use the OEM field to reflect the compiler/library combination. */
2005 #ifdef _MSC_VER
2006 #define COMPILER_NAME "msvc"
2007 #else
2008 #ifdef __GNUC__
2009 #define COMPILER_NAME "mingw"
2010 #else
2011 #define COMPILER_NAME "unknown"
2012 #endif
2013 #endif
2014 oem = COMPILER_NAME;
2016 switch (osinfo_cache.dwPlatformId) {
2017 case VER_PLATFORM_WIN32_NT:
2018 os = "nt";
2019 build_num = osinfo_cache.dwBuildNumber;
2020 break;
2021 case VER_PLATFORM_WIN32_WINDOWS:
2022 if (osinfo_cache.dwMinorVersion == 0) {
2023 os = "windows95";
2024 } else {
2025 os = "windows98";
2027 build_num = LOWORD (osinfo_cache.dwBuildNumber);
2028 break;
2029 case VER_PLATFORM_WIN32s:
2030 /* Not supported, should not happen. */
2031 os = "windows32s";
2032 build_num = LOWORD (osinfo_cache.dwBuildNumber);
2033 break;
2034 default:
2035 os = "unknown";
2036 build_num = 0;
2037 break;
2040 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
2041 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
2042 get_w32_major_version (), get_w32_minor_version (), build_num);
2043 } else {
2044 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
2047 return configuration_buffer;
2050 char *
2051 get_emacs_configuration_options (void)
2053 static char *options_buffer;
2054 char cv[32]; /* Enough for COMPILER_VERSION. */
2055 char *options[] = {
2056 cv, /* To be filled later. */
2057 #ifdef EMACSDEBUG
2058 " --no-opt",
2059 #endif
2060 #ifdef ENABLE_CHECKING
2061 " --enable-checking",
2062 #endif
2063 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
2064 with a starting space to save work here. */
2065 #ifdef USER_CFLAGS
2066 " --cflags", USER_CFLAGS,
2067 #endif
2068 #ifdef USER_LDFLAGS
2069 " --ldflags", USER_LDFLAGS,
2070 #endif
2071 NULL
2073 size_t size = 0;
2074 int i;
2076 /* Work out the effective configure options for this build. */
2077 #ifdef _MSC_VER
2078 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
2079 #else
2080 #ifdef __GNUC__
2081 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
2082 #else
2083 #define COMPILER_VERSION ""
2084 #endif
2085 #endif
2087 if (_snprintf (cv, sizeof (cv) - 1, COMPILER_VERSION) < 0)
2088 return "Error: not enough space for compiler version";
2089 cv[sizeof (cv) - 1] = '\0';
2091 for (i = 0; options[i]; i++)
2092 size += strlen (options[i]);
2094 options_buffer = xmalloc (size + 1);
2095 options_buffer[0] = '\0';
2097 for (i = 0; options[i]; i++)
2098 strcat (options_buffer, options[i]);
2100 return options_buffer;
2104 #include <sys/timeb.h>
2106 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2107 void
2108 gettimeofday (struct timeval *tv, struct timezone *tz)
2110 struct _timeb tb;
2111 _ftime (&tb);
2113 tv->tv_sec = tb.time;
2114 tv->tv_usec = tb.millitm * 1000L;
2115 /* Implementation note: _ftime sometimes doesn't update the dstflag
2116 according to the new timezone when the system timezone is
2117 changed. We could fix that by using GetSystemTime and
2118 GetTimeZoneInformation, but that doesn't seem necessary, since
2119 Emacs always calls gettimeofday with the 2nd argument NULL (see
2120 current_emacs_time). */
2121 if (tz)
2123 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2124 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2128 /* Emulate fdutimens. */
2130 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2131 TIMESPEC[0] and TIMESPEC[1], respectively.
2132 FD must be either negative -- in which case it is ignored --
2133 or a file descriptor that is open on FILE.
2134 If FD is nonnegative, then FILE can be NULL, which means
2135 use just futimes instead of utimes.
2136 If TIMESPEC is null, FAIL.
2137 Return 0 on success, -1 (setting errno) on failure. */
2140 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2142 struct _utimbuf ut;
2144 if (!timespec)
2146 errno = ENOSYS;
2147 return -1;
2149 if (fd < 0 && !file)
2151 errno = EBADF;
2152 return -1;
2154 ut.actime = timespec[0].tv_sec;
2155 ut.modtime = timespec[1].tv_sec;
2156 if (fd >= 0)
2157 return _futime (fd, &ut);
2158 else
2159 return _utime (file, &ut);
2163 /* ------------------------------------------------------------------------- */
2164 /* IO support and wrapper functions for the Windows API. */
2165 /* ------------------------------------------------------------------------- */
2167 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2168 on network directories, so we handle that case here.
2169 (Ulrich Leodolter, 1/11/95). */
2170 char *
2171 sys_ctime (const time_t *t)
2173 char *str = (char *) ctime (t);
2174 return (str ? str : "Sun Jan 01 00:00:00 1970");
2177 /* Emulate sleep...we could have done this with a define, but that
2178 would necessitate including windows.h in the files that used it.
2179 This is much easier. */
2180 void
2181 sys_sleep (int seconds)
2183 Sleep (seconds * 1000);
2186 /* Internal MSVC functions for low-level descriptor munging */
2187 extern int __cdecl _set_osfhnd (int fd, long h);
2188 extern int __cdecl _free_osfhnd (int fd);
2190 /* parallel array of private info on file handles */
2191 filedesc fd_info [ MAXDESC ];
2193 typedef struct volume_info_data {
2194 struct volume_info_data * next;
2196 /* time when info was obtained */
2197 DWORD timestamp;
2199 /* actual volume info */
2200 char * root_dir;
2201 DWORD serialnum;
2202 DWORD maxcomp;
2203 DWORD flags;
2204 char * name;
2205 char * type;
2206 } volume_info_data;
2208 /* Global referenced by various functions. */
2209 static volume_info_data volume_info;
2211 /* Vector to indicate which drives are local and fixed (for which cached
2212 data never expires). */
2213 static BOOL fixed_drives[26];
2215 /* Consider cached volume information to be stale if older than 10s,
2216 at least for non-local drives. Info for fixed drives is never stale. */
2217 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2218 #define VOLINFO_STILL_VALID( root_dir, info ) \
2219 ( ( isalpha (root_dir[0]) && \
2220 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2221 || GetTickCount () - info->timestamp < 10000 )
2223 /* Cache support functions. */
2225 /* Simple linked list with linear search is sufficient. */
2226 static volume_info_data *volume_cache = NULL;
2228 static volume_info_data *
2229 lookup_volume_info (char * root_dir)
2231 volume_info_data * info;
2233 for (info = volume_cache; info; info = info->next)
2234 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2235 break;
2236 return info;
2239 static void
2240 add_volume_info (char * root_dir, volume_info_data * info)
2242 info->root_dir = xstrdup (root_dir);
2243 info->next = volume_cache;
2244 volume_cache = info;
2248 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2249 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2250 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2251 static volume_info_data *
2252 GetCachedVolumeInformation (char * root_dir)
2254 volume_info_data * info;
2255 char default_root[ MAX_PATH ];
2257 /* NULL for root_dir means use root from current directory. */
2258 if (root_dir == NULL)
2260 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
2261 return NULL;
2262 parse_root (default_root, &root_dir);
2263 *root_dir = 0;
2264 root_dir = default_root;
2267 /* Local fixed drives can be cached permanently. Removable drives
2268 cannot be cached permanently, since the volume name and serial
2269 number (if nothing else) can change. Remote drives should be
2270 treated as if they are removable, since there is no sure way to
2271 tell whether they are or not. Also, the UNC association of drive
2272 letters mapped to remote volumes can be changed at any time (even
2273 by other processes) without notice.
2275 As a compromise, so we can benefit from caching info for remote
2276 volumes, we use a simple expiry mechanism to invalidate cache
2277 entries that are more than ten seconds old. */
2279 #if 0
2280 /* No point doing this, because WNetGetConnection is even slower than
2281 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2282 GetDriveType is about the only call of this type which does not
2283 involve network access, and so is extremely quick). */
2285 /* Map drive letter to UNC if remote. */
2286 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2288 char remote_name[ 256 ];
2289 char drive[3] = { root_dir[0], ':' };
2291 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2292 == NO_ERROR)
2293 /* do something */ ;
2295 #endif
2297 info = lookup_volume_info (root_dir);
2299 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2301 char name[ 256 ];
2302 DWORD serialnum;
2303 DWORD maxcomp;
2304 DWORD flags;
2305 char type[ 256 ];
2307 /* Info is not cached, or is stale. */
2308 if (!GetVolumeInformation (root_dir,
2309 name, sizeof (name),
2310 &serialnum,
2311 &maxcomp,
2312 &flags,
2313 type, sizeof (type)))
2314 return NULL;
2316 /* Cache the volume information for future use, overwriting existing
2317 entry if present. */
2318 if (info == NULL)
2320 info = xmalloc (sizeof (volume_info_data));
2321 add_volume_info (root_dir, info);
2323 else
2325 xfree (info->name);
2326 xfree (info->type);
2329 info->name = xstrdup (name);
2330 info->serialnum = serialnum;
2331 info->maxcomp = maxcomp;
2332 info->flags = flags;
2333 info->type = xstrdup (type);
2334 info->timestamp = GetTickCount ();
2337 return info;
2340 /* Get information on the volume where NAME is held; set path pointer to
2341 start of pathname in NAME (past UNC header\volume header if present),
2342 if pPath is non-NULL.
2344 Note: if NAME includes symlinks, the information is for the volume
2345 of the symlink, not of its target. That's because, even though
2346 GetVolumeInformation returns information about the symlink target
2347 of its argument, we only pass the root directory to
2348 GetVolumeInformation, not the full NAME. */
2349 static int
2350 get_volume_info (const char * name, const char ** pPath)
2352 char temp[MAX_PATH];
2353 char *rootname = NULL; /* default to current volume */
2354 volume_info_data * info;
2356 if (name == NULL)
2357 return FALSE;
2359 /* Find the root name of the volume if given. */
2360 if (isalpha (name[0]) && name[1] == ':')
2362 rootname = temp;
2363 temp[0] = *name++;
2364 temp[1] = *name++;
2365 temp[2] = '\\';
2366 temp[3] = 0;
2368 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2370 char *str = temp;
2371 int slashes = 4;
2372 rootname = temp;
2375 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2376 break;
2377 *str++ = *name++;
2379 while ( *name );
2381 *str++ = '\\';
2382 *str = 0;
2385 if (pPath)
2386 *pPath = name;
2388 info = GetCachedVolumeInformation (rootname);
2389 if (info != NULL)
2391 /* Set global referenced by other functions. */
2392 volume_info = *info;
2393 return TRUE;
2395 return FALSE;
2398 /* Determine if volume is FAT format (ie. only supports short 8.3
2399 names); also set path pointer to start of pathname in name, if
2400 pPath is non-NULL. */
2401 static int
2402 is_fat_volume (const char * name, const char ** pPath)
2404 if (get_volume_info (name, pPath))
2405 return (volume_info.maxcomp == 12);
2406 return FALSE;
2409 /* Map filename to a valid 8.3 name if necessary.
2410 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2411 const char *
2412 map_w32_filename (const char * name, const char ** pPath)
2414 static char shortname[MAX_PATH];
2415 char * str = shortname;
2416 char c;
2417 char * path;
2418 const char * save_name = name;
2420 if (strlen (name) >= MAX_PATH)
2422 /* Return a filename which will cause callers to fail. */
2423 strcpy (shortname, "?");
2424 return shortname;
2427 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2429 register int left = 8; /* maximum number of chars in part */
2430 register int extn = 0; /* extension added? */
2431 register int dots = 2; /* maximum number of dots allowed */
2433 while (name < path)
2434 *str++ = *name++; /* skip past UNC header */
2436 while ((c = *name++))
2438 switch ( c )
2440 case ':':
2441 case '\\':
2442 case '/':
2443 *str++ = (c == ':' ? ':' : '\\');
2444 extn = 0; /* reset extension flags */
2445 dots = 2; /* max 2 dots */
2446 left = 8; /* max length 8 for main part */
2447 break;
2448 case '.':
2449 if ( dots )
2451 /* Convert path components of the form .xxx to _xxx,
2452 but leave . and .. as they are. This allows .emacs
2453 to be read as _emacs, for example. */
2455 if (! *name ||
2456 *name == '.' ||
2457 IS_DIRECTORY_SEP (*name))
2459 *str++ = '.';
2460 dots--;
2462 else
2464 *str++ = '_';
2465 left--;
2466 dots = 0;
2469 else if ( !extn )
2471 *str++ = '.';
2472 extn = 1; /* we've got an extension */
2473 left = 3; /* 3 chars in extension */
2475 else
2477 /* any embedded dots after the first are converted to _ */
2478 *str++ = '_';
2480 break;
2481 case '~':
2482 case '#': /* don't lose these, they're important */
2483 if ( ! left )
2484 str[-1] = c; /* replace last character of part */
2485 /* FALLTHRU */
2486 default:
2487 if ( left )
2489 *str++ = tolower (c); /* map to lower case (looks nicer) */
2490 left--;
2491 dots = 0; /* started a path component */
2493 break;
2496 *str = '\0';
2498 else
2500 strcpy (shortname, name);
2501 unixtodos_filename (shortname);
2504 if (pPath)
2505 *pPath = shortname + (path - save_name);
2507 return shortname;
2510 static int
2511 is_exec (const char * name)
2513 char * p = strrchr (name, '.');
2514 return
2515 (p != NULL
2516 && (xstrcasecmp (p, ".exe") == 0 ||
2517 xstrcasecmp (p, ".com") == 0 ||
2518 xstrcasecmp (p, ".bat") == 0 ||
2519 xstrcasecmp (p, ".cmd") == 0));
2522 /* Emulate the Unix directory procedures opendir, closedir,
2523 and readdir. We can't use the procedures supplied in sysdep.c,
2524 so we provide them here. */
2526 struct direct dir_static; /* simulated directory contents */
2527 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2528 static int dir_is_fat;
2529 static char dir_pathname[MAXPATHLEN+1];
2530 static WIN32_FIND_DATA dir_find_data;
2532 /* Support shares on a network resource as subdirectories of a read-only
2533 root directory. */
2534 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2535 static HANDLE open_unc_volume (const char *);
2536 static char *read_unc_volume (HANDLE, char *, int);
2537 static void close_unc_volume (HANDLE);
2539 DIR *
2540 opendir (char *filename)
2542 DIR *dirp;
2544 /* Opening is done by FindFirstFile. However, a read is inherent to
2545 this operation, so we defer the open until read time. */
2547 if (dir_find_handle != INVALID_HANDLE_VALUE)
2548 return NULL;
2549 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2550 return NULL;
2552 /* Note: We don't support traversal of UNC volumes via symlinks.
2553 Doing so would mean punishing 99.99% of use cases by resolving
2554 all the possible symlinks in FILENAME, recursively. */
2555 if (is_unc_volume (filename))
2557 wnet_enum_handle = open_unc_volume (filename);
2558 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2559 return NULL;
2562 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2563 return NULL;
2565 dirp->dd_fd = 0;
2566 dirp->dd_loc = 0;
2567 dirp->dd_size = 0;
2569 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2570 dir_pathname[MAXPATHLEN] = '\0';
2571 /* Note: We don't support symlinks to file names on FAT volumes.
2572 Doing so would mean punishing 99.99% of use cases by resolving
2573 all the possible symlinks in FILENAME, recursively. */
2574 dir_is_fat = is_fat_volume (filename, NULL);
2576 return dirp;
2579 void
2580 closedir (DIR *dirp)
2582 /* If we have a find-handle open, close it. */
2583 if (dir_find_handle != INVALID_HANDLE_VALUE)
2585 FindClose (dir_find_handle);
2586 dir_find_handle = INVALID_HANDLE_VALUE;
2588 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2590 close_unc_volume (wnet_enum_handle);
2591 wnet_enum_handle = INVALID_HANDLE_VALUE;
2593 xfree ((char *) dirp);
2596 struct direct *
2597 readdir (DIR *dirp)
2599 int downcase = !NILP (Vw32_downcase_file_names);
2601 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2603 if (!read_unc_volume (wnet_enum_handle,
2604 dir_find_data.cFileName,
2605 MAX_PATH))
2606 return NULL;
2608 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2609 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2611 char filename[MAXNAMLEN + 3];
2612 int ln;
2614 strcpy (filename, dir_pathname);
2615 ln = strlen (filename) - 1;
2616 if (!IS_DIRECTORY_SEP (filename[ln]))
2617 strcat (filename, "\\");
2618 strcat (filename, "*");
2620 /* Note: No need to resolve symlinks in FILENAME, because
2621 FindFirst opens the directory that is the target of a
2622 symlink. */
2623 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2625 if (dir_find_handle == INVALID_HANDLE_VALUE)
2626 return NULL;
2628 else
2630 if (!FindNextFile (dir_find_handle, &dir_find_data))
2631 return NULL;
2634 /* Emacs never uses this value, so don't bother making it match
2635 value returned by stat(). */
2636 dir_static.d_ino = 1;
2638 strcpy (dir_static.d_name, dir_find_data.cFileName);
2640 /* If the file name in cFileName[] includes `?' characters, it means
2641 the original file name used characters that cannot be represented
2642 by the current ANSI codepage. To avoid total lossage, retrieve
2643 the short 8+3 alias of the long file name. */
2644 if (_mbspbrk (dir_static.d_name, "?"))
2646 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2647 downcase = 1; /* 8+3 aliases are returned in all caps */
2649 dir_static.d_namlen = strlen (dir_static.d_name);
2650 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
2651 dir_static.d_namlen - dir_static.d_namlen % 4;
2653 /* If the file name in cFileName[] includes `?' characters, it means
2654 the original file name used characters that cannot be represented
2655 by the current ANSI codepage. To avoid total lossage, retrieve
2656 the short 8+3 alias of the long file name. */
2657 if (_mbspbrk (dir_find_data.cFileName, "?"))
2659 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2660 /* 8+3 aliases are returned in all caps, which could break
2661 various alists that look at filenames' extensions. */
2662 downcase = 1;
2664 else
2665 strcpy (dir_static.d_name, dir_find_data.cFileName);
2666 dir_static.d_namlen = strlen (dir_static.d_name);
2667 if (dir_is_fat)
2668 _mbslwr (dir_static.d_name);
2669 else if (downcase)
2671 register char *p;
2672 int dbcs_p = max_filename_mbslen () > 1;
2673 for (p = dir_static.d_name; *p; )
2675 if (*p >= 'a' && *p <= 'z')
2676 break;
2677 if (dbcs_p)
2678 p = CharNextExA (file_name_codepage, p, 0);
2679 else
2680 p++;
2682 if (!*p)
2683 _mbslwr (dir_static.d_name);
2686 return &dir_static;
2689 static HANDLE
2690 open_unc_volume (const char *path)
2692 NETRESOURCE nr;
2693 HANDLE henum;
2694 int result;
2696 nr.dwScope = RESOURCE_GLOBALNET;
2697 nr.dwType = RESOURCETYPE_DISK;
2698 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2699 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2700 nr.lpLocalName = NULL;
2701 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
2702 nr.lpComment = NULL;
2703 nr.lpProvider = NULL;
2705 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2706 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2708 if (result == NO_ERROR)
2709 return henum;
2710 else
2711 return INVALID_HANDLE_VALUE;
2714 static char *
2715 read_unc_volume (HANDLE henum, char *readbuf, int size)
2717 DWORD count;
2718 int result;
2719 DWORD bufsize = 512;
2720 char *buffer;
2721 char *ptr;
2723 count = 1;
2724 buffer = alloca (bufsize);
2725 result = WNetEnumResource (henum, &count, buffer, &bufsize);
2726 if (result != NO_ERROR)
2727 return NULL;
2729 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2730 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2731 ptr += 2;
2732 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2733 ptr++;
2735 strncpy (readbuf, ptr, size);
2736 return readbuf;
2739 static void
2740 close_unc_volume (HANDLE henum)
2742 if (henum != INVALID_HANDLE_VALUE)
2743 WNetCloseEnum (henum);
2746 static DWORD
2747 unc_volume_file_attributes (const char *path)
2749 HANDLE henum;
2750 DWORD attrs;
2752 henum = open_unc_volume (path);
2753 if (henum == INVALID_HANDLE_VALUE)
2754 return -1;
2756 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2758 close_unc_volume (henum);
2760 return attrs;
2763 /* Ensure a network connection is authenticated. */
2764 static void
2765 logon_network_drive (const char *path)
2767 NETRESOURCE resource;
2768 char share[MAX_PATH];
2769 int i, n_slashes;
2770 char drive[4];
2771 UINT drvtype;
2773 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
2774 drvtype = DRIVE_REMOTE;
2775 else if (path[0] == '\0' || path[1] != ':')
2776 drvtype = GetDriveType (NULL);
2777 else
2779 drive[0] = path[0];
2780 drive[1] = ':';
2781 drive[2] = '\\';
2782 drive[3] = '\0';
2783 drvtype = GetDriveType (drive);
2786 /* Only logon to networked drives. */
2787 if (drvtype != DRIVE_REMOTE)
2788 return;
2790 n_slashes = 2;
2791 strncpy (share, path, MAX_PATH);
2792 /* Truncate to just server and share name. */
2793 for (i = 2; i < MAX_PATH; i++)
2795 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2797 share[i] = '\0';
2798 break;
2802 resource.dwType = RESOURCETYPE_DISK;
2803 resource.lpLocalName = NULL;
2804 resource.lpRemoteName = share;
2805 resource.lpProvider = NULL;
2807 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2810 /* Shadow some MSVC runtime functions to map requests for long filenames
2811 to reasonable short names if necessary. This was originally added to
2812 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2813 long file names. */
2816 sys_access (const char * path, int mode)
2818 DWORD attributes;
2820 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
2821 newer versions blow up when passed D_OK. */
2822 path = map_w32_filename (path, NULL);
2823 /* If the last element of PATH is a symlink, we need to resolve it
2824 to get the attributes of its target file. Note: any symlinks in
2825 PATH elements other than the last one are transparently resolved
2826 by GetFileAttributes below. */
2827 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
2828 path = chase_symlinks (path);
2830 if ((attributes = GetFileAttributes (path)) == -1)
2832 DWORD w32err = GetLastError ();
2834 switch (w32err)
2836 case ERROR_INVALID_NAME:
2837 case ERROR_BAD_PATHNAME:
2838 if (is_unc_volume (path))
2840 attributes = unc_volume_file_attributes (path);
2841 if (attributes == -1)
2843 errno = EACCES;
2844 return -1;
2846 break;
2848 /* FALLTHROUGH */
2849 case ERROR_FILE_NOT_FOUND:
2850 case ERROR_BAD_NETPATH:
2851 errno = ENOENT;
2852 break;
2853 default:
2854 errno = EACCES;
2855 break;
2857 return -1;
2859 if ((mode & X_OK) != 0 && !is_exec (path))
2861 errno = EACCES;
2862 return -1;
2864 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2866 errno = EACCES;
2867 return -1;
2869 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2871 errno = EACCES;
2872 return -1;
2874 return 0;
2878 sys_chdir (const char * path)
2880 return _chdir (map_w32_filename (path, NULL));
2884 sys_chmod (const char * path, int mode)
2886 path = chase_symlinks (map_w32_filename (path, NULL));
2887 return _chmod (path, mode);
2891 sys_chown (const char *path, uid_t owner, gid_t group)
2893 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2894 return -1;
2895 return 0;
2899 sys_creat (const char * path, int mode)
2901 return _creat (map_w32_filename (path, NULL), mode);
2904 FILE *
2905 sys_fopen (const char * path, const char * mode)
2907 int fd;
2908 int oflag;
2909 const char * mode_save = mode;
2911 /* Force all file handles to be non-inheritable. This is necessary to
2912 ensure child processes don't unwittingly inherit handles that might
2913 prevent future file access. */
2915 if (mode[0] == 'r')
2916 oflag = O_RDONLY;
2917 else if (mode[0] == 'w' || mode[0] == 'a')
2918 oflag = O_WRONLY | O_CREAT | O_TRUNC;
2919 else
2920 return NULL;
2922 /* Only do simplistic option parsing. */
2923 while (*++mode)
2924 if (mode[0] == '+')
2926 oflag &= ~(O_RDONLY | O_WRONLY);
2927 oflag |= O_RDWR;
2929 else if (mode[0] == 'b')
2931 oflag &= ~O_TEXT;
2932 oflag |= O_BINARY;
2934 else if (mode[0] == 't')
2936 oflag &= ~O_BINARY;
2937 oflag |= O_TEXT;
2939 else break;
2941 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2942 if (fd < 0)
2943 return NULL;
2945 return _fdopen (fd, mode_save);
2948 /* This only works on NTFS volumes, but is useful to have. */
2950 sys_link (const char * old, const char * new)
2952 HANDLE fileh;
2953 int result = -1;
2954 char oldname[MAX_PATH], newname[MAX_PATH];
2956 if (old == NULL || new == NULL)
2958 errno = ENOENT;
2959 return -1;
2962 strcpy (oldname, map_w32_filename (old, NULL));
2963 strcpy (newname, map_w32_filename (new, NULL));
2965 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2966 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2967 if (fileh != INVALID_HANDLE_VALUE)
2969 int wlen;
2971 /* Confusingly, the "alternate" stream name field does not apply
2972 when restoring a hard link, and instead contains the actual
2973 stream data for the link (ie. the name of the link to create).
2974 The WIN32_STREAM_ID structure before the cStreamName field is
2975 the stream header, which is then immediately followed by the
2976 stream data. */
2978 struct {
2979 WIN32_STREAM_ID wid;
2980 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2981 } data;
2983 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2984 data.wid.cStreamName, MAX_PATH);
2985 if (wlen > 0)
2987 LPVOID context = NULL;
2988 DWORD wbytes = 0;
2990 data.wid.dwStreamId = BACKUP_LINK;
2991 data.wid.dwStreamAttributes = 0;
2992 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
2993 data.wid.Size.HighPart = 0;
2994 data.wid.dwStreamNameSize = 0;
2996 if (BackupWrite (fileh, (LPBYTE)&data,
2997 offsetof (WIN32_STREAM_ID, cStreamName)
2998 + data.wid.Size.LowPart,
2999 &wbytes, FALSE, FALSE, &context)
3000 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
3002 /* succeeded */
3003 result = 0;
3005 else
3007 /* Should try mapping GetLastError to errno; for now just
3008 indicate a general error (eg. links not supported). */
3009 errno = EINVAL; // perhaps EMLINK?
3013 CloseHandle (fileh);
3015 else
3016 errno = ENOENT;
3018 return result;
3022 sys_mkdir (const char * path)
3024 return _mkdir (map_w32_filename (path, NULL));
3027 /* Because of long name mapping issues, we need to implement this
3028 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
3029 a unique name, instead of setting the input template to an empty
3030 string.
3032 Standard algorithm seems to be use pid or tid with a letter on the
3033 front (in place of the 6 X's) and cycle through the letters to find a
3034 unique name. We extend that to allow any reasonable character as the
3035 first of the 6 X's. */
3036 char *
3037 sys_mktemp (char * template)
3039 char * p;
3040 int i;
3041 unsigned uid = GetCurrentThreadId ();
3042 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3044 if (template == NULL)
3045 return NULL;
3046 p = template + strlen (template);
3047 i = 5;
3048 /* replace up to the last 5 X's with uid in decimal */
3049 while (--p >= template && p[0] == 'X' && --i >= 0)
3051 p[0] = '0' + uid % 10;
3052 uid /= 10;
3055 if (i < 0 && p[0] == 'X')
3057 i = 0;
3060 int save_errno = errno;
3061 p[0] = first_char[i];
3062 if (sys_access (template, 0) < 0)
3064 errno = save_errno;
3065 return template;
3068 while (++i < sizeof (first_char));
3071 /* Template is badly formed or else we can't generate a unique name,
3072 so return empty string */
3073 template[0] = 0;
3074 return template;
3078 sys_open (const char * path, int oflag, int mode)
3080 const char* mpath = map_w32_filename (path, NULL);
3081 /* Try to open file without _O_CREAT, to be able to write to hidden
3082 and system files. Force all file handles to be
3083 non-inheritable. */
3084 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
3085 if (res >= 0)
3086 return res;
3087 return _open (mpath, oflag | _O_NOINHERIT, mode);
3091 sys_rename (const char * oldname, const char * newname)
3093 BOOL result;
3094 char temp[MAX_PATH];
3095 int newname_dev;
3096 int oldname_dev;
3098 /* MoveFile on Windows 95 doesn't correctly change the short file name
3099 alias in a number of circumstances (it is not easy to predict when
3100 just by looking at oldname and newname, unfortunately). In these
3101 cases, renaming through a temporary name avoids the problem.
3103 A second problem on Windows 95 is that renaming through a temp name when
3104 newname is uppercase fails (the final long name ends up in
3105 lowercase, although the short alias might be uppercase) UNLESS the
3106 long temp name is not 8.3.
3108 So, on Windows 95 we always rename through a temp name, and we make sure
3109 the temp name has a long extension to ensure correct renaming. */
3111 strcpy (temp, map_w32_filename (oldname, NULL));
3113 /* volume_info is set indirectly by map_w32_filename. */
3114 oldname_dev = volume_info.serialnum;
3116 if (os_subtype == OS_9X)
3118 char * o;
3119 char * p;
3120 int i = 0;
3122 oldname = map_w32_filename (oldname, NULL);
3123 if ((o = strrchr (oldname, '\\')))
3124 o++;
3125 else
3126 o = (char *) oldname;
3128 if ((p = strrchr (temp, '\\')))
3129 p++;
3130 else
3131 p = temp;
3135 /* Force temp name to require a manufactured 8.3 alias - this
3136 seems to make the second rename work properly. */
3137 sprintf (p, "_.%s.%u", o, i);
3138 i++;
3139 result = rename (oldname, temp);
3141 /* This loop must surely terminate! */
3142 while (result < 0 && errno == EEXIST);
3143 if (result < 0)
3144 return -1;
3147 /* Emulate Unix behavior - newname is deleted if it already exists
3148 (at least if it is a file; don't do this for directories).
3150 Since we mustn't do this if we are just changing the case of the
3151 file name (we would end up deleting the file we are trying to
3152 rename!), we let rename detect if the destination file already
3153 exists - that way we avoid the possible pitfalls of trying to
3154 determine ourselves whether two names really refer to the same
3155 file, which is not always possible in the general case. (Consider
3156 all the permutations of shared or subst'd drives, etc.) */
3158 newname = map_w32_filename (newname, NULL);
3160 /* volume_info is set indirectly by map_w32_filename. */
3161 newname_dev = volume_info.serialnum;
3163 result = rename (temp, newname);
3165 if (result < 0)
3167 DWORD w32err = GetLastError ();
3169 if (errno == EACCES
3170 && newname_dev != oldname_dev)
3172 /* The implementation of `rename' on Windows does not return
3173 errno = EXDEV when you are moving a directory to a
3174 different storage device (ex. logical disk). It returns
3175 EACCES instead. So here we handle such situations and
3176 return EXDEV. */
3177 DWORD attributes;
3179 if ((attributes = GetFileAttributes (temp)) != -1
3180 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
3181 errno = EXDEV;
3183 else if (errno == EEXIST)
3185 if (_chmod (newname, 0666) != 0)
3186 return result;
3187 if (_unlink (newname) != 0)
3188 return result;
3189 result = rename (temp, newname);
3191 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
3192 && is_symlink (temp))
3194 /* This is Windows prohibiting the user from creating a
3195 symlink in another place, since that requires
3196 privileges. */
3197 errno = EPERM;
3201 return result;
3205 sys_rmdir (const char * path)
3207 return _rmdir (map_w32_filename (path, NULL));
3211 sys_unlink (const char * path)
3213 path = map_w32_filename (path, NULL);
3215 /* On Unix, unlink works without write permission. */
3216 _chmod (path, 0666);
3217 return _unlink (path);
3220 static FILETIME utc_base_ft;
3221 static ULONGLONG utc_base; /* In 100ns units */
3222 static int init = 0;
3224 #define FILETIME_TO_U64(result, ft) \
3225 do { \
3226 ULARGE_INTEGER uiTemp; \
3227 uiTemp.LowPart = (ft).dwLowDateTime; \
3228 uiTemp.HighPart = (ft).dwHighDateTime; \
3229 result = uiTemp.QuadPart; \
3230 } while (0)
3232 static void
3233 initialize_utc_base (void)
3235 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3236 SYSTEMTIME st;
3238 st.wYear = 1970;
3239 st.wMonth = 1;
3240 st.wDay = 1;
3241 st.wHour = 0;
3242 st.wMinute = 0;
3243 st.wSecond = 0;
3244 st.wMilliseconds = 0;
3246 SystemTimeToFileTime (&st, &utc_base_ft);
3247 FILETIME_TO_U64 (utc_base, utc_base_ft);
3250 static time_t
3251 convert_time (FILETIME ft)
3253 ULONGLONG tmp;
3255 if (!init)
3257 initialize_utc_base ();
3258 init = 1;
3261 if (CompareFileTime (&ft, &utc_base_ft) < 0)
3262 return 0;
3264 FILETIME_TO_U64 (tmp, ft);
3265 return (time_t) ((tmp - utc_base) / 10000000L);
3268 static void
3269 convert_from_time_t (time_t time, FILETIME * pft)
3271 ULARGE_INTEGER tmp;
3273 if (!init)
3275 initialize_utc_base ();
3276 init = 1;
3279 /* time in 100ns units since 1-Jan-1601 */
3280 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
3281 pft->dwHighDateTime = tmp.HighPart;
3282 pft->dwLowDateTime = tmp.LowPart;
3285 #if 0
3286 /* No reason to keep this; faking inode values either by hashing or even
3287 using the file index from GetInformationByHandle, is not perfect and
3288 so by default Emacs doesn't use the inode values on Windows.
3289 Instead, we now determine file-truename correctly (except for
3290 possible drive aliasing etc). */
3292 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3293 static unsigned
3294 hashval (const unsigned char * str)
3296 unsigned h = 0;
3297 while (*str)
3299 h = (h << 4) + *str++;
3300 h ^= (h >> 28);
3302 return h;
3305 /* Return the hash value of the canonical pathname, excluding the
3306 drive/UNC header, to get a hopefully unique inode number. */
3307 static DWORD
3308 generate_inode_val (const char * name)
3310 char fullname[ MAX_PATH ];
3311 char * p;
3312 unsigned hash;
3314 /* Get the truly canonical filename, if it exists. (Note: this
3315 doesn't resolve aliasing due to subst commands, or recognize hard
3316 links. */
3317 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3318 emacs_abort ();
3320 parse_root (fullname, &p);
3321 /* Normal W32 filesystems are still case insensitive. */
3322 _strlwr (p);
3323 return hashval (p);
3326 #endif
3328 static PSECURITY_DESCRIPTOR
3329 get_file_security_desc_by_handle (HANDLE h)
3331 PSECURITY_DESCRIPTOR psd = NULL;
3332 DWORD err;
3333 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3334 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3336 err = get_security_info (h, SE_FILE_OBJECT, si,
3337 NULL, NULL, NULL, NULL, &psd);
3338 if (err != ERROR_SUCCESS)
3339 return NULL;
3341 return psd;
3344 static PSECURITY_DESCRIPTOR
3345 get_file_security_desc_by_name (const char *fname)
3347 PSECURITY_DESCRIPTOR psd = NULL;
3348 DWORD sd_len, err;
3349 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3350 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3352 if (!get_file_security (fname, si, psd, 0, &sd_len))
3354 err = GetLastError ();
3355 if (err != ERROR_INSUFFICIENT_BUFFER)
3356 return NULL;
3359 psd = xmalloc (sd_len);
3360 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3362 xfree (psd);
3363 return NULL;
3366 return psd;
3369 static DWORD
3370 get_rid (PSID sid)
3372 unsigned n_subauthorities;
3374 /* Use the last sub-authority value of the RID, the relative
3375 portion of the SID, as user/group ID. */
3376 n_subauthorities = *get_sid_sub_authority_count (sid);
3377 if (n_subauthorities < 1)
3378 return 0; /* the "World" RID */
3379 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3382 /* Caching SID and account values for faster lokup. */
3384 #ifdef __GNUC__
3385 # define FLEXIBLE_ARRAY_MEMBER
3386 #else
3387 # define FLEXIBLE_ARRAY_MEMBER 1
3388 #endif
3390 struct w32_id {
3391 unsigned rid;
3392 struct w32_id *next;
3393 char name[GNLEN+1];
3394 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3397 static struct w32_id *w32_idlist;
3399 static int
3400 w32_cached_id (PSID sid, unsigned *id, char *name)
3402 struct w32_id *tail, *found;
3404 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3406 if (equal_sid ((PSID)tail->sid, sid))
3408 found = tail;
3409 break;
3412 if (found)
3414 *id = found->rid;
3415 strcpy (name, found->name);
3416 return 1;
3418 else
3419 return 0;
3422 static void
3423 w32_add_to_cache (PSID sid, unsigned id, char *name)
3425 DWORD sid_len;
3426 struct w32_id *new_entry;
3428 /* We don't want to leave behind stale cache from when Emacs was
3429 dumped. */
3430 if (initialized)
3432 sid_len = get_length_sid (sid);
3433 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3434 if (new_entry)
3436 new_entry->rid = id;
3437 strcpy (new_entry->name, name);
3438 copy_sid (sid_len, (PSID)new_entry->sid, sid);
3439 new_entry->next = w32_idlist;
3440 w32_idlist = new_entry;
3445 #define UID 1
3446 #define GID 2
3448 static int
3449 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
3451 PSID sid = NULL;
3452 char machine[MAX_COMPUTERNAME_LENGTH+1];
3453 BOOL dflt;
3454 SID_NAME_USE ignore;
3455 char name[UNLEN+1];
3456 DWORD name_len = sizeof (name);
3457 char domain[1024];
3458 DWORD domain_len = sizeof (domain);
3459 int use_dflt = 0;
3460 int result;
3462 if (what == UID)
3463 result = get_security_descriptor_owner (psd, &sid, &dflt);
3464 else if (what == GID)
3465 result = get_security_descriptor_group (psd, &sid, &dflt);
3466 else
3467 result = 0;
3469 if (!result || !is_valid_sid (sid))
3470 use_dflt = 1;
3471 else if (!w32_cached_id (sid, id, nm))
3473 if (!lookup_account_sid (NULL, sid, name, &name_len,
3474 domain, &domain_len, &ignore)
3475 || name_len > UNLEN+1)
3476 use_dflt = 1;
3477 else
3479 *id = get_rid (sid);
3480 strcpy (nm, name);
3481 w32_add_to_cache (sid, *id, name);
3484 return use_dflt;
3487 static void
3488 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, 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, &st->st_uid, st->st_uname, UID))
3500 dflt_usr = 1;
3501 if (get_name_and_id (psd, &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, buf);
3724 LocalFree (psd);
3726 else if (is_windows_9x () == TRUE)
3727 get_file_owner_and_group (NULL, 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, buf);
3732 xfree (psd);
3734 else
3735 get_file_owner_and_group (NULL, 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, 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 sys_access 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 = sys_access (tem, D_OK);
4110 else
4111 dir_access = sys_access (filename, D_OK);
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, *p2;
4344 BYTE *pend = p + lname_len;
4345 int dbcs_p = max_filename_mbslen () > 1;
4347 /* Normalize like dostounix_filename does, but we don't
4348 want to assume that lname is null-terminated. */
4349 if (dbcs_p)
4350 p2 = CharNextExA (w32_ansi_code_page, p, 0);
4351 else
4352 p2 = p + 1;
4353 if (*p && *p2 == ':' && *p >= 'A' && *p <= 'Z')
4355 *p += 'a' - 'A';
4356 p += 2;
4358 while (p <= pend)
4360 if (*p == '\\')
4361 *p = '/';
4362 if (dbcs_p)
4364 p = CharNextExA (w32_ansi_code_page, p, 0);
4365 /* CharNextExA doesn't advance at null character. */
4366 if (!*p)
4367 break;
4369 else
4370 ++p;
4372 /* Testing for null-terminated LNAME is paranoia:
4373 WideCharToMultiByte should always return a
4374 null-terminated string when its 4th argument is -1
4375 and its 3rd argument is null-terminated (which they
4376 are, see above). */
4377 if (lname[lname_len - 1] == '\0')
4378 lname_len--;
4379 if (lname_len <= buf_size)
4380 size_to_copy = lname_len;
4381 strncpy (buf, lname, size_to_copy);
4382 /* Success! */
4383 retval = size_to_copy;
4386 CloseHandle (sh);
4388 else
4390 /* CreateFile failed. */
4391 DWORD w32err2 = GetLastError ();
4393 switch (w32err2)
4395 case ERROR_FILE_NOT_FOUND:
4396 case ERROR_PATH_NOT_FOUND:
4397 errno = ENOENT;
4398 break;
4399 case ERROR_ACCESS_DENIED:
4400 case ERROR_TOO_MANY_OPEN_FILES:
4401 errno = EACCES;
4402 break;
4403 default:
4404 errno = EPERM;
4405 break;
4408 if (restore_privs)
4410 restore_privilege (&privs);
4411 revert_to_self ();
4414 return retval;
4417 /* If FILE is a symlink, return its target (stored in a static
4418 buffer); otherwise return FILE.
4420 This function repeatedly resolves symlinks in the last component of
4421 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4422 until it arrives at a file whose last component is not a symlink,
4423 or some error occurs. It returns the target of the last
4424 successfully resolved symlink in the chain. If it succeeds to
4425 resolve even a single symlink, the value returned is an absolute
4426 file name with backslashes (result of GetFullPathName). By
4427 contrast, if the original FILE is returned, it is unaltered.
4429 Note: This function can set errno even if it succeeds.
4431 Implementation note: we only resolve the last portion ("basename")
4432 of the argument FILE and of each following file in the chain,
4433 disregarding any possible symlinks in its leading directories.
4434 This is because Windows system calls and library functions
4435 transparently resolve symlinks in leading directories and return
4436 correct information, as long as the basename is not a symlink. */
4437 static char *
4438 chase_symlinks (const char *file)
4440 static char target[MAX_PATH];
4441 char link[MAX_PATH];
4442 ssize_t res, link_len;
4443 int loop_count = 0;
4445 if (is_windows_9x () == TRUE || !is_symlink (file))
4446 return (char *)file;
4448 if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0)
4449 return (char *)file;
4451 target[0] = '\0';
4452 do {
4454 /* Remove trailing slashes, as we want to resolve the last
4455 non-trivial part of the link name. */
4456 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
4457 link[link_len--] = '\0';
4459 res = readlink (link, target, MAX_PATH);
4460 if (res > 0)
4462 target[res] = '\0';
4463 if (!(IS_DEVICE_SEP (target[1])
4464 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
4466 /* Target is relative. Append it to the directory part of
4467 the symlink, then copy the result back to target. */
4468 char *p = link + link_len;
4470 while (p > link && !IS_ANY_SEP (p[-1]))
4471 p--;
4472 strcpy (p, target);
4473 strcpy (target, link);
4475 /* Resolve any "." and ".." to get a fully-qualified file name
4476 in link[] again. */
4477 link_len = GetFullPathName (target, MAX_PATH, link, NULL);
4479 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
4481 if (loop_count > 100)
4482 errno = ELOOP;
4484 if (target[0] == '\0') /* not a single call to readlink succeeded */
4485 return (char *)file;
4486 return target;
4489 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
4490 have a fixed max size for file names, so we don't need the kind of
4491 alloc/malloc/realloc dance the gnulib version does. We also don't
4492 support FD-relative symlinks. */
4493 char *
4494 careadlinkat (int fd, char const *filename,
4495 char *buffer, size_t buffer_size,
4496 struct allocator const *alloc,
4497 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
4499 char linkname[MAX_PATH];
4500 ssize_t link_size;
4502 if (fd != AT_FDCWD)
4504 errno = EINVAL;
4505 return NULL;
4508 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
4510 if (link_size > 0)
4512 char *retval = buffer;
4514 linkname[link_size++] = '\0';
4515 if (link_size > buffer_size)
4516 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
4517 if (retval)
4518 memcpy (retval, linkname, link_size);
4520 return retval;
4522 return NULL;
4525 ssize_t
4526 careadlinkatcwd (int fd, char const *filename, char *buffer,
4527 size_t buffer_size)
4529 (void) fd;
4530 return readlink (filename, buffer, buffer_size);
4534 /* Support for browsing other processes and their attributes. See
4535 process.c for the Lisp bindings. */
4537 /* Helper wrapper functions. */
4539 static HANDLE WINAPI
4540 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
4542 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
4544 if (g_b_init_create_toolhelp32_snapshot == 0)
4546 g_b_init_create_toolhelp32_snapshot = 1;
4547 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
4548 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4549 "CreateToolhelp32Snapshot");
4551 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
4553 return INVALID_HANDLE_VALUE;
4555 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
4558 static BOOL WINAPI
4559 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
4561 static Process32First_Proc s_pfn_Process32_First = NULL;
4563 if (g_b_init_process32_first == 0)
4565 g_b_init_process32_first = 1;
4566 s_pfn_Process32_First = (Process32First_Proc)
4567 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4568 "Process32First");
4570 if (s_pfn_Process32_First == NULL)
4572 return FALSE;
4574 return (s_pfn_Process32_First (hSnapshot, lppe));
4577 static BOOL WINAPI
4578 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
4580 static Process32Next_Proc s_pfn_Process32_Next = NULL;
4582 if (g_b_init_process32_next == 0)
4584 g_b_init_process32_next = 1;
4585 s_pfn_Process32_Next = (Process32Next_Proc)
4586 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4587 "Process32Next");
4589 if (s_pfn_Process32_Next == NULL)
4591 return FALSE;
4593 return (s_pfn_Process32_Next (hSnapshot, lppe));
4596 static BOOL WINAPI
4597 open_thread_token (HANDLE ThreadHandle,
4598 DWORD DesiredAccess,
4599 BOOL OpenAsSelf,
4600 PHANDLE TokenHandle)
4602 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
4603 HMODULE hm_advapi32 = NULL;
4604 if (is_windows_9x () == TRUE)
4606 SetLastError (ERROR_NOT_SUPPORTED);
4607 return FALSE;
4609 if (g_b_init_open_thread_token == 0)
4611 g_b_init_open_thread_token = 1;
4612 hm_advapi32 = LoadLibrary ("Advapi32.dll");
4613 s_pfn_Open_Thread_Token =
4614 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
4616 if (s_pfn_Open_Thread_Token == NULL)
4618 SetLastError (ERROR_NOT_SUPPORTED);
4619 return FALSE;
4621 return (
4622 s_pfn_Open_Thread_Token (
4623 ThreadHandle,
4624 DesiredAccess,
4625 OpenAsSelf,
4626 TokenHandle)
4630 static BOOL WINAPI
4631 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
4633 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
4634 HMODULE hm_advapi32 = NULL;
4635 if (is_windows_9x () == TRUE)
4637 return FALSE;
4639 if (g_b_init_impersonate_self == 0)
4641 g_b_init_impersonate_self = 1;
4642 hm_advapi32 = LoadLibrary ("Advapi32.dll");
4643 s_pfn_Impersonate_Self =
4644 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
4646 if (s_pfn_Impersonate_Self == NULL)
4648 return FALSE;
4650 return s_pfn_Impersonate_Self (ImpersonationLevel);
4653 static BOOL WINAPI
4654 revert_to_self (void)
4656 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
4657 HMODULE hm_advapi32 = NULL;
4658 if (is_windows_9x () == TRUE)
4660 return FALSE;
4662 if (g_b_init_revert_to_self == 0)
4664 g_b_init_revert_to_self = 1;
4665 hm_advapi32 = LoadLibrary ("Advapi32.dll");
4666 s_pfn_Revert_To_Self =
4667 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
4669 if (s_pfn_Revert_To_Self == NULL)
4671 return FALSE;
4673 return s_pfn_Revert_To_Self ();
4676 static BOOL WINAPI
4677 get_process_memory_info (HANDLE h_proc,
4678 PPROCESS_MEMORY_COUNTERS mem_counters,
4679 DWORD bufsize)
4681 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
4682 HMODULE hm_psapi = NULL;
4683 if (is_windows_9x () == TRUE)
4685 return FALSE;
4687 if (g_b_init_get_process_memory_info == 0)
4689 g_b_init_get_process_memory_info = 1;
4690 hm_psapi = LoadLibrary ("Psapi.dll");
4691 if (hm_psapi)
4692 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
4693 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
4695 if (s_pfn_Get_Process_Memory_Info == NULL)
4697 return FALSE;
4699 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
4702 static BOOL WINAPI
4703 get_process_working_set_size (HANDLE h_proc,
4704 PSIZE_T minrss,
4705 PSIZE_T maxrss)
4707 static GetProcessWorkingSetSize_Proc
4708 s_pfn_Get_Process_Working_Set_Size = NULL;
4710 if (is_windows_9x () == TRUE)
4712 return FALSE;
4714 if (g_b_init_get_process_working_set_size == 0)
4716 g_b_init_get_process_working_set_size = 1;
4717 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
4718 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4719 "GetProcessWorkingSetSize");
4721 if (s_pfn_Get_Process_Working_Set_Size == NULL)
4723 return FALSE;
4725 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
4728 static BOOL WINAPI
4729 global_memory_status (MEMORYSTATUS *buf)
4731 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
4733 if (is_windows_9x () == TRUE)
4735 return FALSE;
4737 if (g_b_init_global_memory_status == 0)
4739 g_b_init_global_memory_status = 1;
4740 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
4741 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4742 "GlobalMemoryStatus");
4744 if (s_pfn_Global_Memory_Status == NULL)
4746 return FALSE;
4748 return s_pfn_Global_Memory_Status (buf);
4751 static BOOL WINAPI
4752 global_memory_status_ex (MEMORY_STATUS_EX *buf)
4754 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
4756 if (is_windows_9x () == TRUE)
4758 return FALSE;
4760 if (g_b_init_global_memory_status_ex == 0)
4762 g_b_init_global_memory_status_ex = 1;
4763 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
4764 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4765 "GlobalMemoryStatusEx");
4767 if (s_pfn_Global_Memory_Status_Ex == NULL)
4769 return FALSE;
4771 return s_pfn_Global_Memory_Status_Ex (buf);
4774 Lisp_Object
4775 list_system_processes (void)
4777 struct gcpro gcpro1;
4778 Lisp_Object proclist = Qnil;
4779 HANDLE h_snapshot;
4781 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4783 if (h_snapshot != INVALID_HANDLE_VALUE)
4785 PROCESSENTRY32 proc_entry;
4786 DWORD proc_id;
4787 BOOL res;
4789 GCPRO1 (proclist);
4791 proc_entry.dwSize = sizeof (PROCESSENTRY32);
4792 for (res = process32_first (h_snapshot, &proc_entry); res;
4793 res = process32_next (h_snapshot, &proc_entry))
4795 proc_id = proc_entry.th32ProcessID;
4796 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
4799 CloseHandle (h_snapshot);
4800 UNGCPRO;
4801 proclist = Fnreverse (proclist);
4804 return proclist;
4807 static int
4808 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
4810 TOKEN_PRIVILEGES priv;
4811 DWORD priv_size = sizeof (priv);
4812 DWORD opriv_size = sizeof (*old_priv);
4813 HANDLE h_token = NULL;
4814 HANDLE h_thread = GetCurrentThread ();
4815 int ret_val = 0;
4816 BOOL res;
4818 res = open_thread_token (h_thread,
4819 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4820 FALSE, &h_token);
4821 if (!res && GetLastError () == ERROR_NO_TOKEN)
4823 if (impersonate_self (SecurityImpersonation))
4824 res = open_thread_token (h_thread,
4825 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4826 FALSE, &h_token);
4828 if (res)
4830 priv.PrivilegeCount = 1;
4831 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
4832 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
4833 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
4834 old_priv, &opriv_size)
4835 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
4836 ret_val = 1;
4838 if (h_token)
4839 CloseHandle (h_token);
4841 return ret_val;
4844 static int
4845 restore_privilege (TOKEN_PRIVILEGES *priv)
4847 DWORD priv_size = sizeof (*priv);
4848 HANDLE h_token = NULL;
4849 int ret_val = 0;
4851 if (open_thread_token (GetCurrentThread (),
4852 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4853 FALSE, &h_token))
4855 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
4856 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
4857 ret_val = 1;
4859 if (h_token)
4860 CloseHandle (h_token);
4862 return ret_val;
4865 static Lisp_Object
4866 ltime (ULONGLONG time_100ns)
4868 ULONGLONG time_sec = time_100ns / 10000000;
4869 int subsec = time_100ns % 10000000;
4870 return list4 (make_number (time_sec >> 16),
4871 make_number (time_sec & 0xffff),
4872 make_number (subsec / 10),
4873 make_number (subsec % 10 * 100000));
4876 #define U64_TO_LISP_TIME(time) ltime (time)
4878 static int
4879 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
4880 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
4881 double *pcpu)
4883 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
4884 ULONGLONG tem1, tem2, tem3, tem;
4886 if (!h_proc
4887 || !get_process_times_fn
4888 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
4889 &ft_kernel, &ft_user))
4890 return 0;
4892 GetSystemTimeAsFileTime (&ft_current);
4894 FILETIME_TO_U64 (tem1, ft_kernel);
4895 *stime = U64_TO_LISP_TIME (tem1);
4897 FILETIME_TO_U64 (tem2, ft_user);
4898 *utime = U64_TO_LISP_TIME (tem2);
4900 tem3 = tem1 + tem2;
4901 *ttime = U64_TO_LISP_TIME (tem3);
4903 FILETIME_TO_U64 (tem, ft_creation);
4904 /* Process no 4 (System) returns zero creation time. */
4905 if (tem)
4906 tem -= utc_base;
4907 *ctime = U64_TO_LISP_TIME (tem);
4909 if (tem)
4911 FILETIME_TO_U64 (tem3, ft_current);
4912 tem = (tem3 - utc_base) - tem;
4914 *etime = U64_TO_LISP_TIME (tem);
4916 if (tem)
4918 *pcpu = 100.0 * (tem1 + tem2) / tem;
4919 if (*pcpu > 100)
4920 *pcpu = 100.0;
4922 else
4923 *pcpu = 0;
4925 return 1;
4928 Lisp_Object
4929 system_process_attributes (Lisp_Object pid)
4931 struct gcpro gcpro1, gcpro2, gcpro3;
4932 Lisp_Object attrs = Qnil;
4933 Lisp_Object cmd_str, decoded_cmd, tem;
4934 HANDLE h_snapshot, h_proc;
4935 DWORD proc_id;
4936 int found_proc = 0;
4937 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
4938 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
4939 DWORD glength = sizeof (gname);
4940 HANDLE token = NULL;
4941 SID_NAME_USE user_type;
4942 unsigned char *buf = NULL;
4943 DWORD blen = 0;
4944 TOKEN_USER user_token;
4945 TOKEN_PRIMARY_GROUP group_token;
4946 unsigned euid;
4947 unsigned egid;
4948 PROCESS_MEMORY_COUNTERS mem;
4949 PROCESS_MEMORY_COUNTERS_EX mem_ex;
4950 SIZE_T minrss, maxrss;
4951 MEMORYSTATUS memst;
4952 MEMORY_STATUS_EX memstex;
4953 double totphys = 0.0;
4954 Lisp_Object ctime, stime, utime, etime, ttime;
4955 double pcpu;
4956 BOOL result = FALSE;
4958 CHECK_NUMBER_OR_FLOAT (pid);
4959 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
4961 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4963 GCPRO3 (attrs, decoded_cmd, tem);
4965 if (h_snapshot != INVALID_HANDLE_VALUE)
4967 PROCESSENTRY32 pe;
4968 BOOL res;
4970 pe.dwSize = sizeof (PROCESSENTRY32);
4971 for (res = process32_first (h_snapshot, &pe); res;
4972 res = process32_next (h_snapshot, &pe))
4974 if (proc_id == pe.th32ProcessID)
4976 if (proc_id == 0)
4977 decoded_cmd = build_string ("Idle");
4978 else
4980 /* Decode the command name from locale-specific
4981 encoding. */
4982 cmd_str = make_unibyte_string (pe.szExeFile,
4983 strlen (pe.szExeFile));
4984 decoded_cmd =
4985 code_convert_string_norecord (cmd_str,
4986 Vlocale_coding_system, 0);
4988 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
4989 attrs = Fcons (Fcons (Qppid,
4990 make_fixnum_or_float (pe.th32ParentProcessID)),
4991 attrs);
4992 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
4993 attrs);
4994 attrs = Fcons (Fcons (Qthcount,
4995 make_fixnum_or_float (pe.cntThreads)),
4996 attrs);
4997 found_proc = 1;
4998 break;
5002 CloseHandle (h_snapshot);
5005 if (!found_proc)
5007 UNGCPRO;
5008 return Qnil;
5011 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
5012 FALSE, proc_id);
5013 /* If we were denied a handle to the process, try again after
5014 enabling the SeDebugPrivilege in our process. */
5015 if (!h_proc)
5017 TOKEN_PRIVILEGES priv_current;
5019 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
5021 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
5022 FALSE, proc_id);
5023 restore_privilege (&priv_current);
5024 revert_to_self ();
5027 if (h_proc)
5029 result = open_process_token (h_proc, TOKEN_QUERY, &token);
5030 if (result)
5032 result = get_token_information (token, TokenUser, NULL, 0, &blen);
5033 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
5035 buf = xmalloc (blen);
5036 result = get_token_information (token, TokenUser,
5037 (LPVOID)buf, blen, &needed);
5038 if (result)
5040 memcpy (&user_token, buf, sizeof (user_token));
5041 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
5043 euid = get_rid (user_token.User.Sid);
5044 result = lookup_account_sid (NULL, user_token.User.Sid,
5045 uname, &ulength,
5046 domain, &dlength,
5047 &user_type);
5048 if (result)
5049 w32_add_to_cache (user_token.User.Sid, euid, uname);
5050 else
5052 strcpy (uname, "unknown");
5053 result = TRUE;
5056 ulength = strlen (uname);
5060 if (result)
5062 /* Determine a reasonable euid and gid values. */
5063 if (xstrcasecmp ("administrator", uname) == 0)
5065 euid = 500; /* well-known Administrator uid */
5066 egid = 513; /* well-known None gid */
5068 else
5070 /* Get group id and name. */
5071 result = get_token_information (token, TokenPrimaryGroup,
5072 (LPVOID)buf, blen, &needed);
5073 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
5075 buf = xrealloc (buf, blen = needed);
5076 result = get_token_information (token, TokenPrimaryGroup,
5077 (LPVOID)buf, blen, &needed);
5079 if (result)
5081 memcpy (&group_token, buf, sizeof (group_token));
5082 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
5084 egid = get_rid (group_token.PrimaryGroup);
5085 dlength = sizeof (domain);
5086 result =
5087 lookup_account_sid (NULL, group_token.PrimaryGroup,
5088 gname, &glength, NULL, &dlength,
5089 &user_type);
5090 if (result)
5091 w32_add_to_cache (group_token.PrimaryGroup,
5092 egid, gname);
5093 else
5095 strcpy (gname, "None");
5096 result = TRUE;
5099 glength = strlen (gname);
5103 xfree (buf);
5105 if (!result)
5107 if (!is_windows_9x ())
5109 /* We couldn't open the process token, presumably because of
5110 insufficient access rights. Assume this process is run
5111 by the system. */
5112 strcpy (uname, "SYSTEM");
5113 strcpy (gname, "None");
5114 euid = 18; /* SYSTEM */
5115 egid = 513; /* None */
5116 glength = strlen (gname);
5117 ulength = strlen (uname);
5119 /* If we are running under Windows 9X, where security calls are
5120 not supported, we assume all processes are run by the current
5121 user. */
5122 else if (GetUserName (uname, &ulength))
5124 if (xstrcasecmp ("administrator", uname) == 0)
5125 euid = 0;
5126 else
5127 euid = 123;
5128 egid = euid;
5129 strcpy (gname, "None");
5130 glength = strlen (gname);
5131 ulength = strlen (uname);
5133 else
5135 euid = 123;
5136 egid = 123;
5137 strcpy (uname, "administrator");
5138 ulength = strlen (uname);
5139 strcpy (gname, "None");
5140 glength = strlen (gname);
5142 if (token)
5143 CloseHandle (token);
5146 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
5147 tem = make_unibyte_string (uname, ulength);
5148 attrs = Fcons (Fcons (Quser,
5149 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
5150 attrs);
5151 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
5152 tem = make_unibyte_string (gname, glength);
5153 attrs = Fcons (Fcons (Qgroup,
5154 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
5155 attrs);
5157 if (global_memory_status_ex (&memstex))
5158 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
5159 totphys = memstex.ullTotalPhys / 1024.0;
5160 #else
5161 /* Visual Studio 6 cannot convert an unsigned __int64 type to
5162 double, so we need to do this for it... */
5164 DWORD tot_hi = memstex.ullTotalPhys >> 32;
5165 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
5166 DWORD tot_lo = memstex.ullTotalPhys % 1024;
5168 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
5170 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5171 else if (global_memory_status (&memst))
5172 totphys = memst.dwTotalPhys / 1024.0;
5174 if (h_proc
5175 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
5176 sizeof (mem_ex)))
5178 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
5180 attrs = Fcons (Fcons (Qmajflt,
5181 make_fixnum_or_float (mem_ex.PageFaultCount)),
5182 attrs);
5183 attrs = Fcons (Fcons (Qvsize,
5184 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
5185 attrs);
5186 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
5187 if (totphys)
5188 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
5190 else if (h_proc
5191 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
5193 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
5195 attrs = Fcons (Fcons (Qmajflt,
5196 make_fixnum_or_float (mem.PageFaultCount)),
5197 attrs);
5198 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
5199 if (totphys)
5200 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
5202 else if (h_proc
5203 && get_process_working_set_size (h_proc, &minrss, &maxrss))
5205 DWORD rss = maxrss / 1024;
5207 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
5208 if (totphys)
5209 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
5212 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
5214 attrs = Fcons (Fcons (Qutime, utime), attrs);
5215 attrs = Fcons (Fcons (Qstime, stime), attrs);
5216 attrs = Fcons (Fcons (Qtime, ttime), attrs);
5217 attrs = Fcons (Fcons (Qstart, ctime), attrs);
5218 attrs = Fcons (Fcons (Qetime, etime), attrs);
5219 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
5222 /* FIXME: Retrieve command line by walking the PEB of the process. */
5224 if (h_proc)
5225 CloseHandle (h_proc);
5226 UNGCPRO;
5227 return attrs;
5231 /* Wrappers for winsock functions to map between our file descriptors
5232 and winsock's handles; also set h_errno for convenience.
5234 To allow Emacs to run on systems which don't have winsock support
5235 installed, we dynamically link to winsock on startup if present, and
5236 otherwise provide the minimum necessary functionality
5237 (eg. gethostname). */
5239 /* function pointers for relevant socket functions */
5240 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
5241 void (PASCAL *pfn_WSASetLastError) (int iError);
5242 int (PASCAL *pfn_WSAGetLastError) (void);
5243 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
5244 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
5245 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
5246 int (PASCAL *pfn_socket) (int af, int type, int protocol);
5247 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
5248 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
5249 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
5250 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
5251 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
5252 int (PASCAL *pfn_closesocket) (SOCKET s);
5253 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
5254 int (PASCAL *pfn_WSACleanup) (void);
5256 u_short (PASCAL *pfn_htons) (u_short hostshort);
5257 u_short (PASCAL *pfn_ntohs) (u_short netshort);
5258 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
5259 int (PASCAL *pfn_gethostname) (char * name, int namelen);
5260 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
5261 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
5262 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
5263 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
5264 const char * optval, int optlen);
5265 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
5266 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
5267 int * namelen);
5268 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
5269 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
5270 struct sockaddr * from, int * fromlen);
5271 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
5272 const struct sockaddr * to, int tolen);
5274 /* SetHandleInformation is only needed to make sockets non-inheritable. */
5275 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
5276 #ifndef HANDLE_FLAG_INHERIT
5277 #define HANDLE_FLAG_INHERIT 1
5278 #endif
5280 HANDLE winsock_lib;
5281 static int winsock_inuse;
5283 BOOL
5284 term_winsock (void)
5286 if (winsock_lib != NULL && winsock_inuse == 0)
5288 /* Not sure what would cause WSAENETDOWN, or even if it can happen
5289 after WSAStartup returns successfully, but it seems reasonable
5290 to allow unloading winsock anyway in that case. */
5291 if (pfn_WSACleanup () == 0 ||
5292 pfn_WSAGetLastError () == WSAENETDOWN)
5294 if (FreeLibrary (winsock_lib))
5295 winsock_lib = NULL;
5296 return TRUE;
5299 return FALSE;
5302 BOOL
5303 init_winsock (int load_now)
5305 WSADATA winsockData;
5307 if (winsock_lib != NULL)
5308 return TRUE;
5310 pfn_SetHandleInformation
5311 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
5312 "SetHandleInformation");
5314 winsock_lib = LoadLibrary ("Ws2_32.dll");
5316 if (winsock_lib != NULL)
5318 /* dynamically link to socket functions */
5320 #define LOAD_PROC(fn) \
5321 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
5322 goto fail;
5324 LOAD_PROC (WSAStartup);
5325 LOAD_PROC (WSASetLastError);
5326 LOAD_PROC (WSAGetLastError);
5327 LOAD_PROC (WSAEventSelect);
5328 LOAD_PROC (WSACreateEvent);
5329 LOAD_PROC (WSACloseEvent);
5330 LOAD_PROC (socket);
5331 LOAD_PROC (bind);
5332 LOAD_PROC (connect);
5333 LOAD_PROC (ioctlsocket);
5334 LOAD_PROC (recv);
5335 LOAD_PROC (send);
5336 LOAD_PROC (closesocket);
5337 LOAD_PROC (shutdown);
5338 LOAD_PROC (htons);
5339 LOAD_PROC (ntohs);
5340 LOAD_PROC (inet_addr);
5341 LOAD_PROC (gethostname);
5342 LOAD_PROC (gethostbyname);
5343 LOAD_PROC (getservbyname);
5344 LOAD_PROC (getpeername);
5345 LOAD_PROC (WSACleanup);
5346 LOAD_PROC (setsockopt);
5347 LOAD_PROC (listen);
5348 LOAD_PROC (getsockname);
5349 LOAD_PROC (accept);
5350 LOAD_PROC (recvfrom);
5351 LOAD_PROC (sendto);
5352 #undef LOAD_PROC
5354 /* specify version 1.1 of winsock */
5355 if (pfn_WSAStartup (0x101, &winsockData) == 0)
5357 if (winsockData.wVersion != 0x101)
5358 goto fail;
5360 if (!load_now)
5362 /* Report that winsock exists and is usable, but leave
5363 socket functions disabled. I am assuming that calling
5364 WSAStartup does not require any network interaction,
5365 and in particular does not cause or require a dial-up
5366 connection to be established. */
5368 pfn_WSACleanup ();
5369 FreeLibrary (winsock_lib);
5370 winsock_lib = NULL;
5372 winsock_inuse = 0;
5373 return TRUE;
5376 fail:
5377 FreeLibrary (winsock_lib);
5378 winsock_lib = NULL;
5381 return FALSE;
5385 int h_errno = 0;
5387 /* function to set h_errno for compatibility; map winsock error codes to
5388 normal system codes where they overlap (non-overlapping definitions
5389 are already in <sys/socket.h> */
5390 static void
5391 set_errno (void)
5393 if (winsock_lib == NULL)
5394 h_errno = EINVAL;
5395 else
5396 h_errno = pfn_WSAGetLastError ();
5398 switch (h_errno)
5400 case WSAEACCES: h_errno = EACCES; break;
5401 case WSAEBADF: h_errno = EBADF; break;
5402 case WSAEFAULT: h_errno = EFAULT; break;
5403 case WSAEINTR: h_errno = EINTR; break;
5404 case WSAEINVAL: h_errno = EINVAL; break;
5405 case WSAEMFILE: h_errno = EMFILE; break;
5406 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
5407 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
5409 errno = h_errno;
5412 static void
5413 check_errno (void)
5415 if (h_errno == 0 && winsock_lib != NULL)
5416 pfn_WSASetLastError (0);
5419 /* Extend strerror to handle the winsock-specific error codes. */
5420 struct {
5421 int errnum;
5422 char * msg;
5423 } _wsa_errlist[] = {
5424 {WSAEINTR , "Interrupted function call"},
5425 {WSAEBADF , "Bad file descriptor"},
5426 {WSAEACCES , "Permission denied"},
5427 {WSAEFAULT , "Bad address"},
5428 {WSAEINVAL , "Invalid argument"},
5429 {WSAEMFILE , "Too many open files"},
5431 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
5432 {WSAEINPROGRESS , "Operation now in progress"},
5433 {WSAEALREADY , "Operation already in progress"},
5434 {WSAENOTSOCK , "Socket operation on non-socket"},
5435 {WSAEDESTADDRREQ , "Destination address required"},
5436 {WSAEMSGSIZE , "Message too long"},
5437 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
5438 {WSAENOPROTOOPT , "Bad protocol option"},
5439 {WSAEPROTONOSUPPORT , "Protocol not supported"},
5440 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
5441 {WSAEOPNOTSUPP , "Operation not supported"},
5442 {WSAEPFNOSUPPORT , "Protocol family not supported"},
5443 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
5444 {WSAEADDRINUSE , "Address already in use"},
5445 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
5446 {WSAENETDOWN , "Network is down"},
5447 {WSAENETUNREACH , "Network is unreachable"},
5448 {WSAENETRESET , "Network dropped connection on reset"},
5449 {WSAECONNABORTED , "Software caused connection abort"},
5450 {WSAECONNRESET , "Connection reset by peer"},
5451 {WSAENOBUFS , "No buffer space available"},
5452 {WSAEISCONN , "Socket is already connected"},
5453 {WSAENOTCONN , "Socket is not connected"},
5454 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
5455 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
5456 {WSAETIMEDOUT , "Connection timed out"},
5457 {WSAECONNREFUSED , "Connection refused"},
5458 {WSAELOOP , "Network loop"}, /* not sure */
5459 {WSAENAMETOOLONG , "Name is too long"},
5460 {WSAEHOSTDOWN , "Host is down"},
5461 {WSAEHOSTUNREACH , "No route to host"},
5462 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
5463 {WSAEPROCLIM , "Too many processes"},
5464 {WSAEUSERS , "Too many users"}, /* not sure */
5465 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
5466 {WSAESTALE , "Data is stale"}, /* not sure */
5467 {WSAEREMOTE , "Remote error"}, /* not sure */
5469 {WSASYSNOTREADY , "Network subsystem is unavailable"},
5470 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
5471 {WSANOTINITIALISED , "Winsock not initialized successfully"},
5472 {WSAEDISCON , "Graceful shutdown in progress"},
5473 #ifdef WSAENOMORE
5474 {WSAENOMORE , "No more operations allowed"}, /* not sure */
5475 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
5476 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
5477 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
5478 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
5479 {WSASYSCALLFAILURE , "System call failure"},
5480 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
5481 {WSATYPE_NOT_FOUND , "Class type not found"},
5482 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
5483 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
5484 {WSAEREFUSED , "Operation refused"}, /* not sure */
5485 #endif
5487 {WSAHOST_NOT_FOUND , "Host not found"},
5488 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
5489 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
5490 {WSANO_DATA , "Valid name, no data record of requested type"},
5492 {-1, NULL}
5495 char *
5496 sys_strerror (int error_no)
5498 int i;
5499 static char unknown_msg[40];
5501 if (error_no >= 0 && error_no < sys_nerr)
5502 return sys_errlist[error_no];
5504 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
5505 if (_wsa_errlist[i].errnum == error_no)
5506 return _wsa_errlist[i].msg;
5508 sprintf (unknown_msg, "Unidentified error: %d", error_no);
5509 return unknown_msg;
5512 /* [andrewi 3-May-96] I've had conflicting results using both methods,
5513 but I believe the method of keeping the socket handle separate (and
5514 insuring it is not inheritable) is the correct one. */
5516 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
5518 static int socket_to_fd (SOCKET s);
5521 sys_socket (int af, int type, int protocol)
5523 SOCKET s;
5525 if (winsock_lib == NULL)
5527 h_errno = ENETDOWN;
5528 return INVALID_SOCKET;
5531 check_errno ();
5533 /* call the real socket function */
5534 s = pfn_socket (af, type, protocol);
5536 if (s != INVALID_SOCKET)
5537 return socket_to_fd (s);
5539 set_errno ();
5540 return -1;
5543 /* Convert a SOCKET to a file descriptor. */
5544 static int
5545 socket_to_fd (SOCKET s)
5547 int fd;
5548 child_process * cp;
5550 /* Although under NT 3.5 _open_osfhandle will accept a socket
5551 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
5552 that does not work under NT 3.1. However, we can get the same
5553 effect by using a backdoor function to replace an existing
5554 descriptor handle with the one we want. */
5556 /* allocate a file descriptor (with appropriate flags) */
5557 fd = _open ("NUL:", _O_RDWR);
5558 if (fd >= 0)
5560 /* Make a non-inheritable copy of the socket handle. Note
5561 that it is possible that sockets aren't actually kernel
5562 handles, which appears to be the case on Windows 9x when
5563 the MS Proxy winsock client is installed. */
5565 /* Apparently there is a bug in NT 3.51 with some service
5566 packs, which prevents using DuplicateHandle to make a
5567 socket handle non-inheritable (causes WSACleanup to
5568 hang). The work-around is to use SetHandleInformation
5569 instead if it is available and implemented. */
5570 if (pfn_SetHandleInformation)
5572 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
5574 else
5576 HANDLE parent = GetCurrentProcess ();
5577 HANDLE new_s = INVALID_HANDLE_VALUE;
5579 if (DuplicateHandle (parent,
5580 (HANDLE) s,
5581 parent,
5582 &new_s,
5584 FALSE,
5585 DUPLICATE_SAME_ACCESS))
5587 /* It is possible that DuplicateHandle succeeds even
5588 though the socket wasn't really a kernel handle,
5589 because a real handle has the same value. So
5590 test whether the new handle really is a socket. */
5591 long nonblocking = 0;
5592 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
5594 pfn_closesocket (s);
5595 s = (SOCKET) new_s;
5597 else
5599 CloseHandle (new_s);
5604 fd_info[fd].hnd = (HANDLE) s;
5606 /* set our own internal flags */
5607 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
5609 cp = new_child ();
5610 if (cp)
5612 cp->fd = fd;
5613 cp->status = STATUS_READ_ACKNOWLEDGED;
5615 /* attach child_process to fd_info */
5616 if (fd_info[ fd ].cp != NULL)
5618 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
5619 emacs_abort ();
5622 fd_info[ fd ].cp = cp;
5624 /* success! */
5625 winsock_inuse++; /* count open sockets */
5626 return fd;
5629 /* clean up */
5630 _close (fd);
5632 pfn_closesocket (s);
5633 h_errno = EMFILE;
5634 return -1;
5638 sys_bind (int s, const struct sockaddr * addr, int namelen)
5640 if (winsock_lib == NULL)
5642 h_errno = ENOTSOCK;
5643 return SOCKET_ERROR;
5646 check_errno ();
5647 if (fd_info[s].flags & FILE_SOCKET)
5649 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
5650 if (rc == SOCKET_ERROR)
5651 set_errno ();
5652 return rc;
5654 h_errno = ENOTSOCK;
5655 return SOCKET_ERROR;
5659 sys_connect (int s, const struct sockaddr * name, int namelen)
5661 if (winsock_lib == NULL)
5663 h_errno = ENOTSOCK;
5664 return SOCKET_ERROR;
5667 check_errno ();
5668 if (fd_info[s].flags & FILE_SOCKET)
5670 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
5671 if (rc == SOCKET_ERROR)
5672 set_errno ();
5673 return rc;
5675 h_errno = ENOTSOCK;
5676 return SOCKET_ERROR;
5679 u_short
5680 sys_htons (u_short hostshort)
5682 return (winsock_lib != NULL) ?
5683 pfn_htons (hostshort) : hostshort;
5686 u_short
5687 sys_ntohs (u_short netshort)
5689 return (winsock_lib != NULL) ?
5690 pfn_ntohs (netshort) : netshort;
5693 unsigned long
5694 sys_inet_addr (const char * cp)
5696 return (winsock_lib != NULL) ?
5697 pfn_inet_addr (cp) : INADDR_NONE;
5701 sys_gethostname (char * name, int namelen)
5703 if (winsock_lib != NULL)
5704 return pfn_gethostname (name, namelen);
5706 if (namelen > MAX_COMPUTERNAME_LENGTH)
5707 return !GetComputerName (name, (DWORD *)&namelen);
5709 h_errno = EFAULT;
5710 return SOCKET_ERROR;
5713 struct hostent *
5714 sys_gethostbyname (const char * name)
5716 struct hostent * host;
5718 if (winsock_lib == NULL)
5720 h_errno = ENETDOWN;
5721 return NULL;
5724 check_errno ();
5725 host = pfn_gethostbyname (name);
5726 if (!host)
5727 set_errno ();
5728 return host;
5731 struct servent *
5732 sys_getservbyname (const char * name, const char * proto)
5734 struct servent * serv;
5736 if (winsock_lib == NULL)
5738 h_errno = ENETDOWN;
5739 return NULL;
5742 check_errno ();
5743 serv = pfn_getservbyname (name, proto);
5744 if (!serv)
5745 set_errno ();
5746 return serv;
5750 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
5752 if (winsock_lib == NULL)
5754 h_errno = ENETDOWN;
5755 return SOCKET_ERROR;
5758 check_errno ();
5759 if (fd_info[s].flags & FILE_SOCKET)
5761 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
5762 if (rc == SOCKET_ERROR)
5763 set_errno ();
5764 return rc;
5766 h_errno = ENOTSOCK;
5767 return SOCKET_ERROR;
5771 sys_shutdown (int s, int how)
5773 if (winsock_lib == NULL)
5775 h_errno = ENETDOWN;
5776 return SOCKET_ERROR;
5779 check_errno ();
5780 if (fd_info[s].flags & FILE_SOCKET)
5782 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
5783 if (rc == SOCKET_ERROR)
5784 set_errno ();
5785 return rc;
5787 h_errno = ENOTSOCK;
5788 return SOCKET_ERROR;
5792 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
5794 if (winsock_lib == NULL)
5796 h_errno = ENETDOWN;
5797 return SOCKET_ERROR;
5800 check_errno ();
5801 if (fd_info[s].flags & FILE_SOCKET)
5803 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
5804 (const char *)optval, optlen);
5805 if (rc == SOCKET_ERROR)
5806 set_errno ();
5807 return rc;
5809 h_errno = ENOTSOCK;
5810 return SOCKET_ERROR;
5814 sys_listen (int s, int backlog)
5816 if (winsock_lib == NULL)
5818 h_errno = ENETDOWN;
5819 return SOCKET_ERROR;
5822 check_errno ();
5823 if (fd_info[s].flags & FILE_SOCKET)
5825 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
5826 if (rc == SOCKET_ERROR)
5827 set_errno ();
5828 else
5829 fd_info[s].flags |= FILE_LISTEN;
5830 return rc;
5832 h_errno = ENOTSOCK;
5833 return SOCKET_ERROR;
5837 sys_getsockname (int s, struct sockaddr * name, int * namelen)
5839 if (winsock_lib == NULL)
5841 h_errno = ENETDOWN;
5842 return SOCKET_ERROR;
5845 check_errno ();
5846 if (fd_info[s].flags & FILE_SOCKET)
5848 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
5849 if (rc == SOCKET_ERROR)
5850 set_errno ();
5851 return rc;
5853 h_errno = ENOTSOCK;
5854 return SOCKET_ERROR;
5858 sys_accept (int s, struct sockaddr * addr, int * addrlen)
5860 if (winsock_lib == NULL)
5862 h_errno = ENETDOWN;
5863 return -1;
5866 check_errno ();
5867 if (fd_info[s].flags & FILE_LISTEN)
5869 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
5870 int fd = -1;
5871 if (t == INVALID_SOCKET)
5872 set_errno ();
5873 else
5874 fd = socket_to_fd (t);
5876 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
5877 ResetEvent (fd_info[s].cp->char_avail);
5878 return fd;
5880 h_errno = ENOTSOCK;
5881 return -1;
5885 sys_recvfrom (int s, char * buf, int len, int flags,
5886 struct sockaddr * from, int * fromlen)
5888 if (winsock_lib == NULL)
5890 h_errno = ENETDOWN;
5891 return SOCKET_ERROR;
5894 check_errno ();
5895 if (fd_info[s].flags & FILE_SOCKET)
5897 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
5898 if (rc == SOCKET_ERROR)
5899 set_errno ();
5900 return rc;
5902 h_errno = ENOTSOCK;
5903 return SOCKET_ERROR;
5907 sys_sendto (int s, const char * buf, int len, int flags,
5908 const struct sockaddr * to, int tolen)
5910 if (winsock_lib == NULL)
5912 h_errno = ENETDOWN;
5913 return SOCKET_ERROR;
5916 check_errno ();
5917 if (fd_info[s].flags & FILE_SOCKET)
5919 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
5920 if (rc == SOCKET_ERROR)
5921 set_errno ();
5922 return rc;
5924 h_errno = ENOTSOCK;
5925 return SOCKET_ERROR;
5928 /* Windows does not have an fcntl function. Provide an implementation
5929 solely for making sockets non-blocking. */
5931 fcntl (int s, int cmd, int options)
5933 if (winsock_lib == NULL)
5935 h_errno = ENETDOWN;
5936 return -1;
5939 check_errno ();
5940 if (fd_info[s].flags & FILE_SOCKET)
5942 if (cmd == F_SETFL && options == O_NDELAY)
5944 unsigned long nblock = 1;
5945 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
5946 if (rc == SOCKET_ERROR)
5947 set_errno ();
5948 /* Keep track of the fact that we set this to non-blocking. */
5949 fd_info[s].flags |= FILE_NDELAY;
5950 return rc;
5952 else
5954 h_errno = EINVAL;
5955 return SOCKET_ERROR;
5958 h_errno = ENOTSOCK;
5959 return SOCKET_ERROR;
5963 /* Shadow main io functions: we need to handle pipes and sockets more
5964 intelligently, and implement non-blocking mode as well. */
5967 sys_close (int fd)
5969 int rc;
5971 if (fd < 0)
5973 errno = EBADF;
5974 return -1;
5977 if (fd < MAXDESC && fd_info[fd].cp)
5979 child_process * cp = fd_info[fd].cp;
5981 fd_info[fd].cp = NULL;
5983 if (CHILD_ACTIVE (cp))
5985 /* if last descriptor to active child_process then cleanup */
5986 int i;
5987 for (i = 0; i < MAXDESC; i++)
5989 if (i == fd)
5990 continue;
5991 if (fd_info[i].cp == cp)
5992 break;
5994 if (i == MAXDESC)
5996 if (fd_info[fd].flags & FILE_SOCKET)
5998 if (winsock_lib == NULL) emacs_abort ();
6000 pfn_shutdown (SOCK_HANDLE (fd), 2);
6001 rc = pfn_closesocket (SOCK_HANDLE (fd));
6003 winsock_inuse--; /* count open sockets */
6005 delete_child (cp);
6010 /* Note that sockets do not need special treatment here (at least on
6011 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
6012 closesocket is equivalent to CloseHandle, which is to be expected
6013 because socket handles are fully fledged kernel handles. */
6014 rc = _close (fd);
6016 if (rc == 0 && fd < MAXDESC)
6017 fd_info[fd].flags = 0;
6019 return rc;
6023 sys_dup (int fd)
6025 int new_fd;
6027 new_fd = _dup (fd);
6028 if (new_fd >= 0 && new_fd < MAXDESC)
6030 /* duplicate our internal info as well */
6031 fd_info[new_fd] = fd_info[fd];
6033 return new_fd;
6037 sys_dup2 (int src, int dst)
6039 int rc;
6041 if (dst < 0 || dst >= MAXDESC)
6043 errno = EBADF;
6044 return -1;
6047 /* make sure we close the destination first if it's a pipe or socket */
6048 if (src != dst && fd_info[dst].flags != 0)
6049 sys_close (dst);
6051 rc = _dup2 (src, dst);
6052 if (rc == 0)
6054 /* duplicate our internal info as well */
6055 fd_info[dst] = fd_info[src];
6057 return rc;
6060 /* Unix pipe() has only one arg */
6062 sys_pipe (int * phandles)
6064 int rc;
6065 unsigned flags;
6067 /* make pipe handles non-inheritable; when we spawn a child, we
6068 replace the relevant handle with an inheritable one. Also put
6069 pipes into binary mode; we will do text mode translation ourselves
6070 if required. */
6071 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
6073 if (rc == 0)
6075 /* Protect against overflow, since Windows can open more handles than
6076 our fd_info array has room for. */
6077 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
6079 _close (phandles[0]);
6080 _close (phandles[1]);
6081 rc = -1;
6083 else
6085 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
6086 fd_info[phandles[0]].flags = flags;
6088 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
6089 fd_info[phandles[1]].flags = flags;
6093 return rc;
6096 /* Function to do blocking read of one byte, needed to implement
6097 select. It is only allowed on sockets and pipes. */
6099 _sys_read_ahead (int fd)
6101 child_process * cp;
6102 int rc;
6104 if (fd < 0 || fd >= MAXDESC)
6105 return STATUS_READ_ERROR;
6107 cp = fd_info[fd].cp;
6109 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
6110 return STATUS_READ_ERROR;
6112 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
6113 || (fd_info[fd].flags & FILE_READ) == 0)
6115 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
6116 emacs_abort ();
6119 cp->status = STATUS_READ_IN_PROGRESS;
6121 if (fd_info[fd].flags & FILE_PIPE)
6123 rc = _read (fd, &cp->chr, sizeof (char));
6125 /* Give subprocess time to buffer some more output for us before
6126 reporting that input is available; we need this because Windows 95
6127 connects DOS programs to pipes by making the pipe appear to be
6128 the normal console stdout - as a result most DOS programs will
6129 write to stdout without buffering, ie. one character at a
6130 time. Even some W32 programs do this - "dir" in a command
6131 shell on NT is very slow if we don't do this. */
6132 if (rc > 0)
6134 int wait = w32_pipe_read_delay;
6136 if (wait > 0)
6137 Sleep (wait);
6138 else if (wait < 0)
6139 while (++wait <= 0)
6140 /* Yield remainder of our time slice, effectively giving a
6141 temporary priority boost to the child process. */
6142 Sleep (0);
6145 else if (fd_info[fd].flags & FILE_SERIAL)
6147 HANDLE hnd = fd_info[fd].hnd;
6148 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
6149 COMMTIMEOUTS ct;
6151 /* Configure timeouts for blocking read. */
6152 if (!GetCommTimeouts (hnd, &ct))
6153 return STATUS_READ_ERROR;
6154 ct.ReadIntervalTimeout = 0;
6155 ct.ReadTotalTimeoutMultiplier = 0;
6156 ct.ReadTotalTimeoutConstant = 0;
6157 if (!SetCommTimeouts (hnd, &ct))
6158 return STATUS_READ_ERROR;
6160 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
6162 if (GetLastError () != ERROR_IO_PENDING)
6163 return STATUS_READ_ERROR;
6164 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
6165 return STATUS_READ_ERROR;
6168 else if (fd_info[fd].flags & FILE_SOCKET)
6170 unsigned long nblock = 0;
6171 /* We always want this to block, so temporarily disable NDELAY. */
6172 if (fd_info[fd].flags & FILE_NDELAY)
6173 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6175 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
6177 if (fd_info[fd].flags & FILE_NDELAY)
6179 nblock = 1;
6180 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6184 if (rc == sizeof (char))
6185 cp->status = STATUS_READ_SUCCEEDED;
6186 else
6187 cp->status = STATUS_READ_FAILED;
6189 return cp->status;
6193 _sys_wait_accept (int fd)
6195 HANDLE hEv;
6196 child_process * cp;
6197 int rc;
6199 if (fd < 0 || fd >= MAXDESC)
6200 return STATUS_READ_ERROR;
6202 cp = fd_info[fd].cp;
6204 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
6205 return STATUS_READ_ERROR;
6207 cp->status = STATUS_READ_FAILED;
6209 hEv = pfn_WSACreateEvent ();
6210 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
6211 if (rc != SOCKET_ERROR)
6213 rc = WaitForSingleObject (hEv, INFINITE);
6214 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
6215 if (rc == WAIT_OBJECT_0)
6216 cp->status = STATUS_READ_SUCCEEDED;
6218 pfn_WSACloseEvent (hEv);
6220 return cp->status;
6224 sys_read (int fd, char * buffer, unsigned int count)
6226 int nchars;
6227 int to_read;
6228 DWORD waiting;
6229 char * orig_buffer = buffer;
6231 if (fd < 0)
6233 errno = EBADF;
6234 return -1;
6237 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
6239 child_process *cp = fd_info[fd].cp;
6241 if ((fd_info[fd].flags & FILE_READ) == 0)
6243 errno = EBADF;
6244 return -1;
6247 nchars = 0;
6249 /* re-read CR carried over from last read */
6250 if (fd_info[fd].flags & FILE_LAST_CR)
6252 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
6253 *buffer++ = 0x0d;
6254 count--;
6255 nchars++;
6256 fd_info[fd].flags &= ~FILE_LAST_CR;
6259 /* presence of a child_process structure means we are operating in
6260 non-blocking mode - otherwise we just call _read directly.
6261 Note that the child_process structure might be missing because
6262 reap_subprocess has been called; in this case the pipe is
6263 already broken, so calling _read on it is okay. */
6264 if (cp)
6266 int current_status = cp->status;
6268 switch (current_status)
6270 case STATUS_READ_FAILED:
6271 case STATUS_READ_ERROR:
6272 /* report normal EOF if nothing in buffer */
6273 if (nchars <= 0)
6274 fd_info[fd].flags |= FILE_AT_EOF;
6275 return nchars;
6277 case STATUS_READ_READY:
6278 case STATUS_READ_IN_PROGRESS:
6279 DebPrint (("sys_read called when read is in progress\n"));
6280 errno = EWOULDBLOCK;
6281 return -1;
6283 case STATUS_READ_SUCCEEDED:
6284 /* consume read-ahead char */
6285 *buffer++ = cp->chr;
6286 count--;
6287 nchars++;
6288 cp->status = STATUS_READ_ACKNOWLEDGED;
6289 ResetEvent (cp->char_avail);
6291 case STATUS_READ_ACKNOWLEDGED:
6292 break;
6294 default:
6295 DebPrint (("sys_read: bad status %d\n", current_status));
6296 errno = EBADF;
6297 return -1;
6300 if (fd_info[fd].flags & FILE_PIPE)
6302 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
6303 to_read = min (waiting, (DWORD) count);
6305 if (to_read > 0)
6306 nchars += _read (fd, buffer, to_read);
6308 else if (fd_info[fd].flags & FILE_SERIAL)
6310 HANDLE hnd = fd_info[fd].hnd;
6311 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
6312 int rc = 0;
6313 COMMTIMEOUTS ct;
6315 if (count > 0)
6317 /* Configure timeouts for non-blocking read. */
6318 if (!GetCommTimeouts (hnd, &ct))
6320 errno = EIO;
6321 return -1;
6323 ct.ReadIntervalTimeout = MAXDWORD;
6324 ct.ReadTotalTimeoutMultiplier = 0;
6325 ct.ReadTotalTimeoutConstant = 0;
6326 if (!SetCommTimeouts (hnd, &ct))
6328 errno = EIO;
6329 return -1;
6332 if (!ResetEvent (ovl->hEvent))
6334 errno = EIO;
6335 return -1;
6337 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
6339 if (GetLastError () != ERROR_IO_PENDING)
6341 errno = EIO;
6342 return -1;
6344 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
6346 errno = EIO;
6347 return -1;
6350 nchars += rc;
6353 else /* FILE_SOCKET */
6355 if (winsock_lib == NULL) emacs_abort ();
6357 /* do the equivalent of a non-blocking read */
6358 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
6359 if (waiting == 0 && nchars == 0)
6361 h_errno = errno = EWOULDBLOCK;
6362 return -1;
6365 if (waiting)
6367 /* always use binary mode for sockets */
6368 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
6369 if (res == SOCKET_ERROR)
6371 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
6372 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
6373 set_errno ();
6374 return -1;
6376 nchars += res;
6380 else
6382 int nread = _read (fd, buffer, count);
6383 if (nread >= 0)
6384 nchars += nread;
6385 else if (nchars == 0)
6386 nchars = nread;
6389 if (nchars <= 0)
6390 fd_info[fd].flags |= FILE_AT_EOF;
6391 /* Perform text mode translation if required. */
6392 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
6394 nchars = crlf_to_lf (nchars, orig_buffer);
6395 /* If buffer contains only CR, return that. To be absolutely
6396 sure we should attempt to read the next char, but in
6397 practice a CR to be followed by LF would not appear by
6398 itself in the buffer. */
6399 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
6401 fd_info[fd].flags |= FILE_LAST_CR;
6402 nchars--;
6406 else
6407 nchars = _read (fd, buffer, count);
6409 return nchars;
6412 /* From w32xfns.c */
6413 extern HANDLE interrupt_handle;
6415 /* For now, don't bother with a non-blocking mode */
6417 sys_write (int fd, const void * buffer, unsigned int count)
6419 int nchars;
6421 if (fd < 0)
6423 errno = EBADF;
6424 return -1;
6427 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
6429 if ((fd_info[fd].flags & FILE_WRITE) == 0)
6431 errno = EBADF;
6432 return -1;
6435 /* Perform text mode translation if required. */
6436 if ((fd_info[fd].flags & FILE_BINARY) == 0)
6438 char * tmpbuf = alloca (count * 2);
6439 unsigned char * src = (void *)buffer;
6440 unsigned char * dst = tmpbuf;
6441 int nbytes = count;
6443 while (1)
6445 unsigned char *next;
6446 /* copy next line or remaining bytes */
6447 next = _memccpy (dst, src, '\n', nbytes);
6448 if (next)
6450 /* copied one line ending with '\n' */
6451 int copied = next - dst;
6452 nbytes -= copied;
6453 src += copied;
6454 /* insert '\r' before '\n' */
6455 next[-1] = '\r';
6456 next[0] = '\n';
6457 dst = next + 1;
6458 count++;
6460 else
6461 /* copied remaining partial line -> now finished */
6462 break;
6464 buffer = tmpbuf;
6468 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
6470 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
6471 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
6472 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
6473 DWORD active = 0;
6475 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
6477 if (GetLastError () != ERROR_IO_PENDING)
6479 errno = EIO;
6480 return -1;
6482 if (detect_input_pending ())
6483 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
6484 QS_ALLINPUT);
6485 else
6486 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
6487 if (active == WAIT_OBJECT_0)
6488 { /* User pressed C-g, cancel write, then leave. Don't bother
6489 cleaning up as we may only get stuck in buggy drivers. */
6490 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
6491 CancelIo (hnd);
6492 errno = EIO;
6493 return -1;
6495 if (active == WAIT_OBJECT_0 + 1
6496 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
6498 errno = EIO;
6499 return -1;
6503 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
6505 unsigned long nblock = 0;
6506 if (winsock_lib == NULL) emacs_abort ();
6508 /* TODO: implement select() properly so non-blocking I/O works. */
6509 /* For now, make sure the write blocks. */
6510 if (fd_info[fd].flags & FILE_NDELAY)
6511 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6513 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
6515 /* Set the socket back to non-blocking if it was before,
6516 for other operations that support it. */
6517 if (fd_info[fd].flags & FILE_NDELAY)
6519 nblock = 1;
6520 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6523 if (nchars == SOCKET_ERROR)
6525 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
6526 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
6527 set_errno ();
6530 else
6532 /* Some networked filesystems don't like too large writes, so
6533 break them into smaller chunks. See the Comments section of
6534 the MSDN documentation of WriteFile for details behind the
6535 choice of the value of CHUNK below. See also the thread
6536 http://thread.gmane.org/gmane.comp.version-control.git/145294
6537 in the git mailing list. */
6538 const unsigned char *p = buffer;
6539 const unsigned chunk = 30 * 1024 * 1024;
6541 nchars = 0;
6542 while (count > 0)
6544 unsigned this_chunk = count < chunk ? count : chunk;
6545 int n = _write (fd, p, this_chunk);
6547 nchars += n;
6548 if (n < 0)
6550 nchars = n;
6551 break;
6553 else if (n < this_chunk)
6554 break;
6555 count -= n;
6556 p += n;
6560 return nchars;
6563 /* The Windows CRT functions are "optimized for speed", so they don't
6564 check for timezone and DST changes if they were last called less
6565 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
6566 all Emacs features that repeatedly call time functions (e.g.,
6567 display-time) are in real danger of missing timezone and DST
6568 changes. Calling tzset before each localtime call fixes that. */
6569 struct tm *
6570 sys_localtime (const time_t *t)
6572 tzset ();
6573 return localtime (t);
6578 /* Try loading LIBRARY_ID from the file(s) specified in
6579 Vdynamic_library_alist. If the library is loaded successfully,
6580 return the handle of the DLL, and record the filename in the
6581 property :loaded-from of LIBRARY_ID. If the library could not be
6582 found, or when it was already loaded (because the handle is not
6583 recorded anywhere, and so is lost after use), return NULL.
6585 We could also save the handle in :loaded-from, but currently
6586 there's no use case for it. */
6587 HMODULE
6588 w32_delayed_load (Lisp_Object library_id)
6590 HMODULE library_dll = NULL;
6592 CHECK_SYMBOL (library_id);
6594 if (CONSP (Vdynamic_library_alist)
6595 && NILP (Fassq (library_id, Vlibrary_cache)))
6597 Lisp_Object found = Qnil;
6598 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
6600 if (CONSP (dlls))
6601 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
6603 CHECK_STRING_CAR (dlls);
6604 if ((library_dll = LoadLibrary (SDATA (XCAR (dlls)))))
6606 char name[MAX_PATH];
6607 DWORD len;
6609 len = GetModuleFileNameA (library_dll, name, sizeof (name));
6610 found = Fcons (XCAR (dlls),
6611 (len > 0)
6612 /* Possibly truncated */
6613 ? make_specified_string (name, -1, len, 1)
6614 : Qnil);
6615 break;
6619 Fput (library_id, QCloaded_from, found);
6622 return library_dll;
6626 void
6627 check_windows_init_file (void)
6629 /* A common indication that Emacs is not installed properly is when
6630 it cannot find the Windows installation file. If this file does
6631 not exist in the expected place, tell the user. */
6633 if (!noninteractive && !inhibit_window_system
6634 /* Vload_path is not yet initialized when we are loading
6635 loadup.el. */
6636 && NILP (Vpurify_flag))
6638 Lisp_Object init_file;
6639 int fd;
6641 init_file = build_string ("term/w32-win");
6642 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
6643 if (fd < 0)
6645 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
6646 char *init_file_name = SDATA (init_file);
6647 char *load_path = SDATA (load_path_print);
6648 char *buffer = alloca (1024
6649 + strlen (init_file_name)
6650 + strlen (load_path));
6652 sprintf (buffer,
6653 "The Emacs Windows initialization file \"%s.el\" "
6654 "could not be found in your Emacs installation. "
6655 "Emacs checked the following directories for this file:\n"
6656 "\n%s\n\n"
6657 "When Emacs cannot find this file, it usually means that it "
6658 "was not installed properly, or its distribution file was "
6659 "not unpacked properly.\nSee the README.W32 file in the "
6660 "top-level Emacs directory for more information.",
6661 init_file_name, load_path);
6662 MessageBox (NULL,
6663 buffer,
6664 "Emacs Abort Dialog",
6665 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
6666 /* Use the low-level system abort. */
6667 abort ();
6669 else
6671 _close (fd);
6676 void
6677 term_ntproc (int ignored)
6679 (void)ignored;
6681 term_timers ();
6683 /* shutdown the socket interface if necessary */
6684 term_winsock ();
6686 term_w32select ();
6689 void
6690 init_ntproc (int dumping)
6692 sigset_t initial_mask = 0;
6694 /* Initialize the socket interface now if available and requested by
6695 the user by defining PRELOAD_WINSOCK; otherwise loading will be
6696 delayed until open-network-stream is called (w32-has-winsock can
6697 also be used to dynamically load or reload winsock).
6699 Conveniently, init_environment is called before us, so
6700 PRELOAD_WINSOCK can be set in the registry. */
6702 /* Always initialize this correctly. */
6703 winsock_lib = NULL;
6705 if (getenv ("PRELOAD_WINSOCK") != NULL)
6706 init_winsock (TRUE);
6708 /* Initial preparation for subprocess support: replace our standard
6709 handles with non-inheritable versions. */
6711 HANDLE parent;
6712 HANDLE stdin_save = INVALID_HANDLE_VALUE;
6713 HANDLE stdout_save = INVALID_HANDLE_VALUE;
6714 HANDLE stderr_save = INVALID_HANDLE_VALUE;
6716 parent = GetCurrentProcess ();
6718 /* ignore errors when duplicating and closing; typically the
6719 handles will be invalid when running as a gui program. */
6720 DuplicateHandle (parent,
6721 GetStdHandle (STD_INPUT_HANDLE),
6722 parent,
6723 &stdin_save,
6725 FALSE,
6726 DUPLICATE_SAME_ACCESS);
6728 DuplicateHandle (parent,
6729 GetStdHandle (STD_OUTPUT_HANDLE),
6730 parent,
6731 &stdout_save,
6733 FALSE,
6734 DUPLICATE_SAME_ACCESS);
6736 DuplicateHandle (parent,
6737 GetStdHandle (STD_ERROR_HANDLE),
6738 parent,
6739 &stderr_save,
6741 FALSE,
6742 DUPLICATE_SAME_ACCESS);
6744 fclose (stdin);
6745 fclose (stdout);
6746 fclose (stderr);
6748 if (stdin_save != INVALID_HANDLE_VALUE)
6749 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
6750 else
6751 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
6752 _fdopen (0, "r");
6754 if (stdout_save != INVALID_HANDLE_VALUE)
6755 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
6756 else
6757 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
6758 _fdopen (1, "w");
6760 if (stderr_save != INVALID_HANDLE_VALUE)
6761 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
6762 else
6763 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
6764 _fdopen (2, "w");
6767 /* unfortunately, atexit depends on implementation of malloc */
6768 /* atexit (term_ntproc); */
6769 if (!dumping)
6771 /* Make sure we start with all signals unblocked. */
6772 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
6773 signal (SIGABRT, term_ntproc);
6775 init_timers ();
6777 /* determine which drives are fixed, for GetCachedVolumeInformation */
6779 /* GetDriveType must have trailing backslash. */
6780 char drive[] = "A:\\";
6782 /* Loop over all possible drive letters */
6783 while (*drive <= 'Z')
6785 /* Record if this drive letter refers to a fixed drive. */
6786 fixed_drives[DRIVE_INDEX (*drive)] =
6787 (GetDriveType (drive) == DRIVE_FIXED);
6789 (*drive)++;
6792 /* Reset the volume info cache. */
6793 volume_cache = NULL;
6798 shutdown_handler ensures that buffers' autosave files are
6799 up to date when the user logs off, or the system shuts down.
6801 static BOOL WINAPI
6802 shutdown_handler (DWORD type)
6804 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
6805 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
6806 || type == CTRL_LOGOFF_EVENT /* User logs off. */
6807 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
6809 /* Shut down cleanly, making sure autosave files are up to date. */
6810 shut_down_emacs (0, Qnil);
6813 /* Allow other handlers to handle this signal. */
6814 return FALSE;
6818 globals_of_w32 is used to initialize those global variables that
6819 must always be initialized on startup even when the global variable
6820 initialized is non zero (see the function main in emacs.c).
6822 void
6823 globals_of_w32 (void)
6825 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
6827 get_process_times_fn = (GetProcessTimes_Proc)
6828 GetProcAddress (kernel32, "GetProcessTimes");
6830 DEFSYM (QCloaded_from, ":loaded-from");
6832 g_b_init_is_windows_9x = 0;
6833 g_b_init_open_process_token = 0;
6834 g_b_init_get_token_information = 0;
6835 g_b_init_lookup_account_sid = 0;
6836 g_b_init_get_sid_sub_authority = 0;
6837 g_b_init_get_sid_sub_authority_count = 0;
6838 g_b_init_get_security_info = 0;
6839 g_b_init_get_file_security = 0;
6840 g_b_init_get_security_descriptor_owner = 0;
6841 g_b_init_get_security_descriptor_group = 0;
6842 g_b_init_is_valid_sid = 0;
6843 g_b_init_create_toolhelp32_snapshot = 0;
6844 g_b_init_process32_first = 0;
6845 g_b_init_process32_next = 0;
6846 g_b_init_open_thread_token = 0;
6847 g_b_init_impersonate_self = 0;
6848 g_b_init_revert_to_self = 0;
6849 g_b_init_get_process_memory_info = 0;
6850 g_b_init_get_process_working_set_size = 0;
6851 g_b_init_global_memory_status = 0;
6852 g_b_init_global_memory_status_ex = 0;
6853 g_b_init_equal_sid = 0;
6854 g_b_init_copy_sid = 0;
6855 g_b_init_get_length_sid = 0;
6856 g_b_init_get_native_system_info = 0;
6857 g_b_init_get_system_times = 0;
6858 g_b_init_create_symbolic_link = 0;
6859 num_of_processors = 0;
6860 /* The following sets a handler for shutdown notifications for
6861 console apps. This actually applies to Emacs in both console and
6862 GUI modes, since we had to fool windows into thinking emacs is a
6863 console application to get console mode to work. */
6864 SetConsoleCtrlHandler (shutdown_handler, TRUE);
6866 /* "None" is the default group name on standalone workstations. */
6867 strcpy (dflt_group_name, "None");
6870 /* For make-serial-process */
6872 serial_open (char *port)
6874 HANDLE hnd;
6875 child_process *cp;
6876 int fd = -1;
6878 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
6879 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
6880 if (hnd == INVALID_HANDLE_VALUE)
6881 error ("Could not open %s", port);
6882 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
6883 if (fd == -1)
6884 error ("Could not open %s", port);
6886 cp = new_child ();
6887 if (!cp)
6888 error ("Could not create child process");
6889 cp->fd = fd;
6890 cp->status = STATUS_READ_ACKNOWLEDGED;
6891 fd_info[ fd ].hnd = hnd;
6892 fd_info[ fd ].flags |=
6893 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
6894 if (fd_info[ fd ].cp != NULL)
6896 error ("fd_info[fd = %d] is already in use", fd);
6898 fd_info[ fd ].cp = cp;
6899 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
6900 if (cp->ovl_read.hEvent == NULL)
6901 error ("Could not create read event");
6902 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
6903 if (cp->ovl_write.hEvent == NULL)
6904 error ("Could not create write event");
6906 return fd;
6909 /* For serial-process-configure */
6910 void
6911 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
6913 Lisp_Object childp2 = Qnil;
6914 Lisp_Object tem = Qnil;
6915 HANDLE hnd;
6916 DCB dcb;
6917 COMMTIMEOUTS ct;
6918 char summary[4] = "???"; /* This usually becomes "8N1". */
6920 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
6921 error ("Not a serial process");
6922 hnd = fd_info[ p->outfd ].hnd;
6924 childp2 = Fcopy_sequence (p->childp);
6926 /* Initialize timeouts for blocking read and blocking write. */
6927 if (!GetCommTimeouts (hnd, &ct))
6928 error ("GetCommTimeouts() failed");
6929 ct.ReadIntervalTimeout = 0;
6930 ct.ReadTotalTimeoutMultiplier = 0;
6931 ct.ReadTotalTimeoutConstant = 0;
6932 ct.WriteTotalTimeoutMultiplier = 0;
6933 ct.WriteTotalTimeoutConstant = 0;
6934 if (!SetCommTimeouts (hnd, &ct))
6935 error ("SetCommTimeouts() failed");
6936 /* Read port attributes and prepare default configuration. */
6937 memset (&dcb, 0, sizeof (dcb));
6938 dcb.DCBlength = sizeof (DCB);
6939 if (!GetCommState (hnd, &dcb))
6940 error ("GetCommState() failed");
6941 dcb.fBinary = TRUE;
6942 dcb.fNull = FALSE;
6943 dcb.fAbortOnError = FALSE;
6944 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6945 dcb.ErrorChar = 0;
6946 dcb.EofChar = 0;
6947 dcb.EvtChar = 0;
6949 /* Configure speed. */
6950 if (!NILP (Fplist_member (contact, QCspeed)))
6951 tem = Fplist_get (contact, QCspeed);
6952 else
6953 tem = Fplist_get (p->childp, QCspeed);
6954 CHECK_NUMBER (tem);
6955 dcb.BaudRate = XINT (tem);
6956 childp2 = Fplist_put (childp2, QCspeed, tem);
6958 /* Configure bytesize. */
6959 if (!NILP (Fplist_member (contact, QCbytesize)))
6960 tem = Fplist_get (contact, QCbytesize);
6961 else
6962 tem = Fplist_get (p->childp, QCbytesize);
6963 if (NILP (tem))
6964 tem = make_number (8);
6965 CHECK_NUMBER (tem);
6966 if (XINT (tem) != 7 && XINT (tem) != 8)
6967 error (":bytesize must be nil (8), 7, or 8");
6968 dcb.ByteSize = XINT (tem);
6969 summary[0] = XINT (tem) + '0';
6970 childp2 = Fplist_put (childp2, QCbytesize, tem);
6972 /* Configure parity. */
6973 if (!NILP (Fplist_member (contact, QCparity)))
6974 tem = Fplist_get (contact, QCparity);
6975 else
6976 tem = Fplist_get (p->childp, QCparity);
6977 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
6978 error (":parity must be nil (no parity), `even', or `odd'");
6979 dcb.fParity = FALSE;
6980 dcb.Parity = NOPARITY;
6981 dcb.fErrorChar = FALSE;
6982 if (NILP (tem))
6984 summary[1] = 'N';
6986 else if (EQ (tem, Qeven))
6988 summary[1] = 'E';
6989 dcb.fParity = TRUE;
6990 dcb.Parity = EVENPARITY;
6991 dcb.fErrorChar = TRUE;
6993 else if (EQ (tem, Qodd))
6995 summary[1] = 'O';
6996 dcb.fParity = TRUE;
6997 dcb.Parity = ODDPARITY;
6998 dcb.fErrorChar = TRUE;
7000 childp2 = Fplist_put (childp2, QCparity, tem);
7002 /* Configure stopbits. */
7003 if (!NILP (Fplist_member (contact, QCstopbits)))
7004 tem = Fplist_get (contact, QCstopbits);
7005 else
7006 tem = Fplist_get (p->childp, QCstopbits);
7007 if (NILP (tem))
7008 tem = make_number (1);
7009 CHECK_NUMBER (tem);
7010 if (XINT (tem) != 1 && XINT (tem) != 2)
7011 error (":stopbits must be nil (1 stopbit), 1, or 2");
7012 summary[2] = XINT (tem) + '0';
7013 if (XINT (tem) == 1)
7014 dcb.StopBits = ONESTOPBIT;
7015 else if (XINT (tem) == 2)
7016 dcb.StopBits = TWOSTOPBITS;
7017 childp2 = Fplist_put (childp2, QCstopbits, tem);
7019 /* Configure flowcontrol. */
7020 if (!NILP (Fplist_member (contact, QCflowcontrol)))
7021 tem = Fplist_get (contact, QCflowcontrol);
7022 else
7023 tem = Fplist_get (p->childp, QCflowcontrol);
7024 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
7025 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
7026 dcb.fOutxCtsFlow = FALSE;
7027 dcb.fOutxDsrFlow = FALSE;
7028 dcb.fDtrControl = DTR_CONTROL_DISABLE;
7029 dcb.fDsrSensitivity = FALSE;
7030 dcb.fTXContinueOnXoff = FALSE;
7031 dcb.fOutX = FALSE;
7032 dcb.fInX = FALSE;
7033 dcb.fRtsControl = RTS_CONTROL_DISABLE;
7034 dcb.XonChar = 17; /* Control-Q */
7035 dcb.XoffChar = 19; /* Control-S */
7036 if (NILP (tem))
7038 /* Already configured. */
7040 else if (EQ (tem, Qhw))
7042 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
7043 dcb.fOutxCtsFlow = TRUE;
7045 else if (EQ (tem, Qsw))
7047 dcb.fOutX = TRUE;
7048 dcb.fInX = TRUE;
7050 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
7052 /* Activate configuration. */
7053 if (!SetCommState (hnd, &dcb))
7054 error ("SetCommState() failed");
7056 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
7057 pset_childp (p, childp2);
7060 #ifdef HAVE_GNUTLS
7062 ssize_t
7063 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
7065 int n, sc, err;
7066 SELECT_TYPE fdset;
7067 EMACS_TIME timeout;
7068 struct Lisp_Process *process = (struct Lisp_Process *)p;
7069 int fd = process->infd;
7071 for (;;)
7073 n = sys_read (fd, (char*)buf, sz);
7075 if (n >= 0)
7076 return n;
7078 err = errno;
7080 if (err == EWOULDBLOCK)
7082 /* Set a small timeout. */
7083 timeout = make_emacs_time (1, 0);
7084 FD_ZERO (&fdset);
7085 FD_SET ((int)fd, &fdset);
7087 /* Use select with the timeout to poll the selector. */
7088 sc = select (fd + 1, &fdset, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
7089 &timeout, NULL);
7091 if (sc > 0)
7092 continue; /* Try again. */
7094 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
7095 Also accept select return 0 as an indicator to EAGAIN. */
7096 if (sc == 0 || errno == EWOULDBLOCK)
7097 err = EAGAIN;
7098 else
7099 err = errno; /* Other errors are just passed on. */
7102 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
7104 return -1;
7108 ssize_t
7109 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
7111 struct Lisp_Process *process = (struct Lisp_Process *)p;
7112 int fd = process->outfd;
7113 ssize_t n = sys_write (fd, buf, sz);
7115 /* 0 or more bytes written means everything went fine. */
7116 if (n >= 0)
7117 return n;
7119 /* Negative bytes written means we got an error in errno.
7120 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7121 emacs_gnutls_transport_set_errno (process->gnutls_state,
7122 errno == EWOULDBLOCK ? EAGAIN : errno);
7124 return -1;
7126 #endif /* HAVE_GNUTLS */
7128 /* end of w32.c */