Converted compile-time tests to run-time tests. Menus display!
[emacs.git] / src / w32.c
blob1dcf46b5f4bc1b83819256e1986be0de8cf4ae0a
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 <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
33 #include <sys/time.h>
34 #include <sys/utime.h>
35 #include <math.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 open
51 #undef rename
52 #undef rmdir
53 #undef unlink
55 #undef close
56 #undef dup
57 #undef dup2
58 #undef pipe
59 #undef read
60 #undef write
62 #undef strerror
64 #undef localtime
66 #include "lisp.h"
67 #include "epaths.h" /* for SHELL */
69 #include <pwd.h>
70 #include <grp.h>
72 /* MinGW64 (_W64) defines these in its _mingw.h. */
73 #if defined(__GNUC__) && !defined(_W64)
74 #define _ANONYMOUS_UNION
75 #define _ANONYMOUS_STRUCT
76 #endif
77 #include <windows.h>
78 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
79 use a different name to avoid compilation problems. */
80 typedef struct _MEMORY_STATUS_EX {
81 DWORD dwLength;
82 DWORD dwMemoryLoad;
83 DWORDLONG ullTotalPhys;
84 DWORDLONG ullAvailPhys;
85 DWORDLONG ullTotalPageFile;
86 DWORDLONG ullAvailPageFile;
87 DWORDLONG ullTotalVirtual;
88 DWORDLONG ullAvailVirtual;
89 DWORDLONG ullAvailExtendedVirtual;
90 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
92 /* These are here so that GDB would know about these data types. This
93 allows to attach GDB to Emacs when a fatal exception is triggered
94 and Windows pops up the "application needs to be closed" dialog.
95 At that point, _gnu_exception_handler, the top-level exception
96 handler installed by the MinGW startup code, is somewhere on the
97 call-stack of the main thread, so going to that call frame and
98 looking at the argument to _gnu_exception_handler, which is a
99 PEXCEPTION_POINTERS pointer, can reveal the exception code
100 (excptr->ExceptionRecord->ExceptionCode) and the address where the
101 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
102 well as some additional information specific to the exception. */
103 PEXCEPTION_POINTERS excptr;
104 PEXCEPTION_RECORD excprec;
105 PCONTEXT ctxrec;
107 #include <lmcons.h>
108 #include <shlobj.h>
110 #include <tlhelp32.h>
111 #include <psapi.h>
112 #ifndef _MSC_VER
113 #include <w32api.h>
114 #endif
115 #if _WIN32_WINNT < 0x0500
116 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
117 /* This either is not in psapi.h or guarded by higher value of
118 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
119 defines it in psapi.h */
120 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
121 DWORD cb;
122 DWORD PageFaultCount;
123 SIZE_T PeakWorkingSetSize;
124 SIZE_T WorkingSetSize;
125 SIZE_T QuotaPeakPagedPoolUsage;
126 SIZE_T QuotaPagedPoolUsage;
127 SIZE_T QuotaPeakNonPagedPoolUsage;
128 SIZE_T QuotaNonPagedPoolUsage;
129 SIZE_T PagefileUsage;
130 SIZE_T PeakPagefileUsage;
131 SIZE_T PrivateUsage;
132 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
133 #endif
134 #endif
136 #include <winioctl.h>
137 #include <aclapi.h>
138 #include <sddl.h>
140 #include <sys/acl.h>
142 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
143 define them by hand if not already defined. */
144 #ifndef SDDL_REVISION_1
145 #define SDDL_REVISION_1 1
146 #endif /* SDDL_REVISION_1 */
148 #if defined(_MSC_VER) || defined(_W64)
149 /* MSVC and MinGW64 don't provide the definition of
150 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
151 which cannot be included because it triggers conflicts with other
152 Windows API headers. So we define it here by hand. */
154 typedef struct _REPARSE_DATA_BUFFER {
155 ULONG ReparseTag;
156 USHORT ReparseDataLength;
157 USHORT Reserved;
158 union {
159 struct {
160 USHORT SubstituteNameOffset;
161 USHORT SubstituteNameLength;
162 USHORT PrintNameOffset;
163 USHORT PrintNameLength;
164 ULONG Flags;
165 WCHAR PathBuffer[1];
166 } SymbolicLinkReparseBuffer;
167 struct {
168 USHORT SubstituteNameOffset;
169 USHORT SubstituteNameLength;
170 USHORT PrintNameOffset;
171 USHORT PrintNameLength;
172 WCHAR PathBuffer[1];
173 } MountPointReparseBuffer;
174 struct {
175 UCHAR DataBuffer[1];
176 } GenericReparseBuffer;
177 } DUMMYUNIONNAME;
178 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
180 #ifndef FILE_DEVICE_FILE_SYSTEM
181 #define FILE_DEVICE_FILE_SYSTEM 9
182 #endif
183 #ifndef METHOD_BUFFERED
184 #define METHOD_BUFFERED 0
185 #endif
186 #ifndef FILE_ANY_ACCESS
187 #define FILE_ANY_ACCESS 0x00000000
188 #endif
189 #ifndef CTL_CODE
190 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
191 #endif
192 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
193 #ifndef FSCTL_GET_REPARSE_POINT
194 #define FSCTL_GET_REPARSE_POINT \
195 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
196 #endif
197 #endif
199 /* TCP connection support. */
200 #include <sys/socket.h>
201 #undef socket
202 #undef bind
203 #undef connect
204 #undef htons
205 #undef ntohs
206 #undef inet_addr
207 #undef gethostname
208 #undef gethostbyname
209 #undef getservbyname
210 #undef getpeername
211 #undef shutdown
212 #undef setsockopt
213 #undef listen
214 #undef getsockname
215 #undef accept
216 #undef recvfrom
217 #undef sendto
219 #include "w32.h"
220 #include <dirent.h>
221 #include "w32common.h"
222 #include "w32heap.h"
223 #include "w32select.h"
224 #include "systime.h"
225 #include "dispextern.h" /* for xstrcasecmp */
226 #include "coding.h" /* for Vlocale_coding_system */
228 #include "careadlinkat.h"
229 #include "allocator.h"
231 /* For serial_configure and serial_open. */
232 #include "process.h"
234 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
235 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
237 Lisp_Object QCloaded_from;
239 void globals_of_w32 (void);
240 static DWORD get_rid (PSID);
241 static int is_symlink (const char *);
242 static char * chase_symlinks (const char *);
243 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
244 static int restore_privilege (TOKEN_PRIVILEGES *);
245 static BOOL WINAPI revert_to_self (void);
247 extern int sys_access (const char *, int);
248 extern void *e_malloc (size_t);
249 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
250 struct timespec *, void *);
251 extern int sys_dup (int);
256 /* Initialization states.
258 WARNING: If you add any more such variables for additional APIs,
259 you MUST add initialization for them to globals_of_w32
260 below. This is because these variables might get set
261 to non-NULL values during dumping, but the dumped Emacs
262 cannot reuse those values, because it could be run on a
263 different version of the OS, where API addresses are
264 different. */
265 static BOOL g_b_init_is_windows_9x;
266 static BOOL g_b_init_open_process_token;
267 static BOOL g_b_init_get_token_information;
268 static BOOL g_b_init_lookup_account_sid;
269 static BOOL g_b_init_get_sid_sub_authority;
270 static BOOL g_b_init_get_sid_sub_authority_count;
271 static BOOL g_b_init_get_security_info;
272 static BOOL g_b_init_get_file_security;
273 static BOOL g_b_init_get_security_descriptor_owner;
274 static BOOL g_b_init_get_security_descriptor_group;
275 static BOOL g_b_init_is_valid_sid;
276 static BOOL g_b_init_create_toolhelp32_snapshot;
277 static BOOL g_b_init_process32_first;
278 static BOOL g_b_init_process32_next;
279 static BOOL g_b_init_open_thread_token;
280 static BOOL g_b_init_impersonate_self;
281 static BOOL g_b_init_revert_to_self;
282 static BOOL g_b_init_get_process_memory_info;
283 static BOOL g_b_init_get_process_working_set_size;
284 static BOOL g_b_init_global_memory_status;
285 static BOOL g_b_init_global_memory_status_ex;
286 static BOOL g_b_init_get_length_sid;
287 static BOOL g_b_init_equal_sid;
288 static BOOL g_b_init_copy_sid;
289 static BOOL g_b_init_get_native_system_info;
290 static BOOL g_b_init_get_system_times;
291 static BOOL g_b_init_create_symbolic_link;
292 static BOOL g_b_init_get_security_descriptor_dacl;
293 static BOOL g_b_init_convert_sd_to_sddl;
294 static BOOL g_b_init_convert_sddl_to_sd;
295 static BOOL g_b_init_is_valid_security_descriptor;
296 static BOOL g_b_init_set_file_security;
299 BEGIN: Wrapper functions around OpenProcessToken
300 and other functions in advapi32.dll that are only
301 supported in Windows NT / 2k / XP
303 /* ** Function pointer typedefs ** */
304 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
305 HANDLE ProcessHandle,
306 DWORD DesiredAccess,
307 PHANDLE TokenHandle);
308 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
309 HANDLE TokenHandle,
310 TOKEN_INFORMATION_CLASS TokenInformationClass,
311 LPVOID TokenInformation,
312 DWORD TokenInformationLength,
313 PDWORD ReturnLength);
314 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
315 HANDLE process_handle,
316 LPFILETIME creation_time,
317 LPFILETIME exit_time,
318 LPFILETIME kernel_time,
319 LPFILETIME user_time);
321 GetProcessTimes_Proc get_process_times_fn = NULL;
323 #ifdef _UNICODE
324 const char * const LookupAccountSid_Name = "LookupAccountSidW";
325 const char * const GetFileSecurity_Name = "GetFileSecurityW";
326 const char * const SetFileSecurity_Name = "SetFileSecurityW";
327 #else
328 const char * const LookupAccountSid_Name = "LookupAccountSidA";
329 const char * const GetFileSecurity_Name = "GetFileSecurityA";
330 const char * const SetFileSecurity_Name = "SetFileSecurityA";
331 #endif
332 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
333 LPCTSTR lpSystemName,
334 PSID Sid,
335 LPTSTR Name,
336 LPDWORD cbName,
337 LPTSTR DomainName,
338 LPDWORD cbDomainName,
339 PSID_NAME_USE peUse);
340 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
341 PSID pSid,
342 DWORD n);
343 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
344 PSID pSid);
345 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
346 HANDLE handle,
347 SE_OBJECT_TYPE ObjectType,
348 SECURITY_INFORMATION SecurityInfo,
349 PSID *ppsidOwner,
350 PSID *ppsidGroup,
351 PACL *ppDacl,
352 PACL *ppSacl,
353 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
354 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
355 LPCTSTR lpFileName,
356 SECURITY_INFORMATION RequestedInformation,
357 PSECURITY_DESCRIPTOR pSecurityDescriptor,
358 DWORD nLength,
359 LPDWORD lpnLengthNeeded);
360 typedef BOOL (WINAPI *SetFileSecurity_Proc) (
361 LPCTSTR lpFileName,
362 SECURITY_INFORMATION SecurityInformation,
363 PSECURITY_DESCRIPTOR pSecurityDescriptor);
364 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
365 PSECURITY_DESCRIPTOR pSecurityDescriptor,
366 PSID *pOwner,
367 LPBOOL lpbOwnerDefaulted);
368 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
369 PSECURITY_DESCRIPTOR pSecurityDescriptor,
370 PSID *pGroup,
371 LPBOOL lpbGroupDefaulted);
372 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
373 PSECURITY_DESCRIPTOR pSecurityDescriptor,
374 LPBOOL lpbDaclPresent,
375 PACL *pDacl,
376 LPBOOL lpbDaclDefaulted);
377 typedef BOOL (WINAPI * IsValidSid_Proc) (
378 PSID sid);
379 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
380 DWORD dwFlags,
381 DWORD th32ProcessID);
382 typedef BOOL (WINAPI * Process32First_Proc) (
383 HANDLE hSnapshot,
384 LPPROCESSENTRY32 lppe);
385 typedef BOOL (WINAPI * Process32Next_Proc) (
386 HANDLE hSnapshot,
387 LPPROCESSENTRY32 lppe);
388 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
389 HANDLE ThreadHandle,
390 DWORD DesiredAccess,
391 BOOL OpenAsSelf,
392 PHANDLE TokenHandle);
393 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
394 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
395 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
396 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
397 HANDLE Process,
398 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
399 DWORD cb);
400 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
401 HANDLE hProcess,
402 PSIZE_T lpMinimumWorkingSetSize,
403 PSIZE_T lpMaximumWorkingSetSize);
404 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
405 LPMEMORYSTATUS lpBuffer);
406 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
407 LPMEMORY_STATUS_EX lpBuffer);
408 typedef BOOL (WINAPI * CopySid_Proc) (
409 DWORD nDestinationSidLength,
410 PSID pDestinationSid,
411 PSID pSourceSid);
412 typedef BOOL (WINAPI * EqualSid_Proc) (
413 PSID pSid1,
414 PSID pSid2);
415 typedef DWORD (WINAPI * GetLengthSid_Proc) (
416 PSID pSid);
417 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
418 LPSYSTEM_INFO lpSystemInfo);
419 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
420 LPFILETIME lpIdleTime,
421 LPFILETIME lpKernelTime,
422 LPFILETIME lpUserTime);
423 typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) (
424 LPTSTR lpSymlinkFileName,
425 LPTSTR lpTargetFileName,
426 DWORD dwFlags);
427 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
428 LPCTSTR StringSecurityDescriptor,
429 DWORD StringSDRevision,
430 PSECURITY_DESCRIPTOR *SecurityDescriptor,
431 PULONG SecurityDescriptorSize);
432 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
433 PSECURITY_DESCRIPTOR SecurityDescriptor,
434 DWORD RequestedStringSDRevision,
435 SECURITY_INFORMATION SecurityInformation,
436 LPTSTR *StringSecurityDescriptor,
437 PULONG StringSecurityDescriptorLen);
438 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
440 /* ** A utility function ** */
441 static BOOL
442 is_windows_9x (void)
444 static BOOL s_b_ret = 0;
445 OSVERSIONINFO os_ver;
446 if (g_b_init_is_windows_9x == 0)
448 g_b_init_is_windows_9x = 1;
449 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
450 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
451 if (GetVersionEx (&os_ver))
453 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
456 return s_b_ret;
459 static Lisp_Object ltime (ULONGLONG);
461 /* Get total user and system times for get-internal-run-time.
462 Returns a list of integers if the times are provided by the OS
463 (NT derivatives), otherwise it returns the result of current-time. */
464 Lisp_Object
465 w32_get_internal_run_time (void)
467 if (get_process_times_fn)
469 FILETIME create, exit, kernel, user;
470 HANDLE proc = GetCurrentProcess ();
471 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
473 LARGE_INTEGER user_int, kernel_int, total;
474 user_int.LowPart = user.dwLowDateTime;
475 user_int.HighPart = user.dwHighDateTime;
476 kernel_int.LowPart = kernel.dwLowDateTime;
477 kernel_int.HighPart = kernel.dwHighDateTime;
478 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
479 return ltime (total.QuadPart);
483 return Fcurrent_time ();
486 /* ** The wrapper functions ** */
488 static BOOL WINAPI
489 open_process_token (HANDLE ProcessHandle,
490 DWORD DesiredAccess,
491 PHANDLE TokenHandle)
493 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
494 HMODULE hm_advapi32 = NULL;
495 if (is_windows_9x () == TRUE)
497 return FALSE;
499 if (g_b_init_open_process_token == 0)
501 g_b_init_open_process_token = 1;
502 hm_advapi32 = LoadLibrary ("Advapi32.dll");
503 s_pfn_Open_Process_Token =
504 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
506 if (s_pfn_Open_Process_Token == NULL)
508 return FALSE;
510 return (
511 s_pfn_Open_Process_Token (
512 ProcessHandle,
513 DesiredAccess,
514 TokenHandle)
518 static BOOL WINAPI
519 get_token_information (HANDLE TokenHandle,
520 TOKEN_INFORMATION_CLASS TokenInformationClass,
521 LPVOID TokenInformation,
522 DWORD TokenInformationLength,
523 PDWORD ReturnLength)
525 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
526 HMODULE hm_advapi32 = NULL;
527 if (is_windows_9x () == TRUE)
529 return FALSE;
531 if (g_b_init_get_token_information == 0)
533 g_b_init_get_token_information = 1;
534 hm_advapi32 = LoadLibrary ("Advapi32.dll");
535 s_pfn_Get_Token_Information =
536 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
538 if (s_pfn_Get_Token_Information == NULL)
540 return FALSE;
542 return (
543 s_pfn_Get_Token_Information (
544 TokenHandle,
545 TokenInformationClass,
546 TokenInformation,
547 TokenInformationLength,
548 ReturnLength)
552 static BOOL WINAPI
553 lookup_account_sid (LPCTSTR lpSystemName,
554 PSID Sid,
555 LPTSTR Name,
556 LPDWORD cbName,
557 LPTSTR DomainName,
558 LPDWORD cbDomainName,
559 PSID_NAME_USE peUse)
561 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
562 HMODULE hm_advapi32 = NULL;
563 if (is_windows_9x () == TRUE)
565 return FALSE;
567 if (g_b_init_lookup_account_sid == 0)
569 g_b_init_lookup_account_sid = 1;
570 hm_advapi32 = LoadLibrary ("Advapi32.dll");
571 s_pfn_Lookup_Account_Sid =
572 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
574 if (s_pfn_Lookup_Account_Sid == NULL)
576 return FALSE;
578 return (
579 s_pfn_Lookup_Account_Sid (
580 lpSystemName,
581 Sid,
582 Name,
583 cbName,
584 DomainName,
585 cbDomainName,
586 peUse)
590 static PDWORD WINAPI
591 get_sid_sub_authority (PSID pSid, DWORD n)
593 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
594 static DWORD zero = 0U;
595 HMODULE hm_advapi32 = NULL;
596 if (is_windows_9x () == TRUE)
598 return &zero;
600 if (g_b_init_get_sid_sub_authority == 0)
602 g_b_init_get_sid_sub_authority = 1;
603 hm_advapi32 = LoadLibrary ("Advapi32.dll");
604 s_pfn_Get_Sid_Sub_Authority =
605 (GetSidSubAuthority_Proc) GetProcAddress (
606 hm_advapi32, "GetSidSubAuthority");
608 if (s_pfn_Get_Sid_Sub_Authority == NULL)
610 return &zero;
612 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
615 static PUCHAR WINAPI
616 get_sid_sub_authority_count (PSID pSid)
618 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
619 static UCHAR zero = 0U;
620 HMODULE hm_advapi32 = NULL;
621 if (is_windows_9x () == TRUE)
623 return &zero;
625 if (g_b_init_get_sid_sub_authority_count == 0)
627 g_b_init_get_sid_sub_authority_count = 1;
628 hm_advapi32 = LoadLibrary ("Advapi32.dll");
629 s_pfn_Get_Sid_Sub_Authority_Count =
630 (GetSidSubAuthorityCount_Proc) GetProcAddress (
631 hm_advapi32, "GetSidSubAuthorityCount");
633 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
635 return &zero;
637 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
640 static DWORD WINAPI
641 get_security_info (HANDLE handle,
642 SE_OBJECT_TYPE ObjectType,
643 SECURITY_INFORMATION SecurityInfo,
644 PSID *ppsidOwner,
645 PSID *ppsidGroup,
646 PACL *ppDacl,
647 PACL *ppSacl,
648 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
650 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
651 HMODULE hm_advapi32 = NULL;
652 if (is_windows_9x () == TRUE)
654 return FALSE;
656 if (g_b_init_get_security_info == 0)
658 g_b_init_get_security_info = 1;
659 hm_advapi32 = LoadLibrary ("Advapi32.dll");
660 s_pfn_Get_Security_Info =
661 (GetSecurityInfo_Proc) GetProcAddress (
662 hm_advapi32, "GetSecurityInfo");
664 if (s_pfn_Get_Security_Info == NULL)
666 return FALSE;
668 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
669 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
670 ppSecurityDescriptor));
673 static BOOL WINAPI
674 get_file_security (LPCTSTR lpFileName,
675 SECURITY_INFORMATION RequestedInformation,
676 PSECURITY_DESCRIPTOR pSecurityDescriptor,
677 DWORD nLength,
678 LPDWORD lpnLengthNeeded)
680 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
681 HMODULE hm_advapi32 = NULL;
682 if (is_windows_9x () == TRUE)
684 errno = ENOTSUP;
685 return FALSE;
687 if (g_b_init_get_file_security == 0)
689 g_b_init_get_file_security = 1;
690 hm_advapi32 = LoadLibrary ("Advapi32.dll");
691 s_pfn_Get_File_Security =
692 (GetFileSecurity_Proc) GetProcAddress (
693 hm_advapi32, GetFileSecurity_Name);
695 if (s_pfn_Get_File_Security == NULL)
697 errno = ENOTSUP;
698 return FALSE;
700 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
701 pSecurityDescriptor, nLength,
702 lpnLengthNeeded));
705 static BOOL WINAPI
706 set_file_security (LPCTSTR lpFileName,
707 SECURITY_INFORMATION SecurityInformation,
708 PSECURITY_DESCRIPTOR pSecurityDescriptor)
710 static SetFileSecurity_Proc s_pfn_Set_File_Security = NULL;
711 HMODULE hm_advapi32 = NULL;
712 if (is_windows_9x () == TRUE)
714 errno = ENOTSUP;
715 return FALSE;
717 if (g_b_init_set_file_security == 0)
719 g_b_init_set_file_security = 1;
720 hm_advapi32 = LoadLibrary ("Advapi32.dll");
721 s_pfn_Set_File_Security =
722 (SetFileSecurity_Proc) GetProcAddress (
723 hm_advapi32, SetFileSecurity_Name);
725 if (s_pfn_Set_File_Security == NULL)
727 errno = ENOTSUP;
728 return FALSE;
730 return (s_pfn_Set_File_Security (lpFileName, SecurityInformation,
731 pSecurityDescriptor));
734 static BOOL WINAPI
735 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
736 PSID *pOwner,
737 LPBOOL lpbOwnerDefaulted)
739 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
740 HMODULE hm_advapi32 = NULL;
741 if (is_windows_9x () == TRUE)
743 errno = ENOTSUP;
744 return FALSE;
746 if (g_b_init_get_security_descriptor_owner == 0)
748 g_b_init_get_security_descriptor_owner = 1;
749 hm_advapi32 = LoadLibrary ("Advapi32.dll");
750 s_pfn_Get_Security_Descriptor_Owner =
751 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
752 hm_advapi32, "GetSecurityDescriptorOwner");
754 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
756 errno = ENOTSUP;
757 return FALSE;
759 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
760 lpbOwnerDefaulted));
763 static BOOL WINAPI
764 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
765 PSID *pGroup,
766 LPBOOL lpbGroupDefaulted)
768 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
769 HMODULE hm_advapi32 = NULL;
770 if (is_windows_9x () == TRUE)
772 errno = ENOTSUP;
773 return FALSE;
775 if (g_b_init_get_security_descriptor_group == 0)
777 g_b_init_get_security_descriptor_group = 1;
778 hm_advapi32 = LoadLibrary ("Advapi32.dll");
779 s_pfn_Get_Security_Descriptor_Group =
780 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
781 hm_advapi32, "GetSecurityDescriptorGroup");
783 if (s_pfn_Get_Security_Descriptor_Group == NULL)
785 errno = ENOTSUP;
786 return FALSE;
788 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
789 lpbGroupDefaulted));
792 static BOOL WINAPI
793 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
794 LPBOOL lpbDaclPresent,
795 PACL *pDacl,
796 LPBOOL lpbDaclDefaulted)
798 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
799 HMODULE hm_advapi32 = NULL;
800 if (is_windows_9x () == TRUE)
802 errno = ENOTSUP;
803 return FALSE;
805 if (g_b_init_get_security_descriptor_dacl == 0)
807 g_b_init_get_security_descriptor_dacl = 1;
808 hm_advapi32 = LoadLibrary ("Advapi32.dll");
809 s_pfn_Get_Security_Descriptor_Dacl =
810 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
811 hm_advapi32, "GetSecurityDescriptorDacl");
813 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
815 errno = ENOTSUP;
816 return FALSE;
818 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
819 lpbDaclPresent, pDacl,
820 lpbDaclDefaulted));
823 static BOOL WINAPI
824 is_valid_sid (PSID sid)
826 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
827 HMODULE hm_advapi32 = NULL;
828 if (is_windows_9x () == TRUE)
830 return FALSE;
832 if (g_b_init_is_valid_sid == 0)
834 g_b_init_is_valid_sid = 1;
835 hm_advapi32 = LoadLibrary ("Advapi32.dll");
836 s_pfn_Is_Valid_Sid =
837 (IsValidSid_Proc) GetProcAddress (
838 hm_advapi32, "IsValidSid");
840 if (s_pfn_Is_Valid_Sid == NULL)
842 return FALSE;
844 return (s_pfn_Is_Valid_Sid (sid));
847 static BOOL WINAPI
848 equal_sid (PSID sid1, PSID sid2)
850 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
851 HMODULE hm_advapi32 = NULL;
852 if (is_windows_9x () == TRUE)
854 return FALSE;
856 if (g_b_init_equal_sid == 0)
858 g_b_init_equal_sid = 1;
859 hm_advapi32 = LoadLibrary ("Advapi32.dll");
860 s_pfn_Equal_Sid =
861 (EqualSid_Proc) GetProcAddress (
862 hm_advapi32, "EqualSid");
864 if (s_pfn_Equal_Sid == NULL)
866 return FALSE;
868 return (s_pfn_Equal_Sid (sid1, sid2));
871 static DWORD WINAPI
872 get_length_sid (PSID sid)
874 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
875 HMODULE hm_advapi32 = NULL;
876 if (is_windows_9x () == TRUE)
878 return 0;
880 if (g_b_init_get_length_sid == 0)
882 g_b_init_get_length_sid = 1;
883 hm_advapi32 = LoadLibrary ("Advapi32.dll");
884 s_pfn_Get_Length_Sid =
885 (GetLengthSid_Proc) GetProcAddress (
886 hm_advapi32, "GetLengthSid");
888 if (s_pfn_Get_Length_Sid == NULL)
890 return 0;
892 return (s_pfn_Get_Length_Sid (sid));
895 static BOOL WINAPI
896 copy_sid (DWORD destlen, PSID dest, PSID src)
898 static CopySid_Proc s_pfn_Copy_Sid = NULL;
899 HMODULE hm_advapi32 = NULL;
900 if (is_windows_9x () == TRUE)
902 return FALSE;
904 if (g_b_init_copy_sid == 0)
906 g_b_init_copy_sid = 1;
907 hm_advapi32 = LoadLibrary ("Advapi32.dll");
908 s_pfn_Copy_Sid =
909 (CopySid_Proc) GetProcAddress (
910 hm_advapi32, "CopySid");
912 if (s_pfn_Copy_Sid == NULL)
914 return FALSE;
916 return (s_pfn_Copy_Sid (destlen, dest, src));
920 END: Wrapper functions around OpenProcessToken
921 and other functions in advapi32.dll that are only
922 supported in Windows NT / 2k / XP
925 static void WINAPI
926 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
928 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
929 if (is_windows_9x () != TRUE)
931 if (g_b_init_get_native_system_info == 0)
933 g_b_init_get_native_system_info = 1;
934 s_pfn_Get_Native_System_Info =
935 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
936 "GetNativeSystemInfo");
938 if (s_pfn_Get_Native_System_Info != NULL)
939 s_pfn_Get_Native_System_Info (lpSystemInfo);
941 else
942 lpSystemInfo->dwNumberOfProcessors = -1;
945 static BOOL WINAPI
946 get_system_times (LPFILETIME lpIdleTime,
947 LPFILETIME lpKernelTime,
948 LPFILETIME lpUserTime)
950 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
951 if (is_windows_9x () == TRUE)
953 return FALSE;
955 if (g_b_init_get_system_times == 0)
957 g_b_init_get_system_times = 1;
958 s_pfn_Get_System_times =
959 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
960 "GetSystemTimes");
962 if (s_pfn_Get_System_times == NULL)
963 return FALSE;
964 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
967 static BOOLEAN WINAPI
968 create_symbolic_link (LPTSTR lpSymlinkFilename,
969 LPTSTR lpTargetFileName,
970 DWORD dwFlags)
972 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link = NULL;
973 BOOLEAN retval;
975 if (is_windows_9x () == TRUE)
977 errno = ENOSYS;
978 return 0;
980 if (g_b_init_create_symbolic_link == 0)
982 g_b_init_create_symbolic_link = 1;
983 #ifdef _UNICODE
984 s_pfn_Create_Symbolic_Link =
985 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
986 "CreateSymbolicLinkW");
987 #else
988 s_pfn_Create_Symbolic_Link =
989 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
990 "CreateSymbolicLinkA");
991 #endif
993 if (s_pfn_Create_Symbolic_Link == NULL)
995 errno = ENOSYS;
996 return 0;
999 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
1000 dwFlags);
1001 /* If we were denied creation of the symlink, try again after
1002 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1003 if (!retval)
1005 TOKEN_PRIVILEGES priv_current;
1007 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE, &priv_current))
1009 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
1010 dwFlags);
1011 restore_privilege (&priv_current);
1012 revert_to_self ();
1015 return retval;
1018 static BOOL WINAPI
1019 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1021 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1023 if (is_windows_9x () == TRUE)
1025 errno = ENOTSUP;
1026 return FALSE;
1029 if (g_b_init_is_valid_security_descriptor == 0)
1031 g_b_init_is_valid_security_descriptor = 1;
1032 s_pfn_Is_Valid_Security_Descriptor_Proc =
1033 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1034 "IsValidSecurityDescriptor");
1036 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1038 errno = ENOTSUP;
1039 return FALSE;
1042 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1045 static BOOL WINAPI
1046 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1047 DWORD RequestedStringSDRevision,
1048 SECURITY_INFORMATION SecurityInformation,
1049 LPTSTR *StringSecurityDescriptor,
1050 PULONG StringSecurityDescriptorLen)
1052 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1053 BOOL retval;
1055 if (is_windows_9x () == TRUE)
1057 errno = ENOTSUP;
1058 return FALSE;
1061 if (g_b_init_convert_sd_to_sddl == 0)
1063 g_b_init_convert_sd_to_sddl = 1;
1064 #ifdef _UNICODE
1065 s_pfn_Convert_SD_To_SDDL =
1066 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1067 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1068 #else
1069 s_pfn_Convert_SD_To_SDDL =
1070 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1071 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1072 #endif
1074 if (s_pfn_Convert_SD_To_SDDL == NULL)
1076 errno = ENOTSUP;
1077 return FALSE;
1080 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1081 RequestedStringSDRevision,
1082 SecurityInformation,
1083 StringSecurityDescriptor,
1084 StringSecurityDescriptorLen);
1086 return retval;
1089 static BOOL WINAPI
1090 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1091 DWORD StringSDRevision,
1092 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1093 PULONG SecurityDescriptorSize)
1095 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1096 BOOL retval;
1098 if (is_windows_9x () == TRUE)
1100 errno = ENOTSUP;
1101 return FALSE;
1104 if (g_b_init_convert_sddl_to_sd == 0)
1106 g_b_init_convert_sddl_to_sd = 1;
1107 #ifdef _UNICODE
1108 s_pfn_Convert_SDDL_To_SD =
1109 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1110 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1111 #else
1112 s_pfn_Convert_SDDL_To_SD =
1113 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1114 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1115 #endif
1117 if (s_pfn_Convert_SDDL_To_SD == NULL)
1119 errno = ENOTSUP;
1120 return FALSE;
1123 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1124 StringSDRevision,
1125 SecurityDescriptor,
1126 SecurityDescriptorSize);
1128 return retval;
1133 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1134 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1136 This is called from alloc.c:valid_pointer_p. */
1138 w32_valid_pointer_p (void *p, int size)
1140 SIZE_T done;
1141 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1143 if (h)
1145 unsigned char *buf = alloca (size);
1146 int retval = ReadProcessMemory (h, p, buf, size, &done);
1148 CloseHandle (h);
1149 return retval;
1151 else
1152 return -1;
1155 static char startup_dir[MAXPATHLEN];
1157 /* Get the current working directory. */
1158 char *
1159 getcwd (char *dir, int dirsize)
1161 if (!dirsize)
1163 errno = EINVAL;
1164 return NULL;
1166 if (dirsize <= strlen (startup_dir))
1168 errno = ERANGE;
1169 return NULL;
1171 #if 0
1172 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1173 return dir;
1174 return NULL;
1175 #else
1176 /* Emacs doesn't actually change directory itself, it stays in the
1177 same directory where it was started. */
1178 strcpy (dir, startup_dir);
1179 return dir;
1180 #endif
1183 /* Emulate getloadavg. */
1185 struct load_sample {
1186 time_t sample_time;
1187 ULONGLONG idle;
1188 ULONGLONG kernel;
1189 ULONGLONG user;
1192 /* Number of processors on this machine. */
1193 static unsigned num_of_processors;
1195 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1196 static struct load_sample samples[16*60];
1197 static int first_idx = -1, last_idx = -1;
1198 static int max_idx = sizeof (samples) / sizeof (samples[0]);
1200 static int
1201 buf_next (int from)
1203 int next_idx = from + 1;
1205 if (next_idx >= max_idx)
1206 next_idx = 0;
1208 return next_idx;
1211 static int
1212 buf_prev (int from)
1214 int prev_idx = from - 1;
1216 if (prev_idx < 0)
1217 prev_idx = max_idx - 1;
1219 return prev_idx;
1222 static void
1223 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1225 SYSTEM_INFO sysinfo;
1226 FILETIME ft_idle, ft_user, ft_kernel;
1228 /* Initialize the number of processors on this machine. */
1229 if (num_of_processors <= 0)
1231 get_native_system_info (&sysinfo);
1232 num_of_processors = sysinfo.dwNumberOfProcessors;
1233 if (num_of_processors <= 0)
1235 GetSystemInfo (&sysinfo);
1236 num_of_processors = sysinfo.dwNumberOfProcessors;
1238 if (num_of_processors <= 0)
1239 num_of_processors = 1;
1242 /* TODO: Take into account threads that are ready to run, by
1243 sampling the "\System\Processor Queue Length" performance
1244 counter. The code below accounts only for threads that are
1245 actually running. */
1247 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1249 ULARGE_INTEGER uidle, ukernel, uuser;
1251 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1252 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1253 memcpy (&uuser, &ft_user, sizeof (ft_user));
1254 *idle = uidle.QuadPart;
1255 *kernel = ukernel.QuadPart;
1256 *user = uuser.QuadPart;
1258 else
1260 *idle = 0;
1261 *kernel = 0;
1262 *user = 0;
1266 /* Produce the load average for a given time interval, using the
1267 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1268 1-minute, 5-minute, or 15-minute average, respectively. */
1269 static double
1270 getavg (int which)
1272 double retval = -1.0;
1273 double tdiff;
1274 int idx;
1275 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1276 time_t now = samples[last_idx].sample_time;
1278 if (first_idx != last_idx)
1280 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1282 tdiff = difftime (now, samples[idx].sample_time);
1283 if (tdiff >= span - 2*DBL_EPSILON*now)
1285 long double sys =
1286 samples[last_idx].kernel + samples[last_idx].user
1287 - (samples[idx].kernel + samples[idx].user);
1288 long double idl = samples[last_idx].idle - samples[idx].idle;
1290 retval = (1.0 - idl / sys) * num_of_processors;
1291 break;
1293 if (idx == first_idx)
1294 break;
1298 return retval;
1302 getloadavg (double loadavg[], int nelem)
1304 int elem;
1305 ULONGLONG idle, kernel, user;
1306 time_t now = time (NULL);
1308 /* Store another sample. We ignore samples that are less than 1 sec
1309 apart. */
1310 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
1312 sample_system_load (&idle, &kernel, &user);
1313 last_idx = buf_next (last_idx);
1314 samples[last_idx].sample_time = now;
1315 samples[last_idx].idle = idle;
1316 samples[last_idx].kernel = kernel;
1317 samples[last_idx].user = user;
1318 /* If the buffer has more that 15 min worth of samples, discard
1319 the old ones. */
1320 if (first_idx == -1)
1321 first_idx = last_idx;
1322 while (first_idx != last_idx
1323 && (difftime (now, samples[first_idx].sample_time)
1324 >= 15.0*60 + 2*DBL_EPSILON*now))
1325 first_idx = buf_next (first_idx);
1328 for (elem = 0; elem < nelem; elem++)
1330 double avg = getavg (elem);
1332 if (avg < 0)
1333 break;
1334 loadavg[elem] = avg;
1337 return elem;
1340 /* Emulate getpwuid, getpwnam and others. */
1342 #define PASSWD_FIELD_SIZE 256
1344 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1345 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1346 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1347 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
1348 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
1350 static struct passwd dflt_passwd =
1352 dflt_passwd_name,
1353 dflt_passwd_passwd,
1357 dflt_passwd_gecos,
1358 dflt_passwd_dir,
1359 dflt_passwd_shell,
1362 static char dflt_group_name[GNLEN+1];
1364 static struct group dflt_group =
1366 /* When group information is not available, we return this as the
1367 group for all files. */
1368 dflt_group_name,
1372 unsigned
1373 getuid (void)
1375 return dflt_passwd.pw_uid;
1378 unsigned
1379 geteuid (void)
1381 /* I could imagine arguing for checking to see whether the user is
1382 in the Administrators group and returning a UID of 0 for that
1383 case, but I don't know how wise that would be in the long run. */
1384 return getuid ();
1387 unsigned
1388 getgid (void)
1390 return dflt_passwd.pw_gid;
1393 unsigned
1394 getegid (void)
1396 return getgid ();
1399 struct passwd *
1400 getpwuid (unsigned uid)
1402 if (uid == dflt_passwd.pw_uid)
1403 return &dflt_passwd;
1404 return NULL;
1407 struct group *
1408 getgrgid (gid_t gid)
1410 return &dflt_group;
1413 struct passwd *
1414 getpwnam (char *name)
1416 struct passwd *pw;
1418 pw = getpwuid (getuid ());
1419 if (!pw)
1420 return pw;
1422 if (xstrcasecmp (name, pw->pw_name))
1423 return NULL;
1425 return pw;
1428 static void
1429 init_user_info (void)
1431 /* Find the user's real name by opening the process token and
1432 looking up the name associated with the user-sid in that token.
1434 Use the relative portion of the identifier authority value from
1435 the user-sid as the user id value (same for group id using the
1436 primary group sid from the process token). */
1438 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1439 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1440 DWORD glength = sizeof (gname);
1441 HANDLE token = NULL;
1442 SID_NAME_USE user_type;
1443 unsigned char *buf = NULL;
1444 DWORD blen = 0;
1445 TOKEN_USER user_token;
1446 TOKEN_PRIMARY_GROUP group_token;
1447 BOOL result;
1449 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1450 if (result)
1452 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1453 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1455 buf = xmalloc (blen);
1456 result = get_token_information (token, TokenUser,
1457 (LPVOID)buf, blen, &needed);
1458 if (result)
1460 memcpy (&user_token, buf, sizeof (user_token));
1461 result = lookup_account_sid (NULL, user_token.User.Sid,
1462 uname, &ulength,
1463 domain, &dlength, &user_type);
1466 else
1467 result = FALSE;
1469 if (result)
1471 strcpy (dflt_passwd.pw_name, uname);
1472 /* Determine a reasonable uid value. */
1473 if (xstrcasecmp ("administrator", uname) == 0)
1475 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1476 dflt_passwd.pw_gid = 513; /* well-known None gid */
1478 else
1480 /* Use the last sub-authority value of the RID, the relative
1481 portion of the SID, as user/group ID. */
1482 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1484 /* Get group id and name. */
1485 result = get_token_information (token, TokenPrimaryGroup,
1486 (LPVOID)buf, blen, &needed);
1487 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1489 buf = xrealloc (buf, blen = needed);
1490 result = get_token_information (token, TokenPrimaryGroup,
1491 (LPVOID)buf, blen, &needed);
1493 if (result)
1495 memcpy (&group_token, buf, sizeof (group_token));
1496 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1497 dlength = sizeof (domain);
1498 /* If we can get at the real Primary Group name, use that.
1499 Otherwise, the default group name was already set to
1500 "None" in globals_of_w32. */
1501 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1502 gname, &glength, NULL, &dlength,
1503 &user_type))
1504 strcpy (dflt_group_name, gname);
1506 else
1507 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1510 /* If security calls are not supported (presumably because we
1511 are running under Windows 9X), fallback to this: */
1512 else if (GetUserName (uname, &ulength))
1514 strcpy (dflt_passwd.pw_name, uname);
1515 if (xstrcasecmp ("administrator", uname) == 0)
1516 dflt_passwd.pw_uid = 0;
1517 else
1518 dflt_passwd.pw_uid = 123;
1519 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1521 else
1523 strcpy (dflt_passwd.pw_name, "unknown");
1524 dflt_passwd.pw_uid = 123;
1525 dflt_passwd.pw_gid = 123;
1527 dflt_group.gr_gid = dflt_passwd.pw_gid;
1529 /* Ensure HOME and SHELL are defined. */
1530 if (getenv ("HOME") == NULL)
1531 emacs_abort ();
1532 if (getenv ("SHELL") == NULL)
1533 emacs_abort ();
1535 /* Set dir and shell from environment variables. */
1536 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1537 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1539 xfree (buf);
1540 if (token)
1541 CloseHandle (token);
1545 random (void)
1547 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1548 return ((rand () << 15) | rand ());
1551 void
1552 srandom (int seed)
1554 srand (seed);
1557 /* Current codepage for encoding file names. */
1558 static int file_name_codepage;
1560 /* Return the maximum length in bytes of a multibyte character
1561 sequence encoded in the current ANSI codepage. This is required to
1562 correctly walk the encoded file names one character at a time. */
1563 static int
1564 max_filename_mbslen (void)
1566 /* A simple cache to avoid calling GetCPInfo every time we need to
1567 normalize a file name. The file-name encoding is not supposed to
1568 be changed too frequently, if ever. */
1569 static Lisp_Object last_file_name_encoding;
1570 static int last_max_mbslen;
1571 Lisp_Object current_encoding;
1573 current_encoding = Vfile_name_coding_system;
1574 if (NILP (current_encoding))
1575 current_encoding = Vdefault_file_name_coding_system;
1577 if (!EQ (last_file_name_encoding, current_encoding))
1579 CPINFO cp_info;
1581 last_file_name_encoding = current_encoding;
1582 /* Default to the current ANSI codepage. */
1583 file_name_codepage = w32_ansi_code_page;
1584 if (!NILP (current_encoding))
1586 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1587 char *cp = NULL, *end;
1588 int cpnum;
1590 if (strncmp (cpname, "cp", 2) == 0)
1591 cp = cpname + 2;
1592 else if (strncmp (cpname, "windows-", 8) == 0)
1593 cp = cpname + 8;
1595 if (cp)
1597 end = cp;
1598 cpnum = strtol (cp, &end, 10);
1599 if (cpnum && *end == '\0' && end - cp >= 2)
1600 file_name_codepage = cpnum;
1604 if (!file_name_codepage)
1605 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1607 if (!GetCPInfo (file_name_codepage, &cp_info))
1609 file_name_codepage = CP_ACP;
1610 if (!GetCPInfo (file_name_codepage, &cp_info))
1611 emacs_abort ();
1613 last_max_mbslen = cp_info.MaxCharSize;
1616 return last_max_mbslen;
1619 /* Normalize filename by converting all path separators to
1620 the specified separator. Also conditionally convert upper
1621 case path name components to lower case. */
1623 static void
1624 normalize_filename (register char *fp, char path_sep, int multibyte)
1626 char sep;
1627 char *elem, *p2;
1628 int dbcs_p = max_filename_mbslen () > 1;
1630 /* Multibyte file names are in the Emacs internal representation, so
1631 we can traverse them by bytes with no problems. */
1632 if (multibyte)
1633 dbcs_p = 0;
1635 /* Always lower-case drive letters a-z, even if the filesystem
1636 preserves case in filenames.
1637 This is so filenames can be compared by string comparison
1638 functions that are case-sensitive. Even case-preserving filesystems
1639 do not distinguish case in drive letters. */
1640 if (dbcs_p)
1641 p2 = CharNextExA (file_name_codepage, fp, 0);
1642 else
1643 p2 = fp + 1;
1645 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
1647 *fp += 'a' - 'A';
1648 fp += 2;
1651 if (multibyte || NILP (Vw32_downcase_file_names))
1653 while (*fp)
1655 if (*fp == '/' || *fp == '\\')
1656 *fp = path_sep;
1657 if (!dbcs_p)
1658 fp++;
1659 else
1660 fp = CharNextExA (file_name_codepage, fp, 0);
1662 return;
1665 sep = path_sep; /* convert to this path separator */
1666 elem = fp; /* start of current path element */
1668 do {
1669 if (*fp >= 'a' && *fp <= 'z')
1670 elem = 0; /* don't convert this element */
1672 if (*fp == 0 || *fp == ':')
1674 sep = *fp; /* restore current separator (or 0) */
1675 *fp = '/'; /* after conversion of this element */
1678 if (*fp == '/' || *fp == '\\')
1680 if (elem && elem != fp)
1682 *fp = 0; /* temporary end of string */
1683 _mbslwr (elem); /* while we convert to lower case */
1685 *fp = sep; /* convert (or restore) path separator */
1686 elem = fp + 1; /* next element starts after separator */
1687 sep = path_sep;
1689 if (*fp)
1691 if (!dbcs_p)
1692 fp++;
1693 else
1694 fp = CharNextExA (file_name_codepage, fp, 0);
1696 } while (*fp);
1699 /* Destructively turn backslashes into slashes. MULTIBYTE non-zero
1700 means the file name is a multibyte string in Emacs's internal
1701 representation. */
1702 void
1703 dostounix_filename (register char *p, int multibyte)
1705 normalize_filename (p, '/', multibyte);
1708 /* Destructively turn slashes into backslashes. */
1709 void
1710 unixtodos_filename (register char *p)
1712 normalize_filename (p, '\\', 0);
1715 /* Remove all CR's that are followed by a LF.
1716 (From msdos.c...probably should figure out a way to share it,
1717 although this code isn't going to ever change.) */
1718 static int
1719 crlf_to_lf (register int n, register unsigned char *buf)
1721 unsigned char *np = buf;
1722 unsigned char *startp = buf;
1723 unsigned char *endp = buf + n;
1725 if (n == 0)
1726 return n;
1727 while (buf < endp - 1)
1729 if (*buf == 0x0d)
1731 if (*(++buf) != 0x0a)
1732 *np++ = 0x0d;
1734 else
1735 *np++ = *buf++;
1737 if (buf < endp)
1738 *np++ = *buf++;
1739 return np - startp;
1742 /* Parse the root part of file name, if present. Return length and
1743 optionally store pointer to char after root. */
1744 static int
1745 parse_root (char * name, char ** pPath)
1747 char * start = name;
1749 if (name == NULL)
1750 return 0;
1752 /* find the root name of the volume if given */
1753 if (isalpha (name[0]) && name[1] == ':')
1755 /* skip past drive specifier */
1756 name += 2;
1757 if (IS_DIRECTORY_SEP (name[0]))
1758 name++;
1760 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1762 int slashes = 2;
1763 int dbcs_p = max_filename_mbslen () > 1;
1765 name += 2;
1768 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1769 break;
1770 if (dbcs_p)
1771 name = CharNextExA (file_name_codepage, name, 0);
1772 else
1773 name++;
1775 while ( *name );
1776 if (IS_DIRECTORY_SEP (name[0]))
1777 name++;
1780 if (pPath)
1781 *pPath = name;
1783 return name - start;
1786 /* Get long base name for name; name is assumed to be absolute. */
1787 static int
1788 get_long_basename (char * name, char * buf, int size)
1790 WIN32_FIND_DATA find_data;
1791 HANDLE dir_handle;
1792 int len = 0;
1794 /* must be valid filename, no wild cards or other invalid characters */
1795 if (_mbspbrk (name, "*?|<>\""))
1796 return 0;
1798 dir_handle = FindFirstFile (name, &find_data);
1799 if (dir_handle != INVALID_HANDLE_VALUE)
1801 if ((len = strlen (find_data.cFileName)) < size)
1802 memcpy (buf, find_data.cFileName, len + 1);
1803 else
1804 len = 0;
1805 FindClose (dir_handle);
1807 return len;
1810 /* Get long name for file, if possible (assumed to be absolute). */
1811 BOOL
1812 w32_get_long_filename (char * name, char * buf, int size)
1814 char * o = buf;
1815 char * p;
1816 char * q;
1817 char full[ MAX_PATH ];
1818 int len;
1820 len = strlen (name);
1821 if (len >= MAX_PATH)
1822 return FALSE;
1824 /* Use local copy for destructive modification. */
1825 memcpy (full, name, len+1);
1826 unixtodos_filename (full);
1828 /* Copy root part verbatim. */
1829 len = parse_root (full, &p);
1830 memcpy (o, full, len);
1831 o += len;
1832 *o = '\0';
1833 size -= len;
1835 while (p != NULL && *p)
1837 q = p;
1838 p = _mbschr (q, '\\');
1839 if (p) *p = '\0';
1840 len = get_long_basename (full, o, size);
1841 if (len > 0)
1843 o += len;
1844 size -= len;
1845 if (p != NULL)
1847 *p++ = '\\';
1848 if (size < 2)
1849 return FALSE;
1850 *o++ = '\\';
1851 size--;
1852 *o = '\0';
1855 else
1856 return FALSE;
1859 return TRUE;
1862 static int
1863 is_unc_volume (const char *filename)
1865 const char *ptr = filename;
1867 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1868 return 0;
1870 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1871 return 0;
1873 return 1;
1876 /* Emulate the Posix unsetenv. */
1878 unsetenv (const char *name)
1880 char *var;
1881 size_t name_len;
1882 int retval;
1884 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
1886 errno = EINVAL;
1887 return -1;
1889 name_len = strlen (name);
1890 /* MS docs says an environment variable cannot be longer than 32K. */
1891 if (name_len > 32767)
1893 errno = ENOMEM;
1894 return 0;
1896 /* It is safe to use 'alloca' with 32K size, since the stack is at
1897 least 2MB, and we set it to 8MB in the link command line. */
1898 var = alloca (name_len + 2);
1899 strncpy (var, name, name_len);
1900 var[name_len++] = '=';
1901 var[name_len] = '\0';
1902 return _putenv (var);
1905 /* MS _putenv doesn't support removing a variable when the argument
1906 does not include the '=' character, so we fix that here. */
1908 sys_putenv (char *str)
1910 const char *const name_end = strchr (str, '=');
1912 if (name_end == NULL)
1914 /* Remove the variable from the environment. */
1915 return unsetenv (str);
1918 return _putenv (str);
1921 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1923 LPBYTE
1924 w32_get_resource (char *key, LPDWORD lpdwtype)
1926 LPBYTE lpvalue;
1927 HKEY hrootkey = NULL;
1928 DWORD cbData;
1930 /* Check both the current user and the local machine to see if
1931 we have any resources. */
1933 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1935 lpvalue = NULL;
1937 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1938 && (lpvalue = xmalloc (cbData)) != NULL
1939 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1941 RegCloseKey (hrootkey);
1942 return (lpvalue);
1945 xfree (lpvalue);
1947 RegCloseKey (hrootkey);
1950 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1952 lpvalue = NULL;
1954 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1955 && (lpvalue = xmalloc (cbData)) != NULL
1956 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1958 RegCloseKey (hrootkey);
1959 return (lpvalue);
1962 xfree (lpvalue);
1964 RegCloseKey (hrootkey);
1967 return (NULL);
1970 char *get_emacs_configuration (void);
1972 void
1973 init_environment (char ** argv)
1975 static const char * const tempdirs[] = {
1976 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1979 int i;
1981 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1983 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1984 temporary files and assume "/tmp" if $TMPDIR is unset, which
1985 will break on DOS/Windows. Refuse to work if we cannot find
1986 a directory, not even "c:/", usable for that purpose. */
1987 for (i = 0; i < imax ; i++)
1989 const char *tmp = tempdirs[i];
1991 if (*tmp == '$')
1992 tmp = getenv (tmp + 1);
1993 /* Note that `access' can lie to us if the directory resides on a
1994 read-only filesystem, like CD-ROM or a write-protected floppy.
1995 The only way to be really sure is to actually create a file and
1996 see if it succeeds. But I think that's too much to ask. */
1998 /* MSVCRT's _access crashes with D_OK. */
1999 if (tmp && faccessat (AT_FDCWD, tmp, D_OK, AT_EACCESS) == 0)
2001 char * var = alloca (strlen (tmp) + 8);
2002 sprintf (var, "TMPDIR=%s", tmp);
2003 _putenv (strdup (var));
2004 break;
2007 if (i >= imax)
2008 cmd_error_internal
2009 (Fcons (Qerror,
2010 Fcons (build_string ("no usable temporary directories found!!"),
2011 Qnil)),
2012 "While setting TMPDIR: ");
2014 /* Check for environment variables and use registry settings if they
2015 don't exist. Fallback on default values where applicable. */
2017 int i;
2018 LPBYTE lpval;
2019 DWORD dwType;
2020 char locale_name[32];
2021 char default_home[MAX_PATH];
2022 int appdata = 0;
2024 static const struct env_entry
2026 char * name;
2027 char * def_value;
2028 } dflt_envvars[] =
2030 /* If the default value is NULL, we will use the value from the
2031 outside environment or the Registry, but will not push the
2032 variable into the Emacs environment if it is defined neither
2033 in the Registry nor in the outside environment. */
2034 {"HOME", "C:/"},
2035 {"PRELOAD_WINSOCK", NULL},
2036 {"emacs_dir", "C:/emacs"},
2037 {"EMACSLOADPATH", NULL},
2038 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2039 {"EMACSDATA", NULL},
2040 {"EMACSPATH", NULL},
2041 {"INFOPATH", NULL},
2042 {"EMACSDOC", NULL},
2043 {"TERM", "cmd"},
2044 {"LANG", NULL},
2047 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
2049 /* We need to copy dflt_envvars[] and work on the copy because we
2050 don't want the dumped Emacs to inherit the values of
2051 environment variables we saw during dumping (which could be on
2052 a different system). The defaults above must be left intact. */
2053 struct env_entry env_vars[N_ENV_VARS];
2055 for (i = 0; i < N_ENV_VARS; i++)
2056 env_vars[i] = dflt_envvars[i];
2058 /* For backwards compatibility, check if a .emacs file exists in C:/
2059 If not, then we can try to default to the appdata directory under the
2060 user's profile, which is more likely to be writable. */
2061 if (!check_existing ("C:/.emacs"))
2063 HRESULT profile_result;
2064 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2065 of Windows 95 and NT4 that have not been updated to include
2066 MSIE 5. */
2067 ShGetFolderPath_fn get_folder_path;
2068 get_folder_path = (ShGetFolderPath_fn)
2069 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2071 if (get_folder_path != NULL)
2073 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2074 0, default_home);
2076 /* If we can't get the appdata dir, revert to old behavior. */
2077 if (profile_result == S_OK)
2079 env_vars[0].def_value = default_home;
2080 appdata = 1;
2085 /* Get default locale info and use it for LANG. */
2086 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2087 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2088 locale_name, sizeof (locale_name)))
2090 for (i = 0; i < N_ENV_VARS; i++)
2092 if (strcmp (env_vars[i].name, "LANG") == 0)
2094 env_vars[i].def_value = locale_name;
2095 break;
2100 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2102 /* Treat emacs_dir specially: set it unconditionally based on our
2103 location. */
2105 char *p;
2106 char modname[MAX_PATH];
2108 if (!GetModuleFileName (NULL, modname, MAX_PATH))
2109 emacs_abort ();
2110 if ((p = _mbsrchr (modname, '\\')) == NULL)
2111 emacs_abort ();
2112 *p = 0;
2114 if ((p = _mbsrchr (modname, '\\'))
2115 /* From bin means installed Emacs, from src means uninstalled. */
2116 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2118 char buf[SET_ENV_BUF_SIZE];
2119 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2121 *p = 0;
2122 for (p = modname; *p; p = CharNext (p))
2123 if (*p == '\\') *p = '/';
2125 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2126 _putenv (strdup (buf));
2127 /* If we are running from the Posix-like build tree, define
2128 SHELL to point to our own cmdproxy. The loop below will
2129 then disregard PATH_EXEC and the default value. */
2130 if (within_build_tree)
2132 _snprintf (buf, sizeof (buf) - 1,
2133 "SHELL=%s/nt/cmdproxy.exe", modname);
2134 _putenv (strdup (buf));
2137 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
2139 /* FIXME: should use substring of get_emacs_configuration ().
2140 But I don't think the Windows build supports alpha, mips etc
2141 anymore, so have taken the easy option for now. */
2142 else if (p && (xstrcasecmp (p, "\\i386") == 0
2143 || xstrcasecmp (p, "\\AMD64") == 0))
2145 *p = 0;
2146 p = _mbsrchr (modname, '\\');
2147 if (p != NULL)
2149 *p = 0;
2150 p = _mbsrchr (modname, '\\');
2151 if (p && xstrcasecmp (p, "\\src") == 0)
2153 char buf[SET_ENV_BUF_SIZE];
2155 *p = 0;
2156 for (p = modname; *p; p = CharNext (p))
2157 if (*p == '\\') *p = '/';
2159 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2160 _putenv (strdup (buf));
2166 for (i = 0; i < N_ENV_VARS; i++)
2168 if (!getenv (env_vars[i].name))
2170 int dont_free = 0;
2171 char bufc[SET_ENV_BUF_SIZE];
2173 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2174 /* Also ignore empty environment variables. */
2175 || *lpval == 0)
2177 xfree (lpval);
2178 dont_free = 1;
2179 if (strcmp (env_vars[i].name, "SHELL") == 0)
2181 /* Look for cmdproxy.exe in every directory in
2182 PATH_EXEC. FIXME: This does not find cmdproxy
2183 in nt/ when we run uninstalled. */
2184 char fname[MAX_PATH];
2185 const char *pstart = PATH_EXEC, *pend;
2187 do {
2188 pend = _mbschr (pstart, ';');
2189 if (!pend)
2190 pend = pstart + strlen (pstart);
2191 /* Be defensive against series of ;;; characters. */
2192 if (pend > pstart)
2194 strncpy (fname, pstart, pend - pstart);
2195 fname[pend - pstart] = '/';
2196 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2197 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2198 sizeof (bufc));
2199 if (check_existing (bufc))
2201 lpval = bufc;
2202 dwType = REG_SZ;
2203 break;
2206 if (*pend)
2207 pstart = pend + 1;
2208 else
2209 pstart = pend;
2210 if (!*pstart)
2212 /* If not found in any directory, use the
2213 default as the last resort. */
2214 lpval = env_vars[i].def_value;
2215 dwType = REG_EXPAND_SZ;
2217 } while (*pstart);
2219 else
2221 lpval = env_vars[i].def_value;
2222 dwType = REG_EXPAND_SZ;
2224 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2225 Vdelayed_warnings_list
2226 = Fcons (listn (CONSTYPE_HEAP, 2,
2227 intern ("initialization"),
2228 build_string ("Setting HOME to C:\\ by default is deprecated")),
2229 Vdelayed_warnings_list);
2232 if (lpval)
2234 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2236 if (dwType == REG_EXPAND_SZ)
2237 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2238 else if (dwType == REG_SZ)
2239 strcpy (buf1, lpval);
2240 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2242 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2243 buf1);
2244 _putenv (strdup (buf2));
2247 if (!dont_free)
2248 xfree (lpval);
2254 /* Rebuild system configuration to reflect invoking system. */
2255 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2257 /* Another special case: on NT, the PATH variable is actually named
2258 "Path" although cmd.exe (perhaps NT itself) arranges for
2259 environment variable lookup and setting to be case insensitive.
2260 However, Emacs assumes a fully case sensitive environment, so we
2261 need to change "Path" to "PATH" to match the expectations of
2262 various elisp packages. We do this by the sneaky method of
2263 modifying the string in the C runtime environ entry.
2265 The same applies to COMSPEC. */
2267 char ** envp;
2269 for (envp = environ; *envp; envp++)
2270 if (_strnicmp (*envp, "PATH=", 5) == 0)
2271 memcpy (*envp, "PATH=", 5);
2272 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
2273 memcpy (*envp, "COMSPEC=", 8);
2276 /* Remember the initial working directory for getcwd. */
2277 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2278 Does it matter anywhere in Emacs? */
2279 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
2280 emacs_abort ();
2283 static char modname[MAX_PATH];
2285 if (!GetModuleFileName (NULL, modname, MAX_PATH))
2286 emacs_abort ();
2287 argv[0] = modname;
2290 /* Determine if there is a middle mouse button, to allow parse_button
2291 to decide whether right mouse events should be mouse-2 or
2292 mouse-3. */
2293 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2295 init_user_info ();
2298 /* Called from expand-file-name when default-directory is not a string. */
2300 char *
2301 emacs_root_dir (void)
2303 static char root_dir[FILENAME_MAX];
2304 const char *p;
2306 p = getenv ("emacs_dir");
2307 if (p == NULL)
2308 emacs_abort ();
2309 strcpy (root_dir, p);
2310 root_dir[parse_root (root_dir, NULL)] = '\0';
2311 dostounix_filename (root_dir, 0);
2312 return root_dir;
2315 /* We don't have scripts to automatically determine the system configuration
2316 for Emacs before it's compiled, and we don't want to have to make the
2317 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
2318 routine. */
2320 char *
2321 get_emacs_configuration (void)
2323 char *arch, *oem, *os;
2324 int build_num;
2325 static char configuration_buffer[32];
2327 /* Determine the processor type. */
2328 switch (get_processor_type ())
2331 #ifdef PROCESSOR_INTEL_386
2332 case PROCESSOR_INTEL_386:
2333 case PROCESSOR_INTEL_486:
2334 case PROCESSOR_INTEL_PENTIUM:
2335 #ifdef _WIN64
2336 arch = "amd64";
2337 #else
2338 arch = "i386";
2339 #endif
2340 break;
2341 #endif
2342 #ifdef PROCESSOR_AMD_X8664
2343 case PROCESSOR_AMD_X8664:
2344 arch = "amd64";
2345 break;
2346 #endif
2348 #ifdef PROCESSOR_MIPS_R2000
2349 case PROCESSOR_MIPS_R2000:
2350 case PROCESSOR_MIPS_R3000:
2351 case PROCESSOR_MIPS_R4000:
2352 arch = "mips";
2353 break;
2354 #endif
2356 #ifdef PROCESSOR_ALPHA_21064
2357 case PROCESSOR_ALPHA_21064:
2358 arch = "alpha";
2359 break;
2360 #endif
2362 default:
2363 arch = "unknown";
2364 break;
2367 /* Use the OEM field to reflect the compiler/library combination. */
2368 #ifdef _MSC_VER
2369 #define COMPILER_NAME "msvc"
2370 #else
2371 #ifdef __GNUC__
2372 #define COMPILER_NAME "mingw"
2373 #else
2374 #define COMPILER_NAME "unknown"
2375 #endif
2376 #endif
2377 oem = COMPILER_NAME;
2379 switch (osinfo_cache.dwPlatformId) {
2380 case VER_PLATFORM_WIN32_NT:
2381 os = "nt";
2382 build_num = osinfo_cache.dwBuildNumber;
2383 break;
2384 case VER_PLATFORM_WIN32_WINDOWS:
2385 if (osinfo_cache.dwMinorVersion == 0) {
2386 os = "windows95";
2387 } else {
2388 os = "windows98";
2390 build_num = LOWORD (osinfo_cache.dwBuildNumber);
2391 break;
2392 case VER_PLATFORM_WIN32s:
2393 /* Not supported, should not happen. */
2394 os = "windows32s";
2395 build_num = LOWORD (osinfo_cache.dwBuildNumber);
2396 break;
2397 default:
2398 os = "unknown";
2399 build_num = 0;
2400 break;
2403 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
2404 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
2405 get_w32_major_version (), get_w32_minor_version (), build_num);
2406 } else {
2407 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
2410 return configuration_buffer;
2413 char *
2414 get_emacs_configuration_options (void)
2416 static char *options_buffer;
2417 char cv[32]; /* Enough for COMPILER_VERSION. */
2418 char *options[] = {
2419 cv, /* To be filled later. */
2420 #ifdef EMACSDEBUG
2421 " --no-opt",
2422 #endif
2423 #ifdef ENABLE_CHECKING
2424 " --enable-checking",
2425 #endif
2426 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
2427 with a starting space to save work here. */
2428 #ifdef USER_CFLAGS
2429 " --cflags", USER_CFLAGS,
2430 #endif
2431 #ifdef USER_LDFLAGS
2432 " --ldflags", USER_LDFLAGS,
2433 #endif
2434 NULL
2436 size_t size = 0;
2437 int i;
2439 /* Work out the effective configure options for this build. */
2440 #ifdef _MSC_VER
2441 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
2442 #else
2443 #ifdef __GNUC__
2444 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
2445 #else
2446 #define COMPILER_VERSION ""
2447 #endif
2448 #endif
2450 if (_snprintf (cv, sizeof (cv) - 1, COMPILER_VERSION) < 0)
2451 return "Error: not enough space for compiler version";
2452 cv[sizeof (cv) - 1] = '\0';
2454 for (i = 0; options[i]; i++)
2455 size += strlen (options[i]);
2457 options_buffer = xmalloc (size + 1);
2458 options_buffer[0] = '\0';
2460 for (i = 0; options[i]; i++)
2461 strcat (options_buffer, options[i]);
2463 return options_buffer;
2467 #include <sys/timeb.h>
2469 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2471 gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
2473 struct _timeb tb;
2474 _ftime (&tb);
2476 tv->tv_sec = tb.time;
2477 tv->tv_usec = tb.millitm * 1000L;
2478 /* Implementation note: _ftime sometimes doesn't update the dstflag
2479 according to the new timezone when the system timezone is
2480 changed. We could fix that by using GetSystemTime and
2481 GetTimeZoneInformation, but that doesn't seem necessary, since
2482 Emacs always calls gettimeofday with the 2nd argument NULL (see
2483 current_emacs_time). */
2484 if (tz)
2486 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2487 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2489 return 0;
2492 /* Emulate fdutimens. */
2494 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2495 TIMESPEC[0] and TIMESPEC[1], respectively.
2496 FD must be either negative -- in which case it is ignored --
2497 or a file descriptor that is open on FILE.
2498 If FD is nonnegative, then FILE can be NULL, which means
2499 use just futimes instead of utimes.
2500 If TIMESPEC is null, FAIL.
2501 Return 0 on success, -1 (setting errno) on failure. */
2504 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2506 if (!timespec)
2508 errno = ENOSYS;
2509 return -1;
2511 if (fd < 0 && !file)
2513 errno = EBADF;
2514 return -1;
2516 /* _futime's prototype defines 2nd arg as having the type 'struct
2517 _utimbuf', while utime needs to accept 'struct utimbuf' for
2518 compatibility with Posix. So we need to use 2 different (but
2519 equivalent) types to avoid compiler warnings, sigh. */
2520 if (fd >= 0)
2522 struct _utimbuf _ut;
2524 _ut.actime = timespec[0].tv_sec;
2525 _ut.modtime = timespec[1].tv_sec;
2526 return _futime (fd, &_ut);
2528 else
2530 struct utimbuf ut;
2532 ut.actime = timespec[0].tv_sec;
2533 ut.modtime = timespec[1].tv_sec;
2534 /* Call 'utime', which is implemented below, not the MS library
2535 function, which fails on directories. */
2536 return utime (file, &ut);
2541 /* ------------------------------------------------------------------------- */
2542 /* IO support and wrapper functions for the Windows API. */
2543 /* ------------------------------------------------------------------------- */
2545 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2546 on network directories, so we handle that case here.
2547 (Ulrich Leodolter, 1/11/95). */
2548 char *
2549 sys_ctime (const time_t *t)
2551 char *str = (char *) ctime (t);
2552 return (str ? str : "Sun Jan 01 00:00:00 1970");
2555 /* Emulate sleep...we could have done this with a define, but that
2556 would necessitate including windows.h in the files that used it.
2557 This is much easier. */
2558 void
2559 sys_sleep (int seconds)
2561 Sleep (seconds * 1000);
2564 /* Internal MSVC functions for low-level descriptor munging */
2565 extern int __cdecl _set_osfhnd (int fd, long h);
2566 extern int __cdecl _free_osfhnd (int fd);
2568 /* parallel array of private info on file handles */
2569 filedesc fd_info [ MAXDESC ];
2571 typedef struct volume_info_data {
2572 struct volume_info_data * next;
2574 /* time when info was obtained */
2575 DWORD timestamp;
2577 /* actual volume info */
2578 char * root_dir;
2579 DWORD serialnum;
2580 DWORD maxcomp;
2581 DWORD flags;
2582 char * name;
2583 char * type;
2584 } volume_info_data;
2586 /* Global referenced by various functions. */
2587 static volume_info_data volume_info;
2589 /* Vector to indicate which drives are local and fixed (for which cached
2590 data never expires). */
2591 static BOOL fixed_drives[26];
2593 /* Consider cached volume information to be stale if older than 10s,
2594 at least for non-local drives. Info for fixed drives is never stale. */
2595 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2596 #define VOLINFO_STILL_VALID( root_dir, info ) \
2597 ( ( isalpha (root_dir[0]) && \
2598 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2599 || GetTickCount () - info->timestamp < 10000 )
2601 /* Cache support functions. */
2603 /* Simple linked list with linear search is sufficient. */
2604 static volume_info_data *volume_cache = NULL;
2606 static volume_info_data *
2607 lookup_volume_info (char * root_dir)
2609 volume_info_data * info;
2611 for (info = volume_cache; info; info = info->next)
2612 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2613 break;
2614 return info;
2617 static void
2618 add_volume_info (char * root_dir, volume_info_data * info)
2620 info->root_dir = xstrdup (root_dir);
2621 info->next = volume_cache;
2622 volume_cache = info;
2626 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2627 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2628 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2629 static volume_info_data *
2630 GetCachedVolumeInformation (char * root_dir)
2632 volume_info_data * info;
2633 char default_root[ MAX_PATH ];
2635 /* NULL for root_dir means use root from current directory. */
2636 if (root_dir == NULL)
2638 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
2639 return NULL;
2640 parse_root (default_root, &root_dir);
2641 *root_dir = 0;
2642 root_dir = default_root;
2645 /* Local fixed drives can be cached permanently. Removable drives
2646 cannot be cached permanently, since the volume name and serial
2647 number (if nothing else) can change. Remote drives should be
2648 treated as if they are removable, since there is no sure way to
2649 tell whether they are or not. Also, the UNC association of drive
2650 letters mapped to remote volumes can be changed at any time (even
2651 by other processes) without notice.
2653 As a compromise, so we can benefit from caching info for remote
2654 volumes, we use a simple expiry mechanism to invalidate cache
2655 entries that are more than ten seconds old. */
2657 #if 0
2658 /* No point doing this, because WNetGetConnection is even slower than
2659 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2660 GetDriveType is about the only call of this type which does not
2661 involve network access, and so is extremely quick). */
2663 /* Map drive letter to UNC if remote. */
2664 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2666 char remote_name[ 256 ];
2667 char drive[3] = { root_dir[0], ':' };
2669 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2670 == NO_ERROR)
2671 /* do something */ ;
2673 #endif
2675 info = lookup_volume_info (root_dir);
2677 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2679 char name[ 256 ];
2680 DWORD serialnum;
2681 DWORD maxcomp;
2682 DWORD flags;
2683 char type[ 256 ];
2685 /* Info is not cached, or is stale. */
2686 if (!GetVolumeInformation (root_dir,
2687 name, sizeof (name),
2688 &serialnum,
2689 &maxcomp,
2690 &flags,
2691 type, sizeof (type)))
2692 return NULL;
2694 /* Cache the volume information for future use, overwriting existing
2695 entry if present. */
2696 if (info == NULL)
2698 info = xmalloc (sizeof (volume_info_data));
2699 add_volume_info (root_dir, info);
2701 else
2703 xfree (info->name);
2704 xfree (info->type);
2707 info->name = xstrdup (name);
2708 info->serialnum = serialnum;
2709 info->maxcomp = maxcomp;
2710 info->flags = flags;
2711 info->type = xstrdup (type);
2712 info->timestamp = GetTickCount ();
2715 return info;
2718 /* Get information on the volume where NAME is held; set path pointer to
2719 start of pathname in NAME (past UNC header\volume header if present),
2720 if pPath is non-NULL.
2722 Note: if NAME includes symlinks, the information is for the volume
2723 of the symlink, not of its target. That's because, even though
2724 GetVolumeInformation returns information about the symlink target
2725 of its argument, we only pass the root directory to
2726 GetVolumeInformation, not the full NAME. */
2727 static int
2728 get_volume_info (const char * name, const char ** pPath)
2730 char temp[MAX_PATH];
2731 char *rootname = NULL; /* default to current volume */
2732 volume_info_data * info;
2734 if (name == NULL)
2735 return FALSE;
2737 /* Find the root name of the volume if given. */
2738 if (isalpha (name[0]) && name[1] == ':')
2740 rootname = temp;
2741 temp[0] = *name++;
2742 temp[1] = *name++;
2743 temp[2] = '\\';
2744 temp[3] = 0;
2746 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2748 char *str = temp;
2749 int slashes = 4;
2750 int dbcs_p = max_filename_mbslen () > 1;
2752 rootname = temp;
2755 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2756 break;
2757 if (!dbcs_p)
2758 *str++ = *name++;
2759 else
2761 const char *p = name;
2763 name = CharNextExA (file_name_codepage, name, 0);
2764 memcpy (str, p, name - p);
2765 str += name - p;
2768 while ( *name );
2770 *str++ = '\\';
2771 *str = 0;
2774 if (pPath)
2775 *pPath = name;
2777 info = GetCachedVolumeInformation (rootname);
2778 if (info != NULL)
2780 /* Set global referenced by other functions. */
2781 volume_info = *info;
2782 return TRUE;
2784 return FALSE;
2787 /* Determine if volume is FAT format (ie. only supports short 8.3
2788 names); also set path pointer to start of pathname in name, if
2789 pPath is non-NULL. */
2790 static int
2791 is_fat_volume (const char * name, const char ** pPath)
2793 if (get_volume_info (name, pPath))
2794 return (volume_info.maxcomp == 12);
2795 return FALSE;
2798 /* Map filename to a valid 8.3 name if necessary.
2799 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2800 const char *
2801 map_w32_filename (const char * name, const char ** pPath)
2803 static char shortname[MAX_PATH];
2804 char * str = shortname;
2805 char c;
2806 char * path;
2807 const char * save_name = name;
2809 if (strlen (name) >= MAX_PATH)
2811 /* Return a filename which will cause callers to fail. */
2812 strcpy (shortname, "?");
2813 return shortname;
2816 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2818 register int left = 8; /* maximum number of chars in part */
2819 register int extn = 0; /* extension added? */
2820 register int dots = 2; /* maximum number of dots allowed */
2822 while (name < path)
2823 *str++ = *name++; /* skip past UNC header */
2825 while ((c = *name++))
2827 switch ( c )
2829 case ':':
2830 case '\\':
2831 case '/':
2832 *str++ = (c == ':' ? ':' : '\\');
2833 extn = 0; /* reset extension flags */
2834 dots = 2; /* max 2 dots */
2835 left = 8; /* max length 8 for main part */
2836 break;
2837 case '.':
2838 if ( dots )
2840 /* Convert path components of the form .xxx to _xxx,
2841 but leave . and .. as they are. This allows .emacs
2842 to be read as _emacs, for example. */
2844 if (! *name ||
2845 *name == '.' ||
2846 IS_DIRECTORY_SEP (*name))
2848 *str++ = '.';
2849 dots--;
2851 else
2853 *str++ = '_';
2854 left--;
2855 dots = 0;
2858 else if ( !extn )
2860 *str++ = '.';
2861 extn = 1; /* we've got an extension */
2862 left = 3; /* 3 chars in extension */
2864 else
2866 /* any embedded dots after the first are converted to _ */
2867 *str++ = '_';
2869 break;
2870 case '~':
2871 case '#': /* don't lose these, they're important */
2872 if ( ! left )
2873 str[-1] = c; /* replace last character of part */
2874 /* FALLTHRU */
2875 default:
2876 if ( left )
2878 *str++ = tolower (c); /* map to lower case (looks nicer) */
2879 left--;
2880 dots = 0; /* started a path component */
2882 break;
2885 *str = '\0';
2887 else
2889 strcpy (shortname, name);
2890 unixtodos_filename (shortname);
2893 if (pPath)
2894 *pPath = shortname + (path - save_name);
2896 return shortname;
2899 static int
2900 is_exec (const char * name)
2902 char * p = strrchr (name, '.');
2903 return
2904 (p != NULL
2905 && (xstrcasecmp (p, ".exe") == 0 ||
2906 xstrcasecmp (p, ".com") == 0 ||
2907 xstrcasecmp (p, ".bat") == 0 ||
2908 xstrcasecmp (p, ".cmd") == 0));
2911 /* Emulate the Unix directory procedures opendir, closedir,
2912 and readdir. We can't use the procedures supplied in sysdep.c,
2913 so we provide them here. */
2915 struct dirent dir_static; /* simulated directory contents */
2916 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2917 static int dir_is_fat;
2918 static char dir_pathname[MAXPATHLEN+1];
2919 static WIN32_FIND_DATA dir_find_data;
2921 /* Support shares on a network resource as subdirectories of a read-only
2922 root directory. */
2923 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2924 static HANDLE open_unc_volume (const char *);
2925 static char *read_unc_volume (HANDLE, char *, int);
2926 static void close_unc_volume (HANDLE);
2928 DIR *
2929 opendir (const char *filename)
2931 DIR *dirp;
2933 /* Opening is done by FindFirstFile. However, a read is inherent to
2934 this operation, so we defer the open until read time. */
2936 if (dir_find_handle != INVALID_HANDLE_VALUE)
2937 return NULL;
2938 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2939 return NULL;
2941 /* Note: We don't support traversal of UNC volumes via symlinks.
2942 Doing so would mean punishing 99.99% of use cases by resolving
2943 all the possible symlinks in FILENAME, recursively. */
2944 if (is_unc_volume (filename))
2946 wnet_enum_handle = open_unc_volume (filename);
2947 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2948 return NULL;
2951 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2952 return NULL;
2954 dirp->dd_fd = 0;
2955 dirp->dd_loc = 0;
2956 dirp->dd_size = 0;
2958 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2959 dir_pathname[MAXPATHLEN] = '\0';
2960 /* Note: We don't support symlinks to file names on FAT volumes.
2961 Doing so would mean punishing 99.99% of use cases by resolving
2962 all the possible symlinks in FILENAME, recursively. */
2963 dir_is_fat = is_fat_volume (filename, NULL);
2965 return dirp;
2968 void
2969 closedir (DIR *dirp)
2971 /* If we have a find-handle open, close it. */
2972 if (dir_find_handle != INVALID_HANDLE_VALUE)
2974 FindClose (dir_find_handle);
2975 dir_find_handle = INVALID_HANDLE_VALUE;
2977 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2979 close_unc_volume (wnet_enum_handle);
2980 wnet_enum_handle = INVALID_HANDLE_VALUE;
2982 xfree ((char *) dirp);
2985 struct dirent *
2986 readdir (DIR *dirp)
2988 int downcase = !NILP (Vw32_downcase_file_names);
2990 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2992 if (!read_unc_volume (wnet_enum_handle,
2993 dir_find_data.cFileName,
2994 MAX_PATH))
2995 return NULL;
2997 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2998 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3000 char filename[MAXNAMLEN + 3];
3001 int ln;
3002 int dbcs_p = max_filename_mbslen () > 1;
3004 strcpy (filename, dir_pathname);
3005 ln = strlen (filename) - 1;
3006 if (!dbcs_p)
3008 if (!IS_DIRECTORY_SEP (filename[ln]))
3009 strcat (filename, "\\");
3011 else
3013 char *end = filename + ln + 1;
3014 char *last_char = CharPrevExA (file_name_codepage, filename, end, 0);
3016 if (!IS_DIRECTORY_SEP (*last_char))
3017 strcat (filename, "\\");
3019 strcat (filename, "*");
3021 /* Note: No need to resolve symlinks in FILENAME, because
3022 FindFirst opens the directory that is the target of a
3023 symlink. */
3024 dir_find_handle = FindFirstFile (filename, &dir_find_data);
3026 if (dir_find_handle == INVALID_HANDLE_VALUE)
3027 return NULL;
3029 else
3031 if (!FindNextFile (dir_find_handle, &dir_find_data))
3032 return NULL;
3035 /* Emacs never uses this value, so don't bother making it match
3036 value returned by stat(). */
3037 dir_static.d_ino = 1;
3039 strcpy (dir_static.d_name, dir_find_data.cFileName);
3041 /* If the file name in cFileName[] includes `?' characters, it means
3042 the original file name used characters that cannot be represented
3043 by the current ANSI codepage. To avoid total lossage, retrieve
3044 the short 8+3 alias of the long file name. */
3045 if (_mbspbrk (dir_static.d_name, "?"))
3047 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
3048 downcase = 1; /* 8+3 aliases are returned in all caps */
3050 dir_static.d_namlen = strlen (dir_static.d_name);
3051 dir_static.d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
3052 dir_static.d_namlen - dir_static.d_namlen % 4;
3054 /* If the file name in cFileName[] includes `?' characters, it means
3055 the original file name used characters that cannot be represented
3056 by the current ANSI codepage. To avoid total lossage, retrieve
3057 the short 8+3 alias of the long file name. */
3058 if (_mbspbrk (dir_find_data.cFileName, "?"))
3060 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
3061 /* 8+3 aliases are returned in all caps, which could break
3062 various alists that look at filenames' extensions. */
3063 downcase = 1;
3065 else
3066 strcpy (dir_static.d_name, dir_find_data.cFileName);
3067 dir_static.d_namlen = strlen (dir_static.d_name);
3068 if (dir_is_fat)
3069 _mbslwr (dir_static.d_name);
3070 else if (downcase)
3072 register char *p;
3073 int dbcs_p = max_filename_mbslen () > 1;
3074 for (p = dir_static.d_name; *p; )
3076 if (*p >= 'a' && *p <= 'z')
3077 break;
3078 if (dbcs_p)
3079 p = CharNextExA (file_name_codepage, p, 0);
3080 else
3081 p++;
3083 if (!*p)
3084 _mbslwr (dir_static.d_name);
3087 return &dir_static;
3090 static HANDLE
3091 open_unc_volume (const char *path)
3093 NETRESOURCE nr;
3094 HANDLE henum;
3095 int result;
3097 nr.dwScope = RESOURCE_GLOBALNET;
3098 nr.dwType = RESOURCETYPE_DISK;
3099 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3100 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
3101 nr.lpLocalName = NULL;
3102 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
3103 nr.lpComment = NULL;
3104 nr.lpProvider = NULL;
3106 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3107 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
3109 if (result == NO_ERROR)
3110 return henum;
3111 else
3112 return INVALID_HANDLE_VALUE;
3115 static char *
3116 read_unc_volume (HANDLE henum, char *readbuf, int size)
3118 DWORD count;
3119 int result;
3120 DWORD bufsize = 512;
3121 char *buffer;
3122 char *ptr;
3123 int dbcs_p = max_filename_mbslen () > 1;
3125 count = 1;
3126 buffer = alloca (bufsize);
3127 result = WNetEnumResource (henum, &count, buffer, &bufsize);
3128 if (result != NO_ERROR)
3129 return NULL;
3131 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3132 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
3133 ptr += 2;
3134 if (!dbcs_p)
3135 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
3136 else
3138 while (*ptr && !IS_DIRECTORY_SEP (*ptr))
3139 ptr = CharNextExA (file_name_codepage, ptr, 0);
3141 ptr++;
3143 strncpy (readbuf, ptr, size);
3144 return readbuf;
3147 static void
3148 close_unc_volume (HANDLE henum)
3150 if (henum != INVALID_HANDLE_VALUE)
3151 WNetCloseEnum (henum);
3154 static DWORD
3155 unc_volume_file_attributes (const char *path)
3157 HANDLE henum;
3158 DWORD attrs;
3160 henum = open_unc_volume (path);
3161 if (henum == INVALID_HANDLE_VALUE)
3162 return -1;
3164 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3166 close_unc_volume (henum);
3168 return attrs;
3171 /* Ensure a network connection is authenticated. */
3172 static void
3173 logon_network_drive (const char *path)
3175 NETRESOURCE resource;
3176 char share[MAX_PATH];
3177 int n_slashes;
3178 char drive[4];
3179 UINT drvtype;
3180 char *p;
3181 int dbcs_p;
3183 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3184 drvtype = DRIVE_REMOTE;
3185 else if (path[0] == '\0' || path[1] != ':')
3186 drvtype = GetDriveType (NULL);
3187 else
3189 drive[0] = path[0];
3190 drive[1] = ':';
3191 drive[2] = '\\';
3192 drive[3] = '\0';
3193 drvtype = GetDriveType (drive);
3196 /* Only logon to networked drives. */
3197 if (drvtype != DRIVE_REMOTE)
3198 return;
3200 n_slashes = 2;
3201 strncpy (share, path, MAX_PATH);
3202 /* Truncate to just server and share name. */
3203 dbcs_p = max_filename_mbslen () > 1;
3204 for (p = share + 2; *p && p < share + MAX_PATH; )
3206 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3208 *p = '\0';
3209 break;
3211 if (dbcs_p)
3212 p = CharNextExA (file_name_codepage, p, 0);
3213 else
3214 p++;
3217 resource.dwType = RESOURCETYPE_DISK;
3218 resource.lpLocalName = NULL;
3219 resource.lpRemoteName = share;
3220 resource.lpProvider = NULL;
3222 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
3225 /* Emulate faccessat(2). */
3227 faccessat (int dirfd, const char * path, int mode, int flags)
3229 DWORD attributes;
3231 if (dirfd != AT_FDCWD
3232 && !(IS_DIRECTORY_SEP (path[0])
3233 || IS_DEVICE_SEP (path[1])))
3235 errno = EBADF;
3236 return -1;
3239 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3240 newer versions blow up when passed D_OK. */
3241 path = map_w32_filename (path, NULL);
3242 /* If the last element of PATH is a symlink, we need to resolve it
3243 to get the attributes of its target file. Note: any symlinks in
3244 PATH elements other than the last one are transparently resolved
3245 by GetFileAttributes below. */
3246 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3247 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3248 path = chase_symlinks (path);
3250 if ((attributes = GetFileAttributes (path)) == -1)
3252 DWORD w32err = GetLastError ();
3254 switch (w32err)
3256 case ERROR_INVALID_NAME:
3257 case ERROR_BAD_PATHNAME:
3258 if (is_unc_volume (path))
3260 attributes = unc_volume_file_attributes (path);
3261 if (attributes == -1)
3263 errno = EACCES;
3264 return -1;
3266 break;
3268 /* FALLTHROUGH */
3269 case ERROR_FILE_NOT_FOUND:
3270 case ERROR_BAD_NETPATH:
3271 errno = ENOENT;
3272 break;
3273 default:
3274 errno = EACCES;
3275 break;
3277 return -1;
3279 if ((mode & X_OK) != 0
3280 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3282 errno = EACCES;
3283 return -1;
3285 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3287 errno = EACCES;
3288 return -1;
3290 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3292 errno = EACCES;
3293 return -1;
3295 return 0;
3298 /* Shadow some MSVC runtime functions to map requests for long filenames
3299 to reasonable short names if necessary. This was originally added to
3300 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3301 long file names. */
3304 sys_chdir (const char * path)
3306 return _chdir (map_w32_filename (path, NULL));
3310 sys_chmod (const char * path, int mode)
3312 path = chase_symlinks (map_w32_filename (path, NULL));
3313 return _chmod (path, mode);
3317 sys_creat (const char * path, int mode)
3319 return _creat (map_w32_filename (path, NULL), mode);
3322 FILE *
3323 sys_fopen (const char * path, const char * mode)
3325 int fd;
3326 int oflag;
3327 const char * mode_save = mode;
3329 /* Force all file handles to be non-inheritable. This is necessary to
3330 ensure child processes don't unwittingly inherit handles that might
3331 prevent future file access. */
3333 if (mode[0] == 'r')
3334 oflag = O_RDONLY;
3335 else if (mode[0] == 'w' || mode[0] == 'a')
3336 oflag = O_WRONLY | O_CREAT | O_TRUNC;
3337 else
3338 return NULL;
3340 /* Only do simplistic option parsing. */
3341 while (*++mode)
3342 if (mode[0] == '+')
3344 oflag &= ~(O_RDONLY | O_WRONLY);
3345 oflag |= O_RDWR;
3347 else if (mode[0] == 'b')
3349 oflag &= ~O_TEXT;
3350 oflag |= O_BINARY;
3352 else if (mode[0] == 't')
3354 oflag &= ~O_BINARY;
3355 oflag |= O_TEXT;
3357 else break;
3359 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
3360 if (fd < 0)
3361 return NULL;
3363 return _fdopen (fd, mode_save);
3366 /* This only works on NTFS volumes, but is useful to have. */
3368 sys_link (const char * old, const char * new)
3370 HANDLE fileh;
3371 int result = -1;
3372 char oldname[MAX_PATH], newname[MAX_PATH];
3374 if (old == NULL || new == NULL)
3376 errno = ENOENT;
3377 return -1;
3380 strcpy (oldname, map_w32_filename (old, NULL));
3381 strcpy (newname, map_w32_filename (new, NULL));
3383 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
3384 FILE_FLAG_BACKUP_SEMANTICS, NULL);
3385 if (fileh != INVALID_HANDLE_VALUE)
3387 int wlen;
3389 /* Confusingly, the "alternate" stream name field does not apply
3390 when restoring a hard link, and instead contains the actual
3391 stream data for the link (ie. the name of the link to create).
3392 The WIN32_STREAM_ID structure before the cStreamName field is
3393 the stream header, which is then immediately followed by the
3394 stream data. */
3396 struct {
3397 WIN32_STREAM_ID wid;
3398 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
3399 } data;
3401 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
3402 data.wid.cStreamName, MAX_PATH);
3403 if (wlen > 0)
3405 LPVOID context = NULL;
3406 DWORD wbytes = 0;
3408 data.wid.dwStreamId = BACKUP_LINK;
3409 data.wid.dwStreamAttributes = 0;
3410 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
3411 data.wid.Size.HighPart = 0;
3412 data.wid.dwStreamNameSize = 0;
3414 if (BackupWrite (fileh, (LPBYTE)&data,
3415 offsetof (WIN32_STREAM_ID, cStreamName)
3416 + data.wid.Size.LowPart,
3417 &wbytes, FALSE, FALSE, &context)
3418 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
3420 /* succeeded */
3421 result = 0;
3423 else
3425 /* Should try mapping GetLastError to errno; for now just
3426 indicate a general error (eg. links not supported). */
3427 errno = EINVAL; // perhaps EMLINK?
3431 CloseHandle (fileh);
3433 else
3434 errno = ENOENT;
3436 return result;
3440 sys_mkdir (const char * path)
3442 return _mkdir (map_w32_filename (path, NULL));
3446 sys_open (const char * path, int oflag, int mode)
3448 const char* mpath = map_w32_filename (path, NULL);
3449 int res = -1;
3451 /* If possible, try to open file without _O_CREAT, to be able to
3452 write to existing hidden and system files. Force all file
3453 handles to be non-inheritable. */
3454 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
3455 res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
3456 if (res < 0)
3457 res = _open (mpath, oflag | _O_NOINHERIT, mode);
3459 return res;
3462 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
3463 when using mktemp.
3465 Standard algorithm for generating a temporary file name seems to be
3466 use pid or tid with a letter on the front (in place of the 6 X's)
3467 and cycle through the letters to find a unique name. We extend
3468 that to allow any reasonable character as the first of the 6 X's,
3469 so that the number of simultaneously used temporary files will be
3470 greater. */
3473 mkostemp (char * template, int flags)
3475 char * p;
3476 int i, fd = -1;
3477 unsigned uid = GetCurrentThreadId ();
3478 int save_errno = errno;
3479 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3481 errno = EINVAL;
3482 if (template == NULL)
3483 return -1;
3485 p = template + strlen (template);
3486 i = 5;
3487 /* replace up to the last 5 X's with uid in decimal */
3488 while (--p >= template && p[0] == 'X' && --i >= 0)
3490 p[0] = '0' + uid % 10;
3491 uid /= 10;
3494 if (i < 0 && p[0] == 'X')
3496 i = 0;
3499 p[0] = first_char[i];
3500 if ((fd = sys_open (template,
3501 flags | _O_CREAT | _O_EXCL | _O_RDWR,
3502 S_IRUSR | S_IWUSR)) >= 0
3503 || errno != EEXIST)
3505 if (fd >= 0)
3506 errno = save_errno;
3507 return fd;
3510 while (++i < sizeof (first_char));
3513 /* Template is badly formed or else we can't generate a unique name. */
3514 return -1;
3518 fchmod (int fd, mode_t mode)
3520 return 0;
3524 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
3526 BOOL result;
3527 char temp[MAX_PATH];
3528 int newname_dev;
3529 int oldname_dev;
3531 /* MoveFile on Windows 95 doesn't correctly change the short file name
3532 alias in a number of circumstances (it is not easy to predict when
3533 just by looking at oldname and newname, unfortunately). In these
3534 cases, renaming through a temporary name avoids the problem.
3536 A second problem on Windows 95 is that renaming through a temp name when
3537 newname is uppercase fails (the final long name ends up in
3538 lowercase, although the short alias might be uppercase) UNLESS the
3539 long temp name is not 8.3.
3541 So, on Windows 95 we always rename through a temp name, and we make sure
3542 the temp name has a long extension to ensure correct renaming. */
3544 strcpy (temp, map_w32_filename (oldname, NULL));
3546 /* volume_info is set indirectly by map_w32_filename. */
3547 oldname_dev = volume_info.serialnum;
3549 if (os_subtype == OS_9X)
3551 char * o;
3552 char * p;
3553 int i = 0;
3555 oldname = map_w32_filename (oldname, NULL);
3556 if ((o = strrchr (oldname, '\\')))
3557 o++;
3558 else
3559 o = (char *) oldname;
3561 if ((p = strrchr (temp, '\\')))
3562 p++;
3563 else
3564 p = temp;
3568 /* Force temp name to require a manufactured 8.3 alias - this
3569 seems to make the second rename work properly. */
3570 sprintf (p, "_.%s.%u", o, i);
3571 i++;
3572 result = rename (oldname, temp);
3574 /* This loop must surely terminate! */
3575 while (result < 0 && errno == EEXIST);
3576 if (result < 0)
3577 return -1;
3580 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
3581 (at least if it is a file; don't do this for directories).
3583 Since we mustn't do this if we are just changing the case of the
3584 file name (we would end up deleting the file we are trying to
3585 rename!), we let rename detect if the destination file already
3586 exists - that way we avoid the possible pitfalls of trying to
3587 determine ourselves whether two names really refer to the same
3588 file, which is not always possible in the general case. (Consider
3589 all the permutations of shared or subst'd drives, etc.) */
3591 newname = map_w32_filename (newname, NULL);
3593 /* volume_info is set indirectly by map_w32_filename. */
3594 newname_dev = volume_info.serialnum;
3596 result = rename (temp, newname);
3598 if (result < 0 && force)
3600 DWORD w32err = GetLastError ();
3602 if (errno == EACCES
3603 && newname_dev != oldname_dev)
3605 /* The implementation of `rename' on Windows does not return
3606 errno = EXDEV when you are moving a directory to a
3607 different storage device (ex. logical disk). It returns
3608 EACCES instead. So here we handle such situations and
3609 return EXDEV. */
3610 DWORD attributes;
3612 if ((attributes = GetFileAttributes (temp)) != -1
3613 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
3614 errno = EXDEV;
3616 else if (errno == EEXIST)
3618 if (_chmod (newname, 0666) != 0)
3619 return result;
3620 if (_unlink (newname) != 0)
3621 return result;
3622 result = rename (temp, newname);
3624 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
3625 && is_symlink (temp))
3627 /* This is Windows prohibiting the user from creating a
3628 symlink in another place, since that requires
3629 privileges. */
3630 errno = EPERM;
3634 return result;
3638 sys_rename (char const *old, char const *new)
3640 return sys_rename_replace (old, new, TRUE);
3644 sys_rmdir (const char * path)
3646 return _rmdir (map_w32_filename (path, NULL));
3650 sys_unlink (const char * path)
3652 path = map_w32_filename (path, NULL);
3654 /* On Unix, unlink works without write permission. */
3655 _chmod (path, 0666);
3656 return _unlink (path);
3659 static FILETIME utc_base_ft;
3660 static ULONGLONG utc_base; /* In 100ns units */
3661 static int init = 0;
3663 #define FILETIME_TO_U64(result, ft) \
3664 do { \
3665 ULARGE_INTEGER uiTemp; \
3666 uiTemp.LowPart = (ft).dwLowDateTime; \
3667 uiTemp.HighPart = (ft).dwHighDateTime; \
3668 result = uiTemp.QuadPart; \
3669 } while (0)
3671 static void
3672 initialize_utc_base (void)
3674 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3675 SYSTEMTIME st;
3677 st.wYear = 1970;
3678 st.wMonth = 1;
3679 st.wDay = 1;
3680 st.wHour = 0;
3681 st.wMinute = 0;
3682 st.wSecond = 0;
3683 st.wMilliseconds = 0;
3685 SystemTimeToFileTime (&st, &utc_base_ft);
3686 FILETIME_TO_U64 (utc_base, utc_base_ft);
3689 static time_t
3690 convert_time (FILETIME ft)
3692 ULONGLONG tmp;
3694 if (!init)
3696 initialize_utc_base ();
3697 init = 1;
3700 if (CompareFileTime (&ft, &utc_base_ft) < 0)
3701 return 0;
3703 FILETIME_TO_U64 (tmp, ft);
3704 return (time_t) ((tmp - utc_base) / 10000000L);
3707 static void
3708 convert_from_time_t (time_t time, FILETIME * pft)
3710 ULARGE_INTEGER tmp;
3712 if (!init)
3714 initialize_utc_base ();
3715 init = 1;
3718 /* time in 100ns units since 1-Jan-1601 */
3719 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
3720 pft->dwHighDateTime = tmp.HighPart;
3721 pft->dwLowDateTime = tmp.LowPart;
3724 #if 0
3725 /* No reason to keep this; faking inode values either by hashing or even
3726 using the file index from GetInformationByHandle, is not perfect and
3727 so by default Emacs doesn't use the inode values on Windows.
3728 Instead, we now determine file-truename correctly (except for
3729 possible drive aliasing etc). */
3731 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3732 static unsigned
3733 hashval (const unsigned char * str)
3735 unsigned h = 0;
3736 while (*str)
3738 h = (h << 4) + *str++;
3739 h ^= (h >> 28);
3741 return h;
3744 /* Return the hash value of the canonical pathname, excluding the
3745 drive/UNC header, to get a hopefully unique inode number. */
3746 static DWORD
3747 generate_inode_val (const char * name)
3749 char fullname[ MAX_PATH ];
3750 char * p;
3751 unsigned hash;
3753 /* Get the truly canonical filename, if it exists. (Note: this
3754 doesn't resolve aliasing due to subst commands, or recognize hard
3755 links. */
3756 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3757 emacs_abort ();
3759 parse_root (fullname, &p);
3760 /* Normal W32 filesystems are still case insensitive. */
3761 _strlwr (p);
3762 return hashval (p);
3765 #endif
3767 static PSECURITY_DESCRIPTOR
3768 get_file_security_desc_by_handle (HANDLE h)
3770 PSECURITY_DESCRIPTOR psd = NULL;
3771 DWORD err;
3772 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3773 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3775 err = get_security_info (h, SE_FILE_OBJECT, si,
3776 NULL, NULL, NULL, NULL, &psd);
3777 if (err != ERROR_SUCCESS)
3778 return NULL;
3780 return psd;
3783 static PSECURITY_DESCRIPTOR
3784 get_file_security_desc_by_name (const char *fname)
3786 PSECURITY_DESCRIPTOR psd = NULL;
3787 DWORD sd_len, err;
3788 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3789 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3791 if (!get_file_security (fname, si, psd, 0, &sd_len))
3793 err = GetLastError ();
3794 if (err != ERROR_INSUFFICIENT_BUFFER)
3795 return NULL;
3798 psd = xmalloc (sd_len);
3799 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3801 xfree (psd);
3802 return NULL;
3805 return psd;
3808 static DWORD
3809 get_rid (PSID sid)
3811 unsigned n_subauthorities;
3813 /* Use the last sub-authority value of the RID, the relative
3814 portion of the SID, as user/group ID. */
3815 n_subauthorities = *get_sid_sub_authority_count (sid);
3816 if (n_subauthorities < 1)
3817 return 0; /* the "World" RID */
3818 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3821 /* Caching SID and account values for faster lokup. */
3823 struct w32_id {
3824 unsigned rid;
3825 struct w32_id *next;
3826 char name[GNLEN+1];
3827 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3830 static struct w32_id *w32_idlist;
3832 static int
3833 w32_cached_id (PSID sid, unsigned *id, char *name)
3835 struct w32_id *tail, *found;
3837 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3839 if (equal_sid ((PSID)tail->sid, sid))
3841 found = tail;
3842 break;
3845 if (found)
3847 *id = found->rid;
3848 strcpy (name, found->name);
3849 return 1;
3851 else
3852 return 0;
3855 static void
3856 w32_add_to_cache (PSID sid, unsigned id, char *name)
3858 DWORD sid_len;
3859 struct w32_id *new_entry;
3861 /* We don't want to leave behind stale cache from when Emacs was
3862 dumped. */
3863 if (initialized)
3865 sid_len = get_length_sid (sid);
3866 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3867 if (new_entry)
3869 new_entry->rid = id;
3870 strcpy (new_entry->name, name);
3871 copy_sid (sid_len, (PSID)new_entry->sid, sid);
3872 new_entry->next = w32_idlist;
3873 w32_idlist = new_entry;
3878 #define UID 1
3879 #define GID 2
3881 static int
3882 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
3884 PSID sid = NULL;
3885 BOOL dflt;
3886 SID_NAME_USE ignore;
3887 char name[UNLEN+1];
3888 DWORD name_len = sizeof (name);
3889 char domain[1024];
3890 DWORD domain_len = sizeof (domain);
3891 int use_dflt = 0;
3892 int result;
3894 if (what == UID)
3895 result = get_security_descriptor_owner (psd, &sid, &dflt);
3896 else if (what == GID)
3897 result = get_security_descriptor_group (psd, &sid, &dflt);
3898 else
3899 result = 0;
3901 if (!result || !is_valid_sid (sid))
3902 use_dflt = 1;
3903 else if (!w32_cached_id (sid, id, nm))
3905 if (!lookup_account_sid (NULL, sid, name, &name_len,
3906 domain, &domain_len, &ignore)
3907 || name_len > UNLEN+1)
3908 use_dflt = 1;
3909 else
3911 *id = get_rid (sid);
3912 strcpy (nm, name);
3913 w32_add_to_cache (sid, *id, name);
3916 return use_dflt;
3919 static void
3920 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
3922 int dflt_usr = 0, dflt_grp = 0;
3924 if (!psd)
3926 dflt_usr = 1;
3927 dflt_grp = 1;
3929 else
3931 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
3932 dflt_usr = 1;
3933 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
3934 dflt_grp = 1;
3936 /* Consider files to belong to current user/group, if we cannot get
3937 more accurate information. */
3938 if (dflt_usr)
3940 st->st_uid = dflt_passwd.pw_uid;
3941 strcpy (st->st_uname, dflt_passwd.pw_name);
3943 if (dflt_grp)
3945 st->st_gid = dflt_passwd.pw_gid;
3946 strcpy (st->st_gname, dflt_group.gr_name);
3950 /* Return non-zero if NAME is a potentially slow filesystem. */
3952 is_slow_fs (const char *name)
3954 char drive_root[4];
3955 UINT devtype;
3957 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
3958 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
3959 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
3960 devtype = GetDriveType (NULL); /* use root of current drive */
3961 else
3963 /* GetDriveType needs the root directory of the drive. */
3964 strncpy (drive_root, name, 2);
3965 drive_root[2] = '\\';
3966 drive_root[3] = '\0';
3967 devtype = GetDriveType (drive_root);
3969 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
3972 /* If this is non-zero, the caller wants accurate information about
3973 file's owner and group, which could be expensive to get. */
3974 int w32_stat_get_owner_group;
3976 /* MSVC stat function can't cope with UNC names and has other bugs, so
3977 replace it with our own. This also allows us to calculate consistent
3978 inode values and owner/group without hacks in the main Emacs code. */
3980 static int
3981 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
3983 char *name, *save_name, *r;
3984 WIN32_FIND_DATA wfd;
3985 HANDLE fh;
3986 unsigned __int64 fake_inode = 0;
3987 int permission;
3988 int len;
3989 int rootdir = FALSE;
3990 PSECURITY_DESCRIPTOR psd = NULL;
3991 int is_a_symlink = 0;
3992 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
3993 DWORD access_rights = 0;
3994 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
3995 FILETIME ctime, atime, wtime;
3996 int dbcs_p;
3998 if (path == NULL || buf == NULL)
4000 errno = EFAULT;
4001 return -1;
4004 save_name = name = (char *) map_w32_filename (path, &path);
4005 /* Must be valid filename, no wild cards or other invalid
4006 characters. We use _mbspbrk to support multibyte strings that
4007 might look to strpbrk as if they included literal *, ?, and other
4008 characters mentioned below that are disallowed by Windows
4009 filesystems. */
4010 if (_mbspbrk (name, "*?|<>\""))
4012 errno = ENOENT;
4013 return -1;
4016 /* Remove trailing directory separator, unless name is the root
4017 directory of a drive or UNC volume in which case ensure there
4018 is a trailing separator. */
4019 len = strlen (name);
4020 name = strcpy (alloca (len + 2), name);
4022 /* Avoid a somewhat costly call to is_symlink if the filesystem
4023 doesn't support symlinks. */
4024 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4025 is_a_symlink = is_symlink (name);
4027 /* Plan A: Open the file and get all the necessary information via
4028 the resulting handle. This solves several issues in one blow:
4030 . retrieves attributes for the target of a symlink, if needed
4031 . gets attributes of root directories and symlinks pointing to
4032 root directories, thus avoiding the need for special-casing
4033 these and detecting them by examining the file-name format
4034 . retrieves more accurate attributes (e.g., non-zero size for
4035 some directories, esp. directories that are junction points)
4036 . correctly resolves "c:/..", "/.." and similar file names
4037 . avoids run-time penalties for 99% of use cases
4039 Plan A is always tried first, unless the user asked not to (but
4040 if the file is a symlink and we need to follow links, we try Plan
4041 A even if the user asked not to).
4043 If Plan A fails, we go to Plan B (below), where various
4044 potentially expensive techniques must be used to handle "special"
4045 files such as UNC volumes etc. */
4046 if (!(NILP (Vw32_get_true_file_attributes)
4047 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
4048 /* Following symlinks requires getting the info by handle. */
4049 || (is_a_symlink && follow_symlinks))
4051 BY_HANDLE_FILE_INFORMATION info;
4053 if (is_a_symlink && !follow_symlinks)
4054 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
4055 /* READ_CONTROL access rights are required to get security info
4056 by handle. But if the OS doesn't support security in the
4057 first place, we don't need to try. */
4058 if (is_windows_9x () != TRUE)
4059 access_rights |= READ_CONTROL;
4061 fh = CreateFile (name, access_rights, 0, NULL, OPEN_EXISTING,
4062 file_flags, NULL);
4063 /* If CreateFile fails with READ_CONTROL, try again with zero as
4064 access rights. */
4065 if (fh == INVALID_HANDLE_VALUE && access_rights)
4066 fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
4067 file_flags, NULL);
4068 if (fh == INVALID_HANDLE_VALUE)
4069 goto no_true_file_attributes;
4071 /* This is more accurate in terms of getting the correct number
4072 of links, but is quite slow (it is noticeable when Emacs is
4073 making a list of file name completions). */
4074 if (GetFileInformationByHandle (fh, &info))
4076 nlinks = info.nNumberOfLinks;
4077 /* Might as well use file index to fake inode values, but this
4078 is not guaranteed to be unique unless we keep a handle open
4079 all the time (even then there are situations where it is
4080 not unique). Reputedly, there are at most 48 bits of info
4081 (on NTFS, presumably less on FAT). */
4082 fake_inode = info.nFileIndexHigh;
4083 fake_inode <<= 32;
4084 fake_inode += info.nFileIndexLow;
4085 serialnum = info.dwVolumeSerialNumber;
4086 fs_high = info.nFileSizeHigh;
4087 fs_low = info.nFileSizeLow;
4088 ctime = info.ftCreationTime;
4089 atime = info.ftLastAccessTime;
4090 wtime = info.ftLastWriteTime;
4091 fattrs = info.dwFileAttributes;
4093 else
4095 /* We don't go to Plan B here, because it's not clear that
4096 it's a good idea. The only known use case where
4097 CreateFile succeeds, but GetFileInformationByHandle fails
4098 (with ERROR_INVALID_FUNCTION) is for character devices
4099 such as NUL, PRN, etc. For these, switching to Plan B is
4100 a net loss, because we lose the character device
4101 attribute returned by GetFileType below (FindFirstFile
4102 doesn't set that bit in the attributes), and the other
4103 fields don't make sense for character devices anyway.
4104 Emacs doesn't really care for non-file entities in the
4105 context of l?stat, so neither do we. */
4107 /* w32err is assigned so one could put a breakpoint here and
4108 examine its value, when GetFileInformationByHandle
4109 fails. */
4110 DWORD w32err = GetLastError ();
4112 switch (w32err)
4114 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
4115 errno = ENOENT;
4116 return -1;
4120 /* Test for a symlink before testing for a directory, since
4121 symlinks to directories have the directory bit set, but we
4122 don't want them to appear as directories. */
4123 if (is_a_symlink && !follow_symlinks)
4124 buf->st_mode = S_IFLNK;
4125 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4126 buf->st_mode = S_IFDIR;
4127 else
4129 DWORD ftype = GetFileType (fh);
4131 switch (ftype)
4133 case FILE_TYPE_DISK:
4134 buf->st_mode = S_IFREG;
4135 break;
4136 case FILE_TYPE_PIPE:
4137 buf->st_mode = S_IFIFO;
4138 break;
4139 case FILE_TYPE_CHAR:
4140 case FILE_TYPE_UNKNOWN:
4141 default:
4142 buf->st_mode = S_IFCHR;
4145 /* We produce the fallback owner and group data, based on the
4146 current user that runs Emacs, in the following cases:
4148 . caller didn't request owner and group info
4149 . this is Windows 9X
4150 . getting security by handle failed, and we need to produce
4151 information for the target of a symlink (this is better
4152 than producing a potentially misleading info about the
4153 symlink itself)
4155 If getting security by handle fails, and we don't need to
4156 resolve symlinks, we try getting security by name. */
4157 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4158 get_file_owner_and_group (NULL, buf);
4159 else
4161 psd = get_file_security_desc_by_handle (fh);
4162 if (psd)
4164 get_file_owner_and_group (psd, buf);
4165 LocalFree (psd);
4167 else if (!(is_a_symlink && follow_symlinks))
4169 psd = get_file_security_desc_by_name (name);
4170 get_file_owner_and_group (psd, buf);
4171 xfree (psd);
4173 else
4174 get_file_owner_and_group (NULL, buf);
4176 CloseHandle (fh);
4178 else
4180 no_true_file_attributes:
4181 /* Plan B: Either getting a handle on the file failed, or the
4182 caller explicitly asked us to not bother making this
4183 information more accurate.
4185 Implementation note: In Plan B, we never bother to resolve
4186 symlinks, even if we got here because we tried Plan A and
4187 failed. That's because, even if the caller asked for extra
4188 precision by setting Vw32_get_true_file_attributes to t,
4189 resolving symlinks requires acquiring a file handle to the
4190 symlink, which we already know will fail. And if the user
4191 did not ask for extra precision, resolving symlinks will fly
4192 in the face of that request, since the user then wants the
4193 lightweight version of the code. */
4194 dbcs_p = max_filename_mbslen () > 1;
4195 rootdir = (path >= save_name + len - 1
4196 && (IS_DIRECTORY_SEP (*path) || *path == 0));
4198 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4199 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
4200 if (IS_DIRECTORY_SEP (r[0])
4201 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
4202 r[1] = r[2] = '\0';
4204 /* Note: If NAME is a symlink to the root of a UNC volume
4205 (i.e. "\\SERVER"), we will not detect that here, and we will
4206 return data about the symlink as result of FindFirst below.
4207 This is unfortunate, but that marginal use case does not
4208 justify a call to chase_symlinks which would impose a penalty
4209 on all the other use cases. (We get here for symlinks to
4210 roots of UNC volumes because CreateFile above fails for them,
4211 unlike with symlinks to root directories X:\ of drives.) */
4212 if (is_unc_volume (name))
4214 fattrs = unc_volume_file_attributes (name);
4215 if (fattrs == -1)
4216 return -1;
4218 ctime = atime = wtime = utc_base_ft;
4220 else if (rootdir)
4222 if (!dbcs_p)
4224 if (!IS_DIRECTORY_SEP (name[len-1]))
4225 strcat (name, "\\");
4227 else
4229 char *end = name + len;
4230 char *n = CharPrevExA (file_name_codepage, name, end, 0);
4232 if (!IS_DIRECTORY_SEP (*n))
4233 strcat (name, "\\");
4235 if (GetDriveType (name) < 2)
4237 errno = ENOENT;
4238 return -1;
4241 fattrs = FILE_ATTRIBUTE_DIRECTORY;
4242 ctime = atime = wtime = utc_base_ft;
4244 else
4246 if (!dbcs_p)
4248 if (IS_DIRECTORY_SEP (name[len-1]))
4249 name[len - 1] = 0;
4251 else
4253 char *end = name + len;
4254 char *n = CharPrevExA (file_name_codepage, name, end, 0);
4256 if (IS_DIRECTORY_SEP (*n))
4257 *n = 0;
4260 /* (This is hacky, but helps when doing file completions on
4261 network drives.) Optimize by using information available from
4262 active readdir if possible. */
4263 len = strlen (dir_pathname);
4264 if (!dbcs_p)
4266 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
4267 len--;
4269 else
4271 char *end = dir_pathname + len;
4272 char *n = CharPrevExA (file_name_codepage, dir_pathname, end, 0);
4274 if (IS_DIRECTORY_SEP (*n))
4275 len--;
4277 if (dir_find_handle != INVALID_HANDLE_VALUE
4278 && !(is_a_symlink && follow_symlinks)
4279 && strnicmp (save_name, dir_pathname, len) == 0
4280 && IS_DIRECTORY_SEP (name[len])
4281 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
4283 /* This was the last entry returned by readdir. */
4284 wfd = dir_find_data;
4286 else
4288 logon_network_drive (name);
4290 fh = FindFirstFile (name, &wfd);
4291 if (fh == INVALID_HANDLE_VALUE)
4293 errno = ENOENT;
4294 return -1;
4296 FindClose (fh);
4298 /* Note: if NAME is a symlink, the information we get from
4299 FindFirstFile is for the symlink, not its target. */
4300 fattrs = wfd.dwFileAttributes;
4301 ctime = wfd.ftCreationTime;
4302 atime = wfd.ftLastAccessTime;
4303 wtime = wfd.ftLastWriteTime;
4304 fs_high = wfd.nFileSizeHigh;
4305 fs_low = wfd.nFileSizeLow;
4306 fake_inode = 0;
4307 nlinks = 1;
4308 serialnum = volume_info.serialnum;
4310 if (is_a_symlink && !follow_symlinks)
4311 buf->st_mode = S_IFLNK;
4312 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4313 buf->st_mode = S_IFDIR;
4314 else
4315 buf->st_mode = S_IFREG;
4317 get_file_owner_and_group (NULL, buf);
4320 #if 0
4321 /* Not sure if there is any point in this. */
4322 if (!NILP (Vw32_generate_fake_inodes))
4323 fake_inode = generate_inode_val (name);
4324 else if (fake_inode == 0)
4326 /* For want of something better, try to make everything unique. */
4327 static DWORD gen_num = 0;
4328 fake_inode = ++gen_num;
4330 #endif
4332 buf->st_ino = fake_inode;
4334 buf->st_dev = serialnum;
4335 buf->st_rdev = serialnum;
4337 buf->st_size = fs_high;
4338 buf->st_size <<= 32;
4339 buf->st_size += fs_low;
4340 buf->st_nlink = nlinks;
4342 /* Convert timestamps to Unix format. */
4343 buf->st_mtime = convert_time (wtime);
4344 buf->st_atime = convert_time (atime);
4345 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
4346 buf->st_ctime = convert_time (ctime);
4347 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
4349 /* determine rwx permissions */
4350 if (is_a_symlink && !follow_symlinks)
4351 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
4352 else
4354 if (fattrs & FILE_ATTRIBUTE_READONLY)
4355 permission = S_IREAD;
4356 else
4357 permission = S_IREAD | S_IWRITE;
4359 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4360 permission |= S_IEXEC;
4361 else if (is_exec (name))
4362 permission |= S_IEXEC;
4365 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
4367 return 0;
4371 stat (const char * path, struct stat * buf)
4373 return stat_worker (path, buf, 1);
4377 lstat (const char * path, struct stat * buf)
4379 return stat_worker (path, buf, 0);
4383 fstatat (int fd, char const *name, struct stat *st, int flags)
4385 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4386 This is good enough for the current usage in Emacs, but is fragile.
4388 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4389 Gnulib does this and can serve as a model. */
4390 char fullname[MAX_PATH];
4392 if (fd != AT_FDCWD)
4394 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
4395 < 0)
4397 errno = ENAMETOOLONG;
4398 return -1;
4400 name = fullname;
4403 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
4406 /* Provide fstat and utime as well as stat for consistent handling of
4407 file timestamps. */
4409 fstat (int desc, struct stat * buf)
4411 HANDLE fh = (HANDLE) _get_osfhandle (desc);
4412 BY_HANDLE_FILE_INFORMATION info;
4413 unsigned __int64 fake_inode;
4414 int permission;
4416 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
4418 case FILE_TYPE_DISK:
4419 buf->st_mode = S_IFREG;
4420 if (!GetFileInformationByHandle (fh, &info))
4422 errno = EACCES;
4423 return -1;
4425 break;
4426 case FILE_TYPE_PIPE:
4427 buf->st_mode = S_IFIFO;
4428 goto non_disk;
4429 case FILE_TYPE_CHAR:
4430 case FILE_TYPE_UNKNOWN:
4431 default:
4432 buf->st_mode = S_IFCHR;
4433 non_disk:
4434 memset (&info, 0, sizeof (info));
4435 info.dwFileAttributes = 0;
4436 info.ftCreationTime = utc_base_ft;
4437 info.ftLastAccessTime = utc_base_ft;
4438 info.ftLastWriteTime = utc_base_ft;
4441 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
4442 buf->st_mode = S_IFDIR;
4444 buf->st_nlink = info.nNumberOfLinks;
4445 /* Might as well use file index to fake inode values, but this
4446 is not guaranteed to be unique unless we keep a handle open
4447 all the time (even then there are situations where it is
4448 not unique). Reputedly, there are at most 48 bits of info
4449 (on NTFS, presumably less on FAT). */
4450 fake_inode = info.nFileIndexHigh;
4451 fake_inode <<= 32;
4452 fake_inode += info.nFileIndexLow;
4454 /* MSVC defines _ino_t to be short; other libc's might not. */
4455 if (sizeof (buf->st_ino) == 2)
4456 buf->st_ino = fake_inode ^ (fake_inode >> 16);
4457 else
4458 buf->st_ino = fake_inode;
4460 /* If the caller so requested, get the true file owner and group.
4461 Otherwise, consider the file to belong to the current user. */
4462 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4463 get_file_owner_and_group (NULL, buf);
4464 else
4466 PSECURITY_DESCRIPTOR psd = NULL;
4468 psd = get_file_security_desc_by_handle (fh);
4469 if (psd)
4471 get_file_owner_and_group (psd, buf);
4472 LocalFree (psd);
4474 else
4475 get_file_owner_and_group (NULL, buf);
4478 buf->st_dev = info.dwVolumeSerialNumber;
4479 buf->st_rdev = info.dwVolumeSerialNumber;
4481 buf->st_size = info.nFileSizeHigh;
4482 buf->st_size <<= 32;
4483 buf->st_size += info.nFileSizeLow;
4485 /* Convert timestamps to Unix format. */
4486 buf->st_mtime = convert_time (info.ftLastWriteTime);
4487 buf->st_atime = convert_time (info.ftLastAccessTime);
4488 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
4489 buf->st_ctime = convert_time (info.ftCreationTime);
4490 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
4492 /* determine rwx permissions */
4493 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
4494 permission = S_IREAD;
4495 else
4496 permission = S_IREAD | S_IWRITE;
4498 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
4499 permission |= S_IEXEC;
4500 else
4502 #if 0 /* no way of knowing the filename */
4503 char * p = strrchr (name, '.');
4504 if (p != NULL &&
4505 (xstrcasecmp (p, ".exe") == 0 ||
4506 xstrcasecmp (p, ".com") == 0 ||
4507 xstrcasecmp (p, ".bat") == 0 ||
4508 xstrcasecmp (p, ".cmd") == 0))
4509 permission |= S_IEXEC;
4510 #endif
4513 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
4515 return 0;
4518 /* A version of 'utime' which handles directories as well as
4519 files. */
4522 utime (const char *name, struct utimbuf *times)
4524 struct utimbuf deftime;
4525 HANDLE fh;
4526 FILETIME mtime;
4527 FILETIME atime;
4529 if (times == NULL)
4531 deftime.modtime = deftime.actime = time (NULL);
4532 times = &deftime;
4535 /* Need write access to set times. */
4536 fh = CreateFile (name, FILE_WRITE_ATTRIBUTES,
4537 /* If NAME specifies a directory, FILE_SHARE_DELETE
4538 allows other processes to delete files inside it,
4539 while we have the directory open. */
4540 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4541 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
4542 if (fh != INVALID_HANDLE_VALUE)
4544 convert_from_time_t (times->actime, &atime);
4545 convert_from_time_t (times->modtime, &mtime);
4546 if (!SetFileTime (fh, NULL, &atime, &mtime))
4548 CloseHandle (fh);
4549 errno = EACCES;
4550 return -1;
4552 CloseHandle (fh);
4554 else
4556 errno = EINVAL;
4557 return -1;
4559 return 0;
4563 /* Symlink-related functions. */
4564 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4565 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4566 #endif
4569 symlink (char const *filename, char const *linkname)
4571 char linkfn[MAX_PATH], *tgtfn;
4572 DWORD flags = 0;
4573 int dir_access, filename_ends_in_slash;
4574 int dbcs_p;
4576 /* Diagnostics follows Posix as much as possible. */
4577 if (filename == NULL || linkname == NULL)
4579 errno = EFAULT;
4580 return -1;
4582 if (!*filename)
4584 errno = ENOENT;
4585 return -1;
4587 if (strlen (filename) > MAX_PATH || strlen (linkname) > MAX_PATH)
4589 errno = ENAMETOOLONG;
4590 return -1;
4593 strcpy (linkfn, map_w32_filename (linkname, NULL));
4594 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
4596 errno = EPERM;
4597 return -1;
4600 dbcs_p = max_filename_mbslen () > 1;
4602 /* Note: since empty FILENAME was already rejected, we can safely
4603 refer to FILENAME[1]. */
4604 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
4606 /* Non-absolute FILENAME is understood as being relative to
4607 LINKNAME's directory. We need to prepend that directory to
4608 FILENAME to get correct results from faccessat below, since
4609 otherwise it will interpret FILENAME relative to the
4610 directory where the Emacs process runs. Note that
4611 make-symbolic-link always makes sure LINKNAME is a fully
4612 expanded file name. */
4613 char tem[MAX_PATH];
4614 char *p = linkfn + strlen (linkfn);
4616 if (!dbcs_p)
4618 while (p > linkfn && !IS_ANY_SEP (p[-1]))
4619 p--;
4621 else
4623 char *p1 = CharPrevExA (file_name_codepage, linkfn, p, 0);
4625 while (p > linkfn && !IS_ANY_SEP (*p1))
4627 p = p1;
4628 p1 = CharPrevExA (file_name_codepage, linkfn, p1, 0);
4631 if (p > linkfn)
4632 strncpy (tem, linkfn, p - linkfn);
4633 tem[p - linkfn] = '\0';
4634 strcat (tem, filename);
4635 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
4637 else
4638 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
4640 /* Since Windows distinguishes between symlinks to directories and
4641 to files, we provide a kludgy feature: if FILENAME doesn't
4642 exist, but ends in a slash, we create a symlink to directory. If
4643 FILENAME exists and is a directory, we always create a symlink to
4644 directory. */
4645 if (!dbcs_p)
4646 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
4647 else
4649 const char *end = filename + strlen (filename);
4650 const char *n = CharPrevExA (file_name_codepage, filename, end, 0);
4652 filename_ends_in_slash = IS_DIRECTORY_SEP (*n);
4654 if (dir_access == 0 || filename_ends_in_slash)
4655 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
4657 tgtfn = (char *)map_w32_filename (filename, NULL);
4658 if (filename_ends_in_slash)
4659 tgtfn[strlen (tgtfn) - 1] = '\0';
4661 errno = 0;
4662 if (!create_symbolic_link (linkfn, tgtfn, flags))
4664 /* ENOSYS is set by create_symbolic_link, when it detects that
4665 the OS doesn't support the CreateSymbolicLink API. */
4666 if (errno != ENOSYS)
4668 DWORD w32err = GetLastError ();
4670 switch (w32err)
4672 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4673 TGTFN point to the same file name, go figure. */
4674 case ERROR_SUCCESS:
4675 case ERROR_FILE_EXISTS:
4676 errno = EEXIST;
4677 break;
4678 case ERROR_ACCESS_DENIED:
4679 errno = EACCES;
4680 break;
4681 case ERROR_FILE_NOT_FOUND:
4682 case ERROR_PATH_NOT_FOUND:
4683 case ERROR_BAD_NETPATH:
4684 case ERROR_INVALID_REPARSE_DATA:
4685 errno = ENOENT;
4686 break;
4687 case ERROR_DIRECTORY:
4688 errno = EISDIR;
4689 break;
4690 case ERROR_PRIVILEGE_NOT_HELD:
4691 case ERROR_NOT_ALL_ASSIGNED:
4692 errno = EPERM;
4693 break;
4694 case ERROR_DISK_FULL:
4695 errno = ENOSPC;
4696 break;
4697 default:
4698 errno = EINVAL;
4699 break;
4702 return -1;
4704 return 0;
4707 /* A quick inexpensive test of whether FILENAME identifies a file that
4708 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4709 must already be in the normalized form returned by
4710 map_w32_filename.
4712 Note: for repeated operations on many files, it is best to test
4713 whether the underlying volume actually supports symlinks, by
4714 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4715 avoid the call to this function if it doesn't. That's because the
4716 call to GetFileAttributes takes a non-negligible time, especially
4717 on non-local or removable filesystems. See stat_worker for an
4718 example of how to do that. */
4719 static int
4720 is_symlink (const char *filename)
4722 DWORD attrs;
4723 WIN32_FIND_DATA wfd;
4724 HANDLE fh;
4726 attrs = GetFileAttributes (filename);
4727 if (attrs == -1)
4729 DWORD w32err = GetLastError ();
4731 switch (w32err)
4733 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
4734 break;
4735 case ERROR_ACCESS_DENIED:
4736 errno = EACCES;
4737 break;
4738 case ERROR_FILE_NOT_FOUND:
4739 case ERROR_PATH_NOT_FOUND:
4740 default:
4741 errno = ENOENT;
4742 break;
4744 return 0;
4746 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
4747 return 0;
4748 logon_network_drive (filename);
4749 fh = FindFirstFile (filename, &wfd);
4750 if (fh == INVALID_HANDLE_VALUE)
4751 return 0;
4752 FindClose (fh);
4753 return (wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
4754 && (wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
4757 /* If NAME identifies a symbolic link, copy into BUF the file name of
4758 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4759 null-terminate the target name, even if it fits. Return the number
4760 of bytes copied, or -1 if NAME is not a symlink or any error was
4761 encountered while resolving it. The file name copied into BUF is
4762 encoded in the current ANSI codepage. */
4763 ssize_t
4764 readlink (const char *name, char *buf, size_t buf_size)
4766 const char *path;
4767 TOKEN_PRIVILEGES privs;
4768 int restore_privs = 0;
4769 HANDLE sh;
4770 ssize_t retval;
4772 if (name == NULL)
4774 errno = EFAULT;
4775 return -1;
4777 if (!*name)
4779 errno = ENOENT;
4780 return -1;
4783 path = map_w32_filename (name, NULL);
4785 if (strlen (path) > MAX_PATH)
4787 errno = ENAMETOOLONG;
4788 return -1;
4791 errno = 0;
4792 if (is_windows_9x () == TRUE
4793 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
4794 || !is_symlink (path))
4796 if (!errno)
4797 errno = EINVAL; /* not a symlink */
4798 return -1;
4801 /* Done with simple tests, now we're in for some _real_ work. */
4802 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
4803 restore_privs = 1;
4804 /* Implementation note: From here and onward, don't return early,
4805 since that will fail to restore the original set of privileges of
4806 the calling thread. */
4808 retval = -1; /* not too optimistic, are we? */
4810 /* Note: In the next call to CreateFile, we use zero as the 2nd
4811 argument because, when the symlink is a hidden/system file,
4812 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4813 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4814 and directory symlinks. */
4815 sh = CreateFile (path, 0, 0, NULL, OPEN_EXISTING,
4816 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
4817 NULL);
4818 if (sh != INVALID_HANDLE_VALUE)
4820 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
4821 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
4822 DWORD retbytes;
4824 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
4825 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
4826 &retbytes, NULL))
4827 errno = EIO;
4828 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
4829 errno = EINVAL;
4830 else
4832 /* Copy the link target name, in wide characters, from
4833 reparse_data, then convert it to multibyte encoding in
4834 the current locale's codepage. */
4835 WCHAR *lwname;
4836 BYTE lname[MAX_PATH];
4837 USHORT lname_len;
4838 USHORT lwname_len =
4839 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
4840 WCHAR *lwname_src =
4841 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
4842 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
4843 /* This updates file_name_codepage which we need below. */
4844 int dbcs_p = max_filename_mbslen () > 1;
4846 /* According to MSDN, PrintNameLength does not include the
4847 terminating null character. */
4848 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
4849 memcpy (lwname, lwname_src, lwname_len);
4850 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
4852 lname_len = WideCharToMultiByte (file_name_codepage, 0, lwname, -1,
4853 lname, MAX_PATH, NULL, NULL);
4854 if (!lname_len)
4856 /* WideCharToMultiByte failed. */
4857 DWORD w32err1 = GetLastError ();
4859 switch (w32err1)
4861 case ERROR_INSUFFICIENT_BUFFER:
4862 errno = ENAMETOOLONG;
4863 break;
4864 case ERROR_INVALID_PARAMETER:
4865 errno = EFAULT;
4866 break;
4867 case ERROR_NO_UNICODE_TRANSLATION:
4868 errno = ENOENT;
4869 break;
4870 default:
4871 errno = EINVAL;
4872 break;
4875 else
4877 size_t size_to_copy = buf_size;
4878 BYTE *p = lname, *p2;
4879 BYTE *pend = p + lname_len;
4881 /* Normalize like dostounix_filename does, but we don't
4882 want to assume that lname is null-terminated. */
4883 if (dbcs_p)
4884 p2 = CharNextExA (file_name_codepage, p, 0);
4885 else
4886 p2 = p + 1;
4887 if (*p && *p2 == ':' && *p >= 'A' && *p <= 'Z')
4889 *p += 'a' - 'A';
4890 p += 2;
4892 while (p <= pend)
4894 if (*p == '\\')
4895 *p = '/';
4896 if (dbcs_p)
4898 p = CharNextExA (file_name_codepage, p, 0);
4899 /* CharNextExA doesn't advance at null character. */
4900 if (!*p)
4901 break;
4903 else
4904 ++p;
4906 /* Testing for null-terminated LNAME is paranoia:
4907 WideCharToMultiByte should always return a
4908 null-terminated string when its 4th argument is -1
4909 and its 3rd argument is null-terminated (which they
4910 are, see above). */
4911 if (lname[lname_len - 1] == '\0')
4912 lname_len--;
4913 if (lname_len <= buf_size)
4914 size_to_copy = lname_len;
4915 strncpy (buf, lname, size_to_copy);
4916 /* Success! */
4917 retval = size_to_copy;
4920 CloseHandle (sh);
4922 else
4924 /* CreateFile failed. */
4925 DWORD w32err2 = GetLastError ();
4927 switch (w32err2)
4929 case ERROR_FILE_NOT_FOUND:
4930 case ERROR_PATH_NOT_FOUND:
4931 errno = ENOENT;
4932 break;
4933 case ERROR_ACCESS_DENIED:
4934 case ERROR_TOO_MANY_OPEN_FILES:
4935 errno = EACCES;
4936 break;
4937 default:
4938 errno = EPERM;
4939 break;
4942 if (restore_privs)
4944 restore_privilege (&privs);
4945 revert_to_self ();
4948 return retval;
4951 ssize_t
4952 readlinkat (int fd, char const *name, char *buffer,
4953 size_t buffer_size)
4955 /* Rely on a hack: an open directory is modeled as file descriptor 0,
4956 as in fstatat. FIXME: Add proper support for readlinkat. */
4957 char fullname[MAX_PATH];
4959 if (fd != AT_FDCWD)
4961 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
4962 < 0)
4964 errno = ENAMETOOLONG;
4965 return -1;
4967 name = fullname;
4970 return readlink (name, buffer, buffer_size);
4973 /* If FILE is a symlink, return its target (stored in a static
4974 buffer); otherwise return FILE.
4976 This function repeatedly resolves symlinks in the last component of
4977 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4978 until it arrives at a file whose last component is not a symlink,
4979 or some error occurs. It returns the target of the last
4980 successfully resolved symlink in the chain. If it succeeds to
4981 resolve even a single symlink, the value returned is an absolute
4982 file name with backslashes (result of GetFullPathName). By
4983 contrast, if the original FILE is returned, it is unaltered.
4985 Note: This function can set errno even if it succeeds.
4987 Implementation note: we only resolve the last portion ("basename")
4988 of the argument FILE and of each following file in the chain,
4989 disregarding any possible symlinks in its leading directories.
4990 This is because Windows system calls and library functions
4991 transparently resolve symlinks in leading directories and return
4992 correct information, as long as the basename is not a symlink. */
4993 static char *
4994 chase_symlinks (const char *file)
4996 static char target[MAX_PATH];
4997 char link[MAX_PATH];
4998 ssize_t res, link_len;
4999 int loop_count = 0;
5000 int dbcs_p;
5002 if (is_windows_9x () == TRUE || !is_symlink (file))
5003 return (char *)file;
5005 if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0)
5006 return (char *)file;
5008 dbcs_p = max_filename_mbslen () > 1;
5009 target[0] = '\0';
5010 do {
5012 /* Remove trailing slashes, as we want to resolve the last
5013 non-trivial part of the link name. */
5014 if (!dbcs_p)
5016 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
5017 link[link_len--] = '\0';
5019 else if (link_len > 3)
5021 char *n = CharPrevExA (file_name_codepage, link, link + link_len, 0);
5023 while (n >= link + 2 && IS_DIRECTORY_SEP (*n))
5025 n[1] = '\0';
5026 n = CharPrevExA (file_name_codepage, link, n, 0);
5030 res = readlink (link, target, MAX_PATH);
5031 if (res > 0)
5033 target[res] = '\0';
5034 if (!(IS_DEVICE_SEP (target[1])
5035 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
5037 /* Target is relative. Append it to the directory part of
5038 the symlink, then copy the result back to target. */
5039 char *p = link + link_len;
5041 if (!dbcs_p)
5043 while (p > link && !IS_ANY_SEP (p[-1]))
5044 p--;
5046 else
5048 char *p1 = CharPrevExA (file_name_codepage, link, p, 0);
5050 while (p > link && !IS_ANY_SEP (*p1))
5052 p = p1;
5053 p1 = CharPrevExA (file_name_codepage, link, p1, 0);
5056 strcpy (p, target);
5057 strcpy (target, link);
5059 /* Resolve any "." and ".." to get a fully-qualified file name
5060 in link[] again. */
5061 link_len = GetFullPathName (target, MAX_PATH, link, NULL);
5063 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
5065 if (loop_count > 100)
5066 errno = ELOOP;
5068 if (target[0] == '\0') /* not a single call to readlink succeeded */
5069 return (char *)file;
5070 return target;
5074 /* Posix ACL emulation. */
5077 acl_valid (acl_t acl)
5079 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
5082 char *
5083 acl_to_text (acl_t acl, ssize_t *size)
5085 LPTSTR str_acl;
5086 SECURITY_INFORMATION flags =
5087 OWNER_SECURITY_INFORMATION |
5088 GROUP_SECURITY_INFORMATION |
5089 DACL_SECURITY_INFORMATION;
5090 char *retval = NULL;
5091 ULONG local_size;
5092 int e = errno;
5094 errno = 0;
5096 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
5098 errno = e;
5099 /* We don't want to mix heaps, so we duplicate the string in our
5100 heap and free the one allocated by the API. */
5101 retval = xstrdup (str_acl);
5102 if (size)
5103 *size = local_size;
5104 LocalFree (str_acl);
5106 else if (errno != ENOTSUP)
5107 errno = EINVAL;
5109 return retval;
5112 acl_t
5113 acl_from_text (const char *acl_str)
5115 PSECURITY_DESCRIPTOR psd, retval = NULL;
5116 ULONG sd_size;
5117 int e = errno;
5119 errno = 0;
5121 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
5123 errno = e;
5124 retval = xmalloc (sd_size);
5125 memcpy (retval, psd, sd_size);
5126 LocalFree (psd);
5128 else if (errno != ENOTSUP)
5129 errno = EINVAL;
5131 return retval;
5135 acl_free (void *ptr)
5137 xfree (ptr);
5138 return 0;
5141 acl_t
5142 acl_get_file (const char *fname, acl_type_t type)
5144 PSECURITY_DESCRIPTOR psd = NULL;
5145 const char *filename;
5147 if (type == ACL_TYPE_ACCESS)
5149 DWORD sd_len, err;
5150 SECURITY_INFORMATION si =
5151 OWNER_SECURITY_INFORMATION |
5152 GROUP_SECURITY_INFORMATION |
5153 DACL_SECURITY_INFORMATION ;
5154 int e = errno;
5156 filename = map_w32_filename (fname, NULL);
5157 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5158 fname = chase_symlinks (filename);
5159 else
5160 fname = filename;
5162 errno = 0;
5163 if (!get_file_security (fname, si, psd, 0, &sd_len)
5164 && errno != ENOTSUP)
5166 err = GetLastError ();
5167 if (err == ERROR_INSUFFICIENT_BUFFER)
5169 psd = xmalloc (sd_len);
5170 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
5172 xfree (psd);
5173 errno = EIO;
5174 psd = NULL;
5177 else if (err == ERROR_FILE_NOT_FOUND
5178 || err == ERROR_PATH_NOT_FOUND)
5179 errno = ENOENT;
5180 else
5181 errno = EIO;
5183 else if (!errno)
5184 errno = e;
5186 else if (type != ACL_TYPE_DEFAULT)
5187 errno = EINVAL;
5189 return psd;
5193 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
5195 TOKEN_PRIVILEGES old1, old2;
5196 DWORD err;
5197 int st = 0, retval = -1;
5198 SECURITY_INFORMATION flags = 0;
5199 PSID psid;
5200 PACL pacl;
5201 BOOL dflt;
5202 BOOL dacl_present;
5203 int e;
5204 const char *filename;
5206 if (acl_valid (acl) != 0
5207 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
5209 errno = EINVAL;
5210 return -1;
5213 if (type == ACL_TYPE_DEFAULT)
5215 errno = ENOSYS;
5216 return -1;
5219 filename = map_w32_filename (fname, NULL);
5220 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5221 fname = chase_symlinks (filename);
5222 else
5223 fname = filename;
5225 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
5226 && psid)
5227 flags |= OWNER_SECURITY_INFORMATION;
5228 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
5229 && psid)
5230 flags |= GROUP_SECURITY_INFORMATION;
5231 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
5232 &pacl, &dflt)
5233 && dacl_present)
5234 flags |= DACL_SECURITY_INFORMATION;
5235 if (!flags)
5236 return 0;
5238 /* According to KB-245153, setting the owner will succeed if either:
5239 (1) the caller is the user who will be the new owner, and has the
5240 SE_TAKE_OWNERSHIP privilege, or
5241 (2) the caller has the SE_RESTORE privilege, in which case she can
5242 set any valid user or group as the owner
5244 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5245 privileges, and disregard any failures in obtaining them. If
5246 these privileges cannot be obtained, and do not already exist in
5247 the calling thread's security token, this function could fail
5248 with EPERM. */
5249 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
5250 st++;
5251 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
5252 st++;
5254 e = errno;
5255 errno = 0;
5256 if (!set_file_security ((char *)fname, flags, (PSECURITY_DESCRIPTOR)acl))
5258 err = GetLastError ();
5260 if (errno == ENOTSUP)
5262 else if (err == ERROR_INVALID_OWNER
5263 || err == ERROR_NOT_ALL_ASSIGNED
5264 || err == ERROR_ACCESS_DENIED)
5266 /* Maybe the requested ACL and the one the file already has
5267 are identical, in which case we can silently ignore the
5268 failure. (And no, Windows doesn't.) */
5269 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
5271 errno = EPERM;
5272 if (current_acl)
5274 char *acl_from = acl_to_text (current_acl, NULL);
5275 char *acl_to = acl_to_text (acl, NULL);
5277 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
5279 retval = 0;
5280 errno = e;
5282 if (acl_from)
5283 acl_free (acl_from);
5284 if (acl_to)
5285 acl_free (acl_to);
5286 acl_free (current_acl);
5289 else if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
5290 errno = ENOENT;
5291 else
5292 errno = EACCES;
5294 else
5296 retval = 0;
5297 errno = e;
5300 if (st)
5302 if (st >= 2)
5303 restore_privilege (&old2);
5304 restore_privilege (&old1);
5305 revert_to_self ();
5308 return retval;
5312 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5313 have a fixed max size for file names, so we don't need the kind of
5314 alloc/malloc/realloc dance the gnulib version does. We also don't
5315 support FD-relative symlinks. */
5316 char *
5317 careadlinkat (int fd, char const *filename,
5318 char *buffer, size_t buffer_size,
5319 struct allocator const *alloc,
5320 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
5322 char linkname[MAX_PATH];
5323 ssize_t link_size;
5325 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
5327 if (link_size > 0)
5329 char *retval = buffer;
5331 linkname[link_size++] = '\0';
5332 if (link_size > buffer_size)
5333 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
5334 if (retval)
5335 memcpy (retval, linkname, link_size);
5337 return retval;
5339 return NULL;
5343 /* Support for browsing other processes and their attributes. See
5344 process.c for the Lisp bindings. */
5346 /* Helper wrapper functions. */
5348 static HANDLE WINAPI
5349 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
5351 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
5353 if (g_b_init_create_toolhelp32_snapshot == 0)
5355 g_b_init_create_toolhelp32_snapshot = 1;
5356 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
5357 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5358 "CreateToolhelp32Snapshot");
5360 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
5362 return INVALID_HANDLE_VALUE;
5364 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
5367 static BOOL WINAPI
5368 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
5370 static Process32First_Proc s_pfn_Process32_First = NULL;
5372 if (g_b_init_process32_first == 0)
5374 g_b_init_process32_first = 1;
5375 s_pfn_Process32_First = (Process32First_Proc)
5376 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5377 "Process32First");
5379 if (s_pfn_Process32_First == NULL)
5381 return FALSE;
5383 return (s_pfn_Process32_First (hSnapshot, lppe));
5386 static BOOL WINAPI
5387 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
5389 static Process32Next_Proc s_pfn_Process32_Next = NULL;
5391 if (g_b_init_process32_next == 0)
5393 g_b_init_process32_next = 1;
5394 s_pfn_Process32_Next = (Process32Next_Proc)
5395 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5396 "Process32Next");
5398 if (s_pfn_Process32_Next == NULL)
5400 return FALSE;
5402 return (s_pfn_Process32_Next (hSnapshot, lppe));
5405 static BOOL WINAPI
5406 open_thread_token (HANDLE ThreadHandle,
5407 DWORD DesiredAccess,
5408 BOOL OpenAsSelf,
5409 PHANDLE TokenHandle)
5411 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
5412 HMODULE hm_advapi32 = NULL;
5413 if (is_windows_9x () == TRUE)
5415 SetLastError (ERROR_NOT_SUPPORTED);
5416 return FALSE;
5418 if (g_b_init_open_thread_token == 0)
5420 g_b_init_open_thread_token = 1;
5421 hm_advapi32 = LoadLibrary ("Advapi32.dll");
5422 s_pfn_Open_Thread_Token =
5423 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
5425 if (s_pfn_Open_Thread_Token == NULL)
5427 SetLastError (ERROR_NOT_SUPPORTED);
5428 return FALSE;
5430 return (
5431 s_pfn_Open_Thread_Token (
5432 ThreadHandle,
5433 DesiredAccess,
5434 OpenAsSelf,
5435 TokenHandle)
5439 static BOOL WINAPI
5440 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
5442 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
5443 HMODULE hm_advapi32 = NULL;
5444 if (is_windows_9x () == TRUE)
5446 return FALSE;
5448 if (g_b_init_impersonate_self == 0)
5450 g_b_init_impersonate_self = 1;
5451 hm_advapi32 = LoadLibrary ("Advapi32.dll");
5452 s_pfn_Impersonate_Self =
5453 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
5455 if (s_pfn_Impersonate_Self == NULL)
5457 return FALSE;
5459 return s_pfn_Impersonate_Self (ImpersonationLevel);
5462 static BOOL WINAPI
5463 revert_to_self (void)
5465 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
5466 HMODULE hm_advapi32 = NULL;
5467 if (is_windows_9x () == TRUE)
5469 return FALSE;
5471 if (g_b_init_revert_to_self == 0)
5473 g_b_init_revert_to_self = 1;
5474 hm_advapi32 = LoadLibrary ("Advapi32.dll");
5475 s_pfn_Revert_To_Self =
5476 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
5478 if (s_pfn_Revert_To_Self == NULL)
5480 return FALSE;
5482 return s_pfn_Revert_To_Self ();
5485 static BOOL WINAPI
5486 get_process_memory_info (HANDLE h_proc,
5487 PPROCESS_MEMORY_COUNTERS mem_counters,
5488 DWORD bufsize)
5490 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
5491 HMODULE hm_psapi = NULL;
5492 if (is_windows_9x () == TRUE)
5494 return FALSE;
5496 if (g_b_init_get_process_memory_info == 0)
5498 g_b_init_get_process_memory_info = 1;
5499 hm_psapi = LoadLibrary ("Psapi.dll");
5500 if (hm_psapi)
5501 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
5502 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
5504 if (s_pfn_Get_Process_Memory_Info == NULL)
5506 return FALSE;
5508 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
5511 static BOOL WINAPI
5512 get_process_working_set_size (HANDLE h_proc,
5513 PSIZE_T minrss,
5514 PSIZE_T maxrss)
5516 static GetProcessWorkingSetSize_Proc
5517 s_pfn_Get_Process_Working_Set_Size = NULL;
5519 if (is_windows_9x () == TRUE)
5521 return FALSE;
5523 if (g_b_init_get_process_working_set_size == 0)
5525 g_b_init_get_process_working_set_size = 1;
5526 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
5527 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5528 "GetProcessWorkingSetSize");
5530 if (s_pfn_Get_Process_Working_Set_Size == NULL)
5532 return FALSE;
5534 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
5537 static BOOL WINAPI
5538 global_memory_status (MEMORYSTATUS *buf)
5540 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
5542 if (is_windows_9x () == TRUE)
5544 return FALSE;
5546 if (g_b_init_global_memory_status == 0)
5548 g_b_init_global_memory_status = 1;
5549 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
5550 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5551 "GlobalMemoryStatus");
5553 if (s_pfn_Global_Memory_Status == NULL)
5555 return FALSE;
5557 return s_pfn_Global_Memory_Status (buf);
5560 static BOOL WINAPI
5561 global_memory_status_ex (MEMORY_STATUS_EX *buf)
5563 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
5565 if (is_windows_9x () == TRUE)
5567 return FALSE;
5569 if (g_b_init_global_memory_status_ex == 0)
5571 g_b_init_global_memory_status_ex = 1;
5572 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
5573 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5574 "GlobalMemoryStatusEx");
5576 if (s_pfn_Global_Memory_Status_Ex == NULL)
5578 return FALSE;
5580 return s_pfn_Global_Memory_Status_Ex (buf);
5583 Lisp_Object
5584 list_system_processes (void)
5586 struct gcpro gcpro1;
5587 Lisp_Object proclist = Qnil;
5588 HANDLE h_snapshot;
5590 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
5592 if (h_snapshot != INVALID_HANDLE_VALUE)
5594 PROCESSENTRY32 proc_entry;
5595 DWORD proc_id;
5596 BOOL res;
5598 GCPRO1 (proclist);
5600 proc_entry.dwSize = sizeof (PROCESSENTRY32);
5601 for (res = process32_first (h_snapshot, &proc_entry); res;
5602 res = process32_next (h_snapshot, &proc_entry))
5604 proc_id = proc_entry.th32ProcessID;
5605 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
5608 CloseHandle (h_snapshot);
5609 UNGCPRO;
5610 proclist = Fnreverse (proclist);
5613 return proclist;
5616 static int
5617 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
5619 TOKEN_PRIVILEGES priv;
5620 DWORD priv_size = sizeof (priv);
5621 DWORD opriv_size = sizeof (*old_priv);
5622 HANDLE h_token = NULL;
5623 HANDLE h_thread = GetCurrentThread ();
5624 int ret_val = 0;
5625 BOOL res;
5627 res = open_thread_token (h_thread,
5628 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
5629 FALSE, &h_token);
5630 if (!res && GetLastError () == ERROR_NO_TOKEN)
5632 if (impersonate_self (SecurityImpersonation))
5633 res = open_thread_token (h_thread,
5634 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
5635 FALSE, &h_token);
5637 if (res)
5639 priv.PrivilegeCount = 1;
5640 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
5641 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
5642 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
5643 old_priv, &opriv_size)
5644 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
5645 ret_val = 1;
5647 if (h_token)
5648 CloseHandle (h_token);
5650 return ret_val;
5653 static int
5654 restore_privilege (TOKEN_PRIVILEGES *priv)
5656 DWORD priv_size = sizeof (*priv);
5657 HANDLE h_token = NULL;
5658 int ret_val = 0;
5660 if (open_thread_token (GetCurrentThread (),
5661 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
5662 FALSE, &h_token))
5664 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
5665 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
5666 ret_val = 1;
5668 if (h_token)
5669 CloseHandle (h_token);
5671 return ret_val;
5674 static Lisp_Object
5675 ltime (ULONGLONG time_100ns)
5677 ULONGLONG time_sec = time_100ns / 10000000;
5678 int subsec = time_100ns % 10000000;
5679 return list4i (time_sec >> 16, time_sec & 0xffff,
5680 subsec / 10, subsec % 10 * 100000);
5683 #define U64_TO_LISP_TIME(time) ltime (time)
5685 static int
5686 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
5687 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
5688 double *pcpu)
5690 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
5691 ULONGLONG tem1, tem2, tem3, tem;
5693 if (!h_proc
5694 || !get_process_times_fn
5695 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
5696 &ft_kernel, &ft_user))
5697 return 0;
5699 GetSystemTimeAsFileTime (&ft_current);
5701 FILETIME_TO_U64 (tem1, ft_kernel);
5702 *stime = U64_TO_LISP_TIME (tem1);
5704 FILETIME_TO_U64 (tem2, ft_user);
5705 *utime = U64_TO_LISP_TIME (tem2);
5707 tem3 = tem1 + tem2;
5708 *ttime = U64_TO_LISP_TIME (tem3);
5710 FILETIME_TO_U64 (tem, ft_creation);
5711 /* Process no 4 (System) returns zero creation time. */
5712 if (tem)
5713 tem -= utc_base;
5714 *ctime = U64_TO_LISP_TIME (tem);
5716 if (tem)
5718 FILETIME_TO_U64 (tem3, ft_current);
5719 tem = (tem3 - utc_base) - tem;
5721 *etime = U64_TO_LISP_TIME (tem);
5723 if (tem)
5725 *pcpu = 100.0 * (tem1 + tem2) / tem;
5726 if (*pcpu > 100)
5727 *pcpu = 100.0;
5729 else
5730 *pcpu = 0;
5732 return 1;
5735 Lisp_Object
5736 system_process_attributes (Lisp_Object pid)
5738 struct gcpro gcpro1, gcpro2, gcpro3;
5739 Lisp_Object attrs = Qnil;
5740 Lisp_Object cmd_str, decoded_cmd, tem;
5741 HANDLE h_snapshot, h_proc;
5742 DWORD proc_id;
5743 int found_proc = 0;
5744 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
5745 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
5746 DWORD glength = sizeof (gname);
5747 HANDLE token = NULL;
5748 SID_NAME_USE user_type;
5749 unsigned char *buf = NULL;
5750 DWORD blen = 0;
5751 TOKEN_USER user_token;
5752 TOKEN_PRIMARY_GROUP group_token;
5753 unsigned euid;
5754 unsigned egid;
5755 PROCESS_MEMORY_COUNTERS mem;
5756 PROCESS_MEMORY_COUNTERS_EX mem_ex;
5757 SIZE_T minrss, maxrss;
5758 MEMORYSTATUS memst;
5759 MEMORY_STATUS_EX memstex;
5760 double totphys = 0.0;
5761 Lisp_Object ctime, stime, utime, etime, ttime;
5762 double pcpu;
5763 BOOL result = FALSE;
5765 CHECK_NUMBER_OR_FLOAT (pid);
5766 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
5768 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
5770 GCPRO3 (attrs, decoded_cmd, tem);
5772 if (h_snapshot != INVALID_HANDLE_VALUE)
5774 PROCESSENTRY32 pe;
5775 BOOL res;
5777 pe.dwSize = sizeof (PROCESSENTRY32);
5778 for (res = process32_first (h_snapshot, &pe); res;
5779 res = process32_next (h_snapshot, &pe))
5781 if (proc_id == pe.th32ProcessID)
5783 if (proc_id == 0)
5784 decoded_cmd = build_string ("Idle");
5785 else
5787 /* Decode the command name from locale-specific
5788 encoding. */
5789 cmd_str = build_unibyte_string (pe.szExeFile);
5791 decoded_cmd =
5792 code_convert_string_norecord (cmd_str,
5793 Vlocale_coding_system, 0);
5795 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
5796 attrs = Fcons (Fcons (Qppid,
5797 make_fixnum_or_float (pe.th32ParentProcessID)),
5798 attrs);
5799 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
5800 attrs);
5801 attrs = Fcons (Fcons (Qthcount,
5802 make_fixnum_or_float (pe.cntThreads)),
5803 attrs);
5804 found_proc = 1;
5805 break;
5809 CloseHandle (h_snapshot);
5812 if (!found_proc)
5814 UNGCPRO;
5815 return Qnil;
5818 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
5819 FALSE, proc_id);
5820 /* If we were denied a handle to the process, try again after
5821 enabling the SeDebugPrivilege in our process. */
5822 if (!h_proc)
5824 TOKEN_PRIVILEGES priv_current;
5826 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
5828 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
5829 FALSE, proc_id);
5830 restore_privilege (&priv_current);
5831 revert_to_self ();
5834 if (h_proc)
5836 result = open_process_token (h_proc, TOKEN_QUERY, &token);
5837 if (result)
5839 result = get_token_information (token, TokenUser, NULL, 0, &blen);
5840 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
5842 buf = xmalloc (blen);
5843 result = get_token_information (token, TokenUser,
5844 (LPVOID)buf, blen, &needed);
5845 if (result)
5847 memcpy (&user_token, buf, sizeof (user_token));
5848 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
5850 euid = get_rid (user_token.User.Sid);
5851 result = lookup_account_sid (NULL, user_token.User.Sid,
5852 uname, &ulength,
5853 domain, &dlength,
5854 &user_type);
5855 if (result)
5856 w32_add_to_cache (user_token.User.Sid, euid, uname);
5857 else
5859 strcpy (uname, "unknown");
5860 result = TRUE;
5863 ulength = strlen (uname);
5867 if (result)
5869 /* Determine a reasonable euid and gid values. */
5870 if (xstrcasecmp ("administrator", uname) == 0)
5872 euid = 500; /* well-known Administrator uid */
5873 egid = 513; /* well-known None gid */
5875 else
5877 /* Get group id and name. */
5878 result = get_token_information (token, TokenPrimaryGroup,
5879 (LPVOID)buf, blen, &needed);
5880 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
5882 buf = xrealloc (buf, blen = needed);
5883 result = get_token_information (token, TokenPrimaryGroup,
5884 (LPVOID)buf, blen, &needed);
5886 if (result)
5888 memcpy (&group_token, buf, sizeof (group_token));
5889 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
5891 egid = get_rid (group_token.PrimaryGroup);
5892 dlength = sizeof (domain);
5893 result =
5894 lookup_account_sid (NULL, group_token.PrimaryGroup,
5895 gname, &glength, NULL, &dlength,
5896 &user_type);
5897 if (result)
5898 w32_add_to_cache (group_token.PrimaryGroup,
5899 egid, gname);
5900 else
5902 strcpy (gname, "None");
5903 result = TRUE;
5906 glength = strlen (gname);
5910 xfree (buf);
5912 if (!result)
5914 if (!is_windows_9x ())
5916 /* We couldn't open the process token, presumably because of
5917 insufficient access rights. Assume this process is run
5918 by the system. */
5919 strcpy (uname, "SYSTEM");
5920 strcpy (gname, "None");
5921 euid = 18; /* SYSTEM */
5922 egid = 513; /* None */
5923 glength = strlen (gname);
5924 ulength = strlen (uname);
5926 /* If we are running under Windows 9X, where security calls are
5927 not supported, we assume all processes are run by the current
5928 user. */
5929 else if (GetUserName (uname, &ulength))
5931 if (xstrcasecmp ("administrator", uname) == 0)
5932 euid = 0;
5933 else
5934 euid = 123;
5935 egid = euid;
5936 strcpy (gname, "None");
5937 glength = strlen (gname);
5938 ulength = strlen (uname);
5940 else
5942 euid = 123;
5943 egid = 123;
5944 strcpy (uname, "administrator");
5945 ulength = strlen (uname);
5946 strcpy (gname, "None");
5947 glength = strlen (gname);
5949 if (token)
5950 CloseHandle (token);
5953 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
5954 tem = make_unibyte_string (uname, ulength);
5955 attrs = Fcons (Fcons (Quser,
5956 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
5957 attrs);
5958 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
5959 tem = make_unibyte_string (gname, glength);
5960 attrs = Fcons (Fcons (Qgroup,
5961 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
5962 attrs);
5964 if (global_memory_status_ex (&memstex))
5965 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
5966 totphys = memstex.ullTotalPhys / 1024.0;
5967 #else
5968 /* Visual Studio 6 cannot convert an unsigned __int64 type to
5969 double, so we need to do this for it... */
5971 DWORD tot_hi = memstex.ullTotalPhys >> 32;
5972 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
5973 DWORD tot_lo = memstex.ullTotalPhys % 1024;
5975 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
5977 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5978 else if (global_memory_status (&memst))
5979 totphys = memst.dwTotalPhys / 1024.0;
5981 if (h_proc
5982 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
5983 sizeof (mem_ex)))
5985 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
5987 attrs = Fcons (Fcons (Qmajflt,
5988 make_fixnum_or_float (mem_ex.PageFaultCount)),
5989 attrs);
5990 attrs = Fcons (Fcons (Qvsize,
5991 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
5992 attrs);
5993 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
5994 if (totphys)
5995 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
5997 else if (h_proc
5998 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
6000 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6002 attrs = Fcons (Fcons (Qmajflt,
6003 make_fixnum_or_float (mem.PageFaultCount)),
6004 attrs);
6005 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6006 if (totphys)
6007 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6009 else if (h_proc
6010 && get_process_working_set_size (h_proc, &minrss, &maxrss))
6012 DWORD rss = maxrss / 1024;
6014 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
6015 if (totphys)
6016 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6019 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
6021 attrs = Fcons (Fcons (Qutime, utime), attrs);
6022 attrs = Fcons (Fcons (Qstime, stime), attrs);
6023 attrs = Fcons (Fcons (Qtime, ttime), attrs);
6024 attrs = Fcons (Fcons (Qstart, ctime), attrs);
6025 attrs = Fcons (Fcons (Qetime, etime), attrs);
6026 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
6029 /* FIXME: Retrieve command line by walking the PEB of the process. */
6031 if (h_proc)
6032 CloseHandle (h_proc);
6033 UNGCPRO;
6034 return attrs;
6038 /* Wrappers for winsock functions to map between our file descriptors
6039 and winsock's handles; also set h_errno for convenience.
6041 To allow Emacs to run on systems which don't have winsock support
6042 installed, we dynamically link to winsock on startup if present, and
6043 otherwise provide the minimum necessary functionality
6044 (eg. gethostname). */
6046 /* function pointers for relevant socket functions */
6047 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
6048 void (PASCAL *pfn_WSASetLastError) (int iError);
6049 int (PASCAL *pfn_WSAGetLastError) (void);
6050 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
6051 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
6052 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
6053 int (PASCAL *pfn_socket) (int af, int type, int protocol);
6054 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
6055 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
6056 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
6057 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
6058 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
6059 int (PASCAL *pfn_closesocket) (SOCKET s);
6060 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
6061 int (PASCAL *pfn_WSACleanup) (void);
6063 u_short (PASCAL *pfn_htons) (u_short hostshort);
6064 u_short (PASCAL *pfn_ntohs) (u_short netshort);
6065 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
6066 int (PASCAL *pfn_gethostname) (char * name, int namelen);
6067 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
6068 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
6069 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
6070 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
6071 const char * optval, int optlen);
6072 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
6073 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
6074 int * namelen);
6075 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
6076 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
6077 struct sockaddr * from, int * fromlen);
6078 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
6079 const struct sockaddr * to, int tolen);
6081 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6082 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
6083 #ifndef HANDLE_FLAG_INHERIT
6084 #define HANDLE_FLAG_INHERIT 1
6085 #endif
6087 HANDLE winsock_lib;
6088 static int winsock_inuse;
6090 BOOL
6091 term_winsock (void)
6093 if (winsock_lib != NULL && winsock_inuse == 0)
6095 release_listen_threads ();
6096 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6097 after WSAStartup returns successfully, but it seems reasonable
6098 to allow unloading winsock anyway in that case. */
6099 if (pfn_WSACleanup () == 0 ||
6100 pfn_WSAGetLastError () == WSAENETDOWN)
6102 if (FreeLibrary (winsock_lib))
6103 winsock_lib = NULL;
6104 return TRUE;
6107 return FALSE;
6110 BOOL
6111 init_winsock (int load_now)
6113 WSADATA winsockData;
6115 if (winsock_lib != NULL)
6116 return TRUE;
6118 pfn_SetHandleInformation
6119 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6120 "SetHandleInformation");
6122 winsock_lib = LoadLibrary ("Ws2_32.dll");
6124 if (winsock_lib != NULL)
6126 /* dynamically link to socket functions */
6128 #define LOAD_PROC(fn) \
6129 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6130 goto fail;
6132 LOAD_PROC (WSAStartup);
6133 LOAD_PROC (WSASetLastError);
6134 LOAD_PROC (WSAGetLastError);
6135 LOAD_PROC (WSAEventSelect);
6136 LOAD_PROC (WSACreateEvent);
6137 LOAD_PROC (WSACloseEvent);
6138 LOAD_PROC (socket);
6139 LOAD_PROC (bind);
6140 LOAD_PROC (connect);
6141 LOAD_PROC (ioctlsocket);
6142 LOAD_PROC (recv);
6143 LOAD_PROC (send);
6144 LOAD_PROC (closesocket);
6145 LOAD_PROC (shutdown);
6146 LOAD_PROC (htons);
6147 LOAD_PROC (ntohs);
6148 LOAD_PROC (inet_addr);
6149 LOAD_PROC (gethostname);
6150 LOAD_PROC (gethostbyname);
6151 LOAD_PROC (getservbyname);
6152 LOAD_PROC (getpeername);
6153 LOAD_PROC (WSACleanup);
6154 LOAD_PROC (setsockopt);
6155 LOAD_PROC (listen);
6156 LOAD_PROC (getsockname);
6157 LOAD_PROC (accept);
6158 LOAD_PROC (recvfrom);
6159 LOAD_PROC (sendto);
6160 #undef LOAD_PROC
6162 /* specify version 1.1 of winsock */
6163 if (pfn_WSAStartup (0x101, &winsockData) == 0)
6165 if (winsockData.wVersion != 0x101)
6166 goto fail;
6168 if (!load_now)
6170 /* Report that winsock exists and is usable, but leave
6171 socket functions disabled. I am assuming that calling
6172 WSAStartup does not require any network interaction,
6173 and in particular does not cause or require a dial-up
6174 connection to be established. */
6176 pfn_WSACleanup ();
6177 FreeLibrary (winsock_lib);
6178 winsock_lib = NULL;
6180 winsock_inuse = 0;
6181 return TRUE;
6184 fail:
6185 FreeLibrary (winsock_lib);
6186 winsock_lib = NULL;
6189 return FALSE;
6193 int h_errno = 0;
6195 /* Function to map winsock error codes to errno codes for those errno
6196 code defined in errno.h (errno values not defined by errno.h are
6197 already in nt/inc/sys/socket.h). */
6198 static void
6199 set_errno (void)
6201 int wsa_err;
6203 h_errno = 0;
6204 if (winsock_lib == NULL)
6205 wsa_err = EINVAL;
6206 else
6207 wsa_err = pfn_WSAGetLastError ();
6209 switch (wsa_err)
6211 case WSAEACCES: errno = EACCES; break;
6212 case WSAEBADF: errno = EBADF; break;
6213 case WSAEFAULT: errno = EFAULT; break;
6214 case WSAEINTR: errno = EINTR; break;
6215 case WSAEINVAL: errno = EINVAL; break;
6216 case WSAEMFILE: errno = EMFILE; break;
6217 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
6218 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
6219 default: errno = wsa_err; break;
6223 static void
6224 check_errno (void)
6226 h_errno = 0;
6227 if (winsock_lib != NULL)
6228 pfn_WSASetLastError (0);
6231 /* Extend strerror to handle the winsock-specific error codes. */
6232 struct {
6233 int errnum;
6234 char * msg;
6235 } _wsa_errlist[] = {
6236 {WSAEINTR , "Interrupted function call"},
6237 {WSAEBADF , "Bad file descriptor"},
6238 {WSAEACCES , "Permission denied"},
6239 {WSAEFAULT , "Bad address"},
6240 {WSAEINVAL , "Invalid argument"},
6241 {WSAEMFILE , "Too many open files"},
6243 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
6244 {WSAEINPROGRESS , "Operation now in progress"},
6245 {WSAEALREADY , "Operation already in progress"},
6246 {WSAENOTSOCK , "Socket operation on non-socket"},
6247 {WSAEDESTADDRREQ , "Destination address required"},
6248 {WSAEMSGSIZE , "Message too long"},
6249 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
6250 {WSAENOPROTOOPT , "Bad protocol option"},
6251 {WSAEPROTONOSUPPORT , "Protocol not supported"},
6252 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
6253 {WSAEOPNOTSUPP , "Operation not supported"},
6254 {WSAEPFNOSUPPORT , "Protocol family not supported"},
6255 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
6256 {WSAEADDRINUSE , "Address already in use"},
6257 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
6258 {WSAENETDOWN , "Network is down"},
6259 {WSAENETUNREACH , "Network is unreachable"},
6260 {WSAENETRESET , "Network dropped connection on reset"},
6261 {WSAECONNABORTED , "Software caused connection abort"},
6262 {WSAECONNRESET , "Connection reset by peer"},
6263 {WSAENOBUFS , "No buffer space available"},
6264 {WSAEISCONN , "Socket is already connected"},
6265 {WSAENOTCONN , "Socket is not connected"},
6266 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
6267 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
6268 {WSAETIMEDOUT , "Connection timed out"},
6269 {WSAECONNREFUSED , "Connection refused"},
6270 {WSAELOOP , "Network loop"}, /* not sure */
6271 {WSAENAMETOOLONG , "Name is too long"},
6272 {WSAEHOSTDOWN , "Host is down"},
6273 {WSAEHOSTUNREACH , "No route to host"},
6274 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
6275 {WSAEPROCLIM , "Too many processes"},
6276 {WSAEUSERS , "Too many users"}, /* not sure */
6277 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
6278 {WSAESTALE , "Data is stale"}, /* not sure */
6279 {WSAEREMOTE , "Remote error"}, /* not sure */
6281 {WSASYSNOTREADY , "Network subsystem is unavailable"},
6282 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
6283 {WSANOTINITIALISED , "Winsock not initialized successfully"},
6284 {WSAEDISCON , "Graceful shutdown in progress"},
6285 #ifdef WSAENOMORE
6286 {WSAENOMORE , "No more operations allowed"}, /* not sure */
6287 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
6288 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
6289 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
6290 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
6291 {WSASYSCALLFAILURE , "System call failure"},
6292 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
6293 {WSATYPE_NOT_FOUND , "Class type not found"},
6294 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
6295 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
6296 {WSAEREFUSED , "Operation refused"}, /* not sure */
6297 #endif
6299 {WSAHOST_NOT_FOUND , "Host not found"},
6300 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
6301 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
6302 {WSANO_DATA , "Valid name, no data record of requested type"},
6304 {-1, NULL}
6307 char *
6308 sys_strerror (int error_no)
6310 int i;
6311 static char unknown_msg[40];
6313 if (error_no >= 0 && error_no < sys_nerr)
6314 return sys_errlist[error_no];
6316 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
6317 if (_wsa_errlist[i].errnum == error_no)
6318 return _wsa_errlist[i].msg;
6320 sprintf (unknown_msg, "Unidentified error: %d", error_no);
6321 return unknown_msg;
6324 /* [andrewi 3-May-96] I've had conflicting results using both methods,
6325 but I believe the method of keeping the socket handle separate (and
6326 insuring it is not inheritable) is the correct one. */
6328 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
6330 static int socket_to_fd (SOCKET s);
6333 sys_socket (int af, int type, int protocol)
6335 SOCKET s;
6337 if (winsock_lib == NULL)
6339 errno = ENETDOWN;
6340 return INVALID_SOCKET;
6343 check_errno ();
6345 /* call the real socket function */
6346 s = pfn_socket (af, type, protocol);
6348 if (s != INVALID_SOCKET)
6349 return socket_to_fd (s);
6351 set_errno ();
6352 return -1;
6355 /* Convert a SOCKET to a file descriptor. */
6356 static int
6357 socket_to_fd (SOCKET s)
6359 int fd;
6360 child_process * cp;
6362 /* Although under NT 3.5 _open_osfhandle will accept a socket
6363 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
6364 that does not work under NT 3.1. However, we can get the same
6365 effect by using a backdoor function to replace an existing
6366 descriptor handle with the one we want. */
6368 /* allocate a file descriptor (with appropriate flags) */
6369 fd = _open ("NUL:", _O_RDWR);
6370 if (fd >= 0)
6372 /* Make a non-inheritable copy of the socket handle. Note
6373 that it is possible that sockets aren't actually kernel
6374 handles, which appears to be the case on Windows 9x when
6375 the MS Proxy winsock client is installed. */
6377 /* Apparently there is a bug in NT 3.51 with some service
6378 packs, which prevents using DuplicateHandle to make a
6379 socket handle non-inheritable (causes WSACleanup to
6380 hang). The work-around is to use SetHandleInformation
6381 instead if it is available and implemented. */
6382 if (pfn_SetHandleInformation)
6384 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
6386 else
6388 HANDLE parent = GetCurrentProcess ();
6389 HANDLE new_s = INVALID_HANDLE_VALUE;
6391 if (DuplicateHandle (parent,
6392 (HANDLE) s,
6393 parent,
6394 &new_s,
6396 FALSE,
6397 DUPLICATE_SAME_ACCESS))
6399 /* It is possible that DuplicateHandle succeeds even
6400 though the socket wasn't really a kernel handle,
6401 because a real handle has the same value. So
6402 test whether the new handle really is a socket. */
6403 long nonblocking = 0;
6404 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
6406 pfn_closesocket (s);
6407 s = (SOCKET) new_s;
6409 else
6411 CloseHandle (new_s);
6416 eassert (fd < MAXDESC);
6417 fd_info[fd].hnd = (HANDLE) s;
6419 /* set our own internal flags */
6420 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
6422 cp = new_child ();
6423 if (cp)
6425 cp->fd = fd;
6426 cp->status = STATUS_READ_ACKNOWLEDGED;
6428 /* attach child_process to fd_info */
6429 if (fd_info[ fd ].cp != NULL)
6431 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
6432 emacs_abort ();
6435 fd_info[ fd ].cp = cp;
6437 /* success! */
6438 winsock_inuse++; /* count open sockets */
6439 return fd;
6442 /* clean up */
6443 _close (fd);
6445 else
6446 pfn_closesocket (s);
6447 errno = EMFILE;
6448 return -1;
6452 sys_bind (int s, const struct sockaddr * addr, int namelen)
6454 if (winsock_lib == NULL)
6456 errno = ENOTSOCK;
6457 return SOCKET_ERROR;
6460 check_errno ();
6461 if (fd_info[s].flags & FILE_SOCKET)
6463 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
6464 if (rc == SOCKET_ERROR)
6465 set_errno ();
6466 return rc;
6468 errno = ENOTSOCK;
6469 return SOCKET_ERROR;
6473 sys_connect (int s, const struct sockaddr * name, int namelen)
6475 if (winsock_lib == NULL)
6477 errno = ENOTSOCK;
6478 return SOCKET_ERROR;
6481 check_errno ();
6482 if (fd_info[s].flags & FILE_SOCKET)
6484 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
6485 if (rc == SOCKET_ERROR)
6486 set_errno ();
6487 return rc;
6489 errno = ENOTSOCK;
6490 return SOCKET_ERROR;
6493 u_short
6494 sys_htons (u_short hostshort)
6496 return (winsock_lib != NULL) ?
6497 pfn_htons (hostshort) : hostshort;
6500 u_short
6501 sys_ntohs (u_short netshort)
6503 return (winsock_lib != NULL) ?
6504 pfn_ntohs (netshort) : netshort;
6507 unsigned long
6508 sys_inet_addr (const char * cp)
6510 return (winsock_lib != NULL) ?
6511 pfn_inet_addr (cp) : INADDR_NONE;
6515 sys_gethostname (char * name, int namelen)
6517 if (winsock_lib != NULL)
6519 int retval;
6521 check_errno ();
6522 retval = pfn_gethostname (name, namelen);
6523 if (retval == SOCKET_ERROR)
6524 set_errno ();
6525 return retval;
6528 if (namelen > MAX_COMPUTERNAME_LENGTH)
6529 return !GetComputerName (name, (DWORD *)&namelen);
6531 errno = EFAULT;
6532 return SOCKET_ERROR;
6535 struct hostent *
6536 sys_gethostbyname (const char * name)
6538 struct hostent * host;
6539 int h_err = h_errno;
6541 if (winsock_lib == NULL)
6543 h_errno = NO_RECOVERY;
6544 errno = ENETDOWN;
6545 return NULL;
6548 check_errno ();
6549 host = pfn_gethostbyname (name);
6550 if (!host)
6552 set_errno ();
6553 h_errno = errno;
6555 else
6556 h_errno = h_err;
6557 return host;
6560 struct servent *
6561 sys_getservbyname (const char * name, const char * proto)
6563 struct servent * serv;
6565 if (winsock_lib == NULL)
6567 errno = ENETDOWN;
6568 return NULL;
6571 check_errno ();
6572 serv = pfn_getservbyname (name, proto);
6573 if (!serv)
6574 set_errno ();
6575 return serv;
6579 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
6581 if (winsock_lib == NULL)
6583 errno = ENETDOWN;
6584 return SOCKET_ERROR;
6587 check_errno ();
6588 if (fd_info[s].flags & FILE_SOCKET)
6590 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
6591 if (rc == SOCKET_ERROR)
6592 set_errno ();
6593 return rc;
6595 errno = ENOTSOCK;
6596 return SOCKET_ERROR;
6600 sys_shutdown (int s, int how)
6602 if (winsock_lib == NULL)
6604 errno = ENETDOWN;
6605 return SOCKET_ERROR;
6608 check_errno ();
6609 if (fd_info[s].flags & FILE_SOCKET)
6611 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
6612 if (rc == SOCKET_ERROR)
6613 set_errno ();
6614 return rc;
6616 errno = ENOTSOCK;
6617 return SOCKET_ERROR;
6621 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
6623 if (winsock_lib == NULL)
6625 errno = ENETDOWN;
6626 return SOCKET_ERROR;
6629 check_errno ();
6630 if (fd_info[s].flags & FILE_SOCKET)
6632 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
6633 (const char *)optval, optlen);
6634 if (rc == SOCKET_ERROR)
6635 set_errno ();
6636 return rc;
6638 errno = ENOTSOCK;
6639 return SOCKET_ERROR;
6643 sys_listen (int s, int backlog)
6645 if (winsock_lib == NULL)
6647 errno = ENETDOWN;
6648 return SOCKET_ERROR;
6651 check_errno ();
6652 if (fd_info[s].flags & FILE_SOCKET)
6654 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
6655 if (rc == SOCKET_ERROR)
6656 set_errno ();
6657 else
6658 fd_info[s].flags |= FILE_LISTEN;
6659 return rc;
6661 errno = ENOTSOCK;
6662 return SOCKET_ERROR;
6666 sys_getsockname (int s, struct sockaddr * name, int * namelen)
6668 if (winsock_lib == NULL)
6670 errno = ENETDOWN;
6671 return SOCKET_ERROR;
6674 check_errno ();
6675 if (fd_info[s].flags & FILE_SOCKET)
6677 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
6678 if (rc == SOCKET_ERROR)
6679 set_errno ();
6680 return rc;
6682 errno = ENOTSOCK;
6683 return SOCKET_ERROR;
6687 sys_accept (int s, struct sockaddr * addr, int * addrlen)
6689 if (winsock_lib == NULL)
6691 errno = ENETDOWN;
6692 return -1;
6695 check_errno ();
6696 if (fd_info[s].flags & FILE_LISTEN)
6698 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
6699 int fd = -1;
6700 if (t == INVALID_SOCKET)
6701 set_errno ();
6702 else
6703 fd = socket_to_fd (t);
6705 if (fd >= 0)
6707 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
6708 ResetEvent (fd_info[s].cp->char_avail);
6710 return fd;
6712 errno = ENOTSOCK;
6713 return -1;
6717 sys_recvfrom (int s, char * buf, int len, int flags,
6718 struct sockaddr * from, int * fromlen)
6720 if (winsock_lib == NULL)
6722 errno = ENETDOWN;
6723 return SOCKET_ERROR;
6726 check_errno ();
6727 if (fd_info[s].flags & FILE_SOCKET)
6729 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
6730 if (rc == SOCKET_ERROR)
6731 set_errno ();
6732 return rc;
6734 errno = ENOTSOCK;
6735 return SOCKET_ERROR;
6739 sys_sendto (int s, const char * buf, int len, int flags,
6740 const struct sockaddr * to, int tolen)
6742 if (winsock_lib == NULL)
6744 errno = ENETDOWN;
6745 return SOCKET_ERROR;
6748 check_errno ();
6749 if (fd_info[s].flags & FILE_SOCKET)
6751 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
6752 if (rc == SOCKET_ERROR)
6753 set_errno ();
6754 return rc;
6756 errno = ENOTSOCK;
6757 return SOCKET_ERROR;
6760 /* Windows does not have an fcntl function. Provide an implementation
6761 good enough for Emacs. */
6763 fcntl (int s, int cmd, int options)
6765 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
6766 invoked in a context where fd1 is closed and all descriptors less
6767 than fd1 are open, so sys_dup is an adequate implementation. */
6768 if (cmd == F_DUPFD_CLOEXEC)
6769 return sys_dup (s);
6771 if (winsock_lib == NULL)
6773 errno = ENETDOWN;
6774 return -1;
6777 check_errno ();
6778 if (fd_info[s].flags & FILE_SOCKET)
6780 if (cmd == F_SETFL && options == O_NONBLOCK)
6782 unsigned long nblock = 1;
6783 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
6784 if (rc == SOCKET_ERROR)
6785 set_errno ();
6786 /* Keep track of the fact that we set this to non-blocking. */
6787 fd_info[s].flags |= FILE_NDELAY;
6788 return rc;
6790 else
6792 errno = EINVAL;
6793 return SOCKET_ERROR;
6796 errno = ENOTSOCK;
6797 return SOCKET_ERROR;
6801 /* Shadow main io functions: we need to handle pipes and sockets more
6802 intelligently, and implement non-blocking mode as well. */
6805 sys_close (int fd)
6807 int rc;
6809 if (fd < 0)
6811 errno = EBADF;
6812 return -1;
6815 if (fd < MAXDESC && fd_info[fd].cp)
6817 child_process * cp = fd_info[fd].cp;
6819 fd_info[fd].cp = NULL;
6821 if (CHILD_ACTIVE (cp))
6823 /* if last descriptor to active child_process then cleanup */
6824 int i;
6825 for (i = 0; i < MAXDESC; i++)
6827 if (i == fd)
6828 continue;
6829 if (fd_info[i].cp == cp)
6830 break;
6832 if (i == MAXDESC)
6834 if (fd_info[fd].flags & FILE_SOCKET)
6836 if (winsock_lib == NULL) emacs_abort ();
6838 pfn_shutdown (SOCK_HANDLE (fd), 2);
6839 rc = pfn_closesocket (SOCK_HANDLE (fd));
6841 winsock_inuse--; /* count open sockets */
6843 /* If the process handle is NULL, it's either a socket
6844 or serial connection, or a subprocess that was
6845 already reaped by reap_subprocess, but whose
6846 resources were not yet freed, because its output was
6847 not fully read yet by the time it was reaped. (This
6848 usually happens with async subprocesses whose output
6849 is being read by Emacs.) Otherwise, this process was
6850 not reaped yet, so we set its FD to a negative value
6851 to make sure sys_select will eventually get to
6852 calling the SIGCHLD handler for it, which will then
6853 invoke waitpid and reap_subprocess. */
6854 if (cp->procinfo.hProcess == NULL)
6855 delete_child (cp);
6856 else
6857 cp->fd = -1;
6862 if (fd >= 0 && fd < MAXDESC)
6863 fd_info[fd].flags = 0;
6865 /* Note that sockets do not need special treatment here (at least on
6866 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
6867 closesocket is equivalent to CloseHandle, which is to be expected
6868 because socket handles are fully fledged kernel handles. */
6869 rc = _close (fd);
6871 return rc;
6875 sys_dup (int fd)
6877 int new_fd;
6879 new_fd = _dup (fd);
6880 if (new_fd >= 0 && new_fd < MAXDESC)
6882 /* duplicate our internal info as well */
6883 fd_info[new_fd] = fd_info[fd];
6885 return new_fd;
6889 sys_dup2 (int src, int dst)
6891 int rc;
6893 if (dst < 0 || dst >= MAXDESC)
6895 errno = EBADF;
6896 return -1;
6899 /* make sure we close the destination first if it's a pipe or socket */
6900 if (src != dst && fd_info[dst].flags != 0)
6901 sys_close (dst);
6903 rc = _dup2 (src, dst);
6904 if (rc == 0)
6906 /* duplicate our internal info as well */
6907 fd_info[dst] = fd_info[src];
6909 return rc;
6913 pipe2 (int * phandles, int pipe2_flags)
6915 int rc;
6916 unsigned flags;
6918 eassert (pipe2_flags == O_CLOEXEC);
6920 /* make pipe handles non-inheritable; when we spawn a child, we
6921 replace the relevant handle with an inheritable one. Also put
6922 pipes into binary mode; we will do text mode translation ourselves
6923 if required. */
6924 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
6926 if (rc == 0)
6928 /* Protect against overflow, since Windows can open more handles than
6929 our fd_info array has room for. */
6930 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
6932 _close (phandles[0]);
6933 _close (phandles[1]);
6934 errno = EMFILE;
6935 rc = -1;
6937 else
6939 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
6940 fd_info[phandles[0]].flags = flags;
6942 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
6943 fd_info[phandles[1]].flags = flags;
6947 return rc;
6950 /* Function to do blocking read of one byte, needed to implement
6951 select. It is only allowed on communication ports, sockets, or
6952 pipes. */
6954 _sys_read_ahead (int fd)
6956 child_process * cp;
6957 int rc;
6959 if (fd < 0 || fd >= MAXDESC)
6960 return STATUS_READ_ERROR;
6962 cp = fd_info[fd].cp;
6964 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
6965 return STATUS_READ_ERROR;
6967 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
6968 || (fd_info[fd].flags & FILE_READ) == 0)
6970 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
6971 emacs_abort ();
6974 cp->status = STATUS_READ_IN_PROGRESS;
6976 if (fd_info[fd].flags & FILE_PIPE)
6978 rc = _read (fd, &cp->chr, sizeof (char));
6980 /* Give subprocess time to buffer some more output for us before
6981 reporting that input is available; we need this because Windows 95
6982 connects DOS programs to pipes by making the pipe appear to be
6983 the normal console stdout - as a result most DOS programs will
6984 write to stdout without buffering, ie. one character at a
6985 time. Even some W32 programs do this - "dir" in a command
6986 shell on NT is very slow if we don't do this. */
6987 if (rc > 0)
6989 int wait = w32_pipe_read_delay;
6991 if (wait > 0)
6992 Sleep (wait);
6993 else if (wait < 0)
6994 while (++wait <= 0)
6995 /* Yield remainder of our time slice, effectively giving a
6996 temporary priority boost to the child process. */
6997 Sleep (0);
7000 else if (fd_info[fd].flags & FILE_SERIAL)
7002 HANDLE hnd = fd_info[fd].hnd;
7003 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7004 COMMTIMEOUTS ct;
7006 /* Configure timeouts for blocking read. */
7007 if (!GetCommTimeouts (hnd, &ct))
7009 cp->status = STATUS_READ_ERROR;
7010 return STATUS_READ_ERROR;
7012 ct.ReadIntervalTimeout = 0;
7013 ct.ReadTotalTimeoutMultiplier = 0;
7014 ct.ReadTotalTimeoutConstant = 0;
7015 if (!SetCommTimeouts (hnd, &ct))
7017 cp->status = STATUS_READ_ERROR;
7018 return STATUS_READ_ERROR;
7021 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
7023 if (GetLastError () != ERROR_IO_PENDING)
7025 cp->status = STATUS_READ_ERROR;
7026 return STATUS_READ_ERROR;
7028 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
7030 cp->status = STATUS_READ_ERROR;
7031 return STATUS_READ_ERROR;
7035 else if (fd_info[fd].flags & FILE_SOCKET)
7037 unsigned long nblock = 0;
7038 /* We always want this to block, so temporarily disable NDELAY. */
7039 if (fd_info[fd].flags & FILE_NDELAY)
7040 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7042 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
7044 if (fd_info[fd].flags & FILE_NDELAY)
7046 nblock = 1;
7047 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7051 if (rc == sizeof (char))
7052 cp->status = STATUS_READ_SUCCEEDED;
7053 else
7054 cp->status = STATUS_READ_FAILED;
7056 return cp->status;
7060 _sys_wait_accept (int fd)
7062 HANDLE hEv;
7063 child_process * cp;
7064 int rc;
7066 if (fd < 0 || fd >= MAXDESC)
7067 return STATUS_READ_ERROR;
7069 cp = fd_info[fd].cp;
7071 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7072 return STATUS_READ_ERROR;
7074 cp->status = STATUS_READ_FAILED;
7076 hEv = pfn_WSACreateEvent ();
7077 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
7078 if (rc != SOCKET_ERROR)
7080 do {
7081 rc = WaitForSingleObject (hEv, 500);
7082 Sleep (5);
7083 } while (rc == WAIT_TIMEOUT
7084 && cp->status != STATUS_READ_ERROR
7085 && cp->char_avail);
7086 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
7087 if (rc == WAIT_OBJECT_0)
7088 cp->status = STATUS_READ_SUCCEEDED;
7090 pfn_WSACloseEvent (hEv);
7092 return cp->status;
7096 sys_read (int fd, char * buffer, unsigned int count)
7098 int nchars;
7099 int to_read;
7100 DWORD waiting;
7101 char * orig_buffer = buffer;
7103 if (fd < 0)
7105 errno = EBADF;
7106 return -1;
7109 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
7111 child_process *cp = fd_info[fd].cp;
7113 if ((fd_info[fd].flags & FILE_READ) == 0)
7115 errno = EBADF;
7116 return -1;
7119 nchars = 0;
7121 /* re-read CR carried over from last read */
7122 if (fd_info[fd].flags & FILE_LAST_CR)
7124 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
7125 *buffer++ = 0x0d;
7126 count--;
7127 nchars++;
7128 fd_info[fd].flags &= ~FILE_LAST_CR;
7131 /* presence of a child_process structure means we are operating in
7132 non-blocking mode - otherwise we just call _read directly.
7133 Note that the child_process structure might be missing because
7134 reap_subprocess has been called; in this case the pipe is
7135 already broken, so calling _read on it is okay. */
7136 if (cp)
7138 int current_status = cp->status;
7140 switch (current_status)
7142 case STATUS_READ_FAILED:
7143 case STATUS_READ_ERROR:
7144 /* report normal EOF if nothing in buffer */
7145 if (nchars <= 0)
7146 fd_info[fd].flags |= FILE_AT_EOF;
7147 return nchars;
7149 case STATUS_READ_READY:
7150 case STATUS_READ_IN_PROGRESS:
7151 DebPrint (("sys_read called when read is in progress\n"));
7152 errno = EWOULDBLOCK;
7153 return -1;
7155 case STATUS_READ_SUCCEEDED:
7156 /* consume read-ahead char */
7157 *buffer++ = cp->chr;
7158 count--;
7159 nchars++;
7160 cp->status = STATUS_READ_ACKNOWLEDGED;
7161 ResetEvent (cp->char_avail);
7163 case STATUS_READ_ACKNOWLEDGED:
7164 break;
7166 default:
7167 DebPrint (("sys_read: bad status %d\n", current_status));
7168 errno = EBADF;
7169 return -1;
7172 if (fd_info[fd].flags & FILE_PIPE)
7174 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
7175 to_read = min (waiting, (DWORD) count);
7177 if (to_read > 0)
7178 nchars += _read (fd, buffer, to_read);
7180 else if (fd_info[fd].flags & FILE_SERIAL)
7182 HANDLE hnd = fd_info[fd].hnd;
7183 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7184 int rc = 0;
7185 COMMTIMEOUTS ct;
7187 if (count > 0)
7189 /* Configure timeouts for non-blocking read. */
7190 if (!GetCommTimeouts (hnd, &ct))
7192 errno = EIO;
7193 return -1;
7195 ct.ReadIntervalTimeout = MAXDWORD;
7196 ct.ReadTotalTimeoutMultiplier = 0;
7197 ct.ReadTotalTimeoutConstant = 0;
7198 if (!SetCommTimeouts (hnd, &ct))
7200 errno = EIO;
7201 return -1;
7204 if (!ResetEvent (ovl->hEvent))
7206 errno = EIO;
7207 return -1;
7209 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
7211 if (GetLastError () != ERROR_IO_PENDING)
7213 errno = EIO;
7214 return -1;
7216 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
7218 errno = EIO;
7219 return -1;
7222 nchars += rc;
7225 else /* FILE_SOCKET */
7227 if (winsock_lib == NULL) emacs_abort ();
7229 /* do the equivalent of a non-blocking read */
7230 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
7231 if (waiting == 0 && nchars == 0)
7233 errno = EWOULDBLOCK;
7234 return -1;
7237 if (waiting)
7239 /* always use binary mode for sockets */
7240 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
7241 if (res == SOCKET_ERROR)
7243 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
7244 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
7245 set_errno ();
7246 return -1;
7248 nchars += res;
7252 else
7254 int nread = _read (fd, buffer, count);
7255 if (nread >= 0)
7256 nchars += nread;
7257 else if (nchars == 0)
7258 nchars = nread;
7261 if (nchars <= 0)
7262 fd_info[fd].flags |= FILE_AT_EOF;
7263 /* Perform text mode translation if required. */
7264 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
7266 nchars = crlf_to_lf (nchars, orig_buffer);
7267 /* If buffer contains only CR, return that. To be absolutely
7268 sure we should attempt to read the next char, but in
7269 practice a CR to be followed by LF would not appear by
7270 itself in the buffer. */
7271 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
7273 fd_info[fd].flags |= FILE_LAST_CR;
7274 nchars--;
7278 else
7279 nchars = _read (fd, buffer, count);
7281 return nchars;
7284 /* From w32xfns.c */
7285 extern HANDLE interrupt_handle;
7287 /* For now, don't bother with a non-blocking mode */
7289 sys_write (int fd, const void * buffer, unsigned int count)
7291 int nchars;
7293 if (fd < 0)
7295 errno = EBADF;
7296 return -1;
7299 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
7301 if ((fd_info[fd].flags & FILE_WRITE) == 0)
7303 errno = EBADF;
7304 return -1;
7307 /* Perform text mode translation if required. */
7308 if ((fd_info[fd].flags & FILE_BINARY) == 0)
7310 char * tmpbuf = alloca (count * 2);
7311 unsigned char * src = (void *)buffer;
7312 unsigned char * dst = tmpbuf;
7313 int nbytes = count;
7315 while (1)
7317 unsigned char *next;
7318 /* copy next line or remaining bytes */
7319 next = _memccpy (dst, src, '\n', nbytes);
7320 if (next)
7322 /* copied one line ending with '\n' */
7323 int copied = next - dst;
7324 nbytes -= copied;
7325 src += copied;
7326 /* insert '\r' before '\n' */
7327 next[-1] = '\r';
7328 next[0] = '\n';
7329 dst = next + 1;
7330 count++;
7332 else
7333 /* copied remaining partial line -> now finished */
7334 break;
7336 buffer = tmpbuf;
7340 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
7342 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
7343 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
7344 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
7345 DWORD active = 0;
7347 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
7349 if (GetLastError () != ERROR_IO_PENDING)
7351 errno = EIO;
7352 return -1;
7354 if (detect_input_pending ())
7355 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
7356 QS_ALLINPUT);
7357 else
7358 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
7359 if (active == WAIT_OBJECT_0)
7360 { /* User pressed C-g, cancel write, then leave. Don't bother
7361 cleaning up as we may only get stuck in buggy drivers. */
7362 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
7363 CancelIo (hnd);
7364 errno = EIO;
7365 return -1;
7367 if (active == WAIT_OBJECT_0 + 1
7368 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
7370 errno = EIO;
7371 return -1;
7375 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
7377 unsigned long nblock = 0;
7378 if (winsock_lib == NULL) emacs_abort ();
7380 /* TODO: implement select() properly so non-blocking I/O works. */
7381 /* For now, make sure the write blocks. */
7382 if (fd_info[fd].flags & FILE_NDELAY)
7383 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7385 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
7387 /* Set the socket back to non-blocking if it was before,
7388 for other operations that support it. */
7389 if (fd_info[fd].flags & FILE_NDELAY)
7391 nblock = 1;
7392 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7395 if (nchars == SOCKET_ERROR)
7397 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
7398 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
7399 set_errno ();
7402 else
7404 /* Some networked filesystems don't like too large writes, so
7405 break them into smaller chunks. See the Comments section of
7406 the MSDN documentation of WriteFile for details behind the
7407 choice of the value of CHUNK below. See also the thread
7408 http://thread.gmane.org/gmane.comp.version-control.git/145294
7409 in the git mailing list. */
7410 const unsigned char *p = buffer;
7411 const unsigned chunk = 30 * 1024 * 1024;
7413 nchars = 0;
7414 while (count > 0)
7416 unsigned this_chunk = count < chunk ? count : chunk;
7417 int n = _write (fd, p, this_chunk);
7419 nchars += n;
7420 if (n < 0)
7422 nchars = n;
7423 break;
7425 else if (n < this_chunk)
7426 break;
7427 count -= n;
7428 p += n;
7432 return nchars;
7435 /* The Windows CRT functions are "optimized for speed", so they don't
7436 check for timezone and DST changes if they were last called less
7437 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
7438 all Emacs features that repeatedly call time functions (e.g.,
7439 display-time) are in real danger of missing timezone and DST
7440 changes. Calling tzset before each localtime call fixes that. */
7441 struct tm *
7442 sys_localtime (const time_t *t)
7444 tzset ();
7445 return localtime (t);
7450 /* Try loading LIBRARY_ID from the file(s) specified in
7451 Vdynamic_library_alist. If the library is loaded successfully,
7452 return the handle of the DLL, and record the filename in the
7453 property :loaded-from of LIBRARY_ID. If the library could not be
7454 found, or when it was already loaded (because the handle is not
7455 recorded anywhere, and so is lost after use), return NULL.
7457 We could also save the handle in :loaded-from, but currently
7458 there's no use case for it. */
7459 HMODULE
7460 w32_delayed_load (Lisp_Object library_id)
7462 HMODULE library_dll = NULL;
7464 CHECK_SYMBOL (library_id);
7466 if (CONSP (Vdynamic_library_alist)
7467 && NILP (Fassq (library_id, Vlibrary_cache)))
7469 Lisp_Object found = Qnil;
7470 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
7472 if (CONSP (dlls))
7473 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
7475 CHECK_STRING_CAR (dlls);
7476 if ((library_dll = LoadLibrary (SDATA (XCAR (dlls)))))
7478 char name[MAX_PATH];
7479 DWORD len;
7481 len = GetModuleFileNameA (library_dll, name, sizeof (name));
7482 found = Fcons (XCAR (dlls),
7483 (len > 0)
7484 /* Possibly truncated */
7485 ? make_specified_string (name, -1, len, 1)
7486 : Qnil);
7487 break;
7491 Fput (library_id, QCloaded_from, found);
7494 return library_dll;
7498 void
7499 check_windows_init_file (void)
7501 /* A common indication that Emacs is not installed properly is when
7502 it cannot find the Windows installation file. If this file does
7503 not exist in the expected place, tell the user. */
7505 if (!noninteractive && !inhibit_window_system
7506 /* Vload_path is not yet initialized when we are loading
7507 loadup.el. */
7508 && NILP (Vpurify_flag))
7510 Lisp_Object init_file;
7511 int fd;
7513 init_file = build_string ("term/w32-win");
7514 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
7515 if (fd < 0)
7517 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
7518 char *init_file_name = SDATA (init_file);
7519 char *load_path = SDATA (load_path_print);
7520 char *buffer = alloca (1024
7521 + strlen (init_file_name)
7522 + strlen (load_path));
7524 sprintf (buffer,
7525 "The Emacs Windows initialization file \"%s.el\" "
7526 "could not be found in your Emacs installation. "
7527 "Emacs checked the following directories for this file:\n"
7528 "\n%s\n\n"
7529 "When Emacs cannot find this file, it usually means that it "
7530 "was not installed properly, or its distribution file was "
7531 "not unpacked properly.\nSee the README.W32 file in the "
7532 "top-level Emacs directory for more information.",
7533 init_file_name, load_path);
7534 MessageBox (NULL,
7535 buffer,
7536 "Emacs Abort Dialog",
7537 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
7538 /* Use the low-level system abort. */
7539 abort ();
7541 else
7543 _close (fd);
7548 void
7549 term_ntproc (int ignored)
7551 (void)ignored;
7553 term_timers ();
7555 /* shutdown the socket interface if necessary */
7556 term_winsock ();
7558 term_w32select ();
7561 void
7562 init_ntproc (int dumping)
7564 sigset_t initial_mask = 0;
7566 /* Initialize the socket interface now if available and requested by
7567 the user by defining PRELOAD_WINSOCK; otherwise loading will be
7568 delayed until open-network-stream is called (w32-has-winsock can
7569 also be used to dynamically load or reload winsock).
7571 Conveniently, init_environment is called before us, so
7572 PRELOAD_WINSOCK can be set in the registry. */
7574 /* Always initialize this correctly. */
7575 winsock_lib = NULL;
7577 if (getenv ("PRELOAD_WINSOCK") != NULL)
7578 init_winsock (TRUE);
7580 /* Initial preparation for subprocess support: replace our standard
7581 handles with non-inheritable versions. */
7583 HANDLE parent;
7584 HANDLE stdin_save = INVALID_HANDLE_VALUE;
7585 HANDLE stdout_save = INVALID_HANDLE_VALUE;
7586 HANDLE stderr_save = INVALID_HANDLE_VALUE;
7588 parent = GetCurrentProcess ();
7590 /* ignore errors when duplicating and closing; typically the
7591 handles will be invalid when running as a gui program. */
7592 DuplicateHandle (parent,
7593 GetStdHandle (STD_INPUT_HANDLE),
7594 parent,
7595 &stdin_save,
7597 FALSE,
7598 DUPLICATE_SAME_ACCESS);
7600 DuplicateHandle (parent,
7601 GetStdHandle (STD_OUTPUT_HANDLE),
7602 parent,
7603 &stdout_save,
7605 FALSE,
7606 DUPLICATE_SAME_ACCESS);
7608 DuplicateHandle (parent,
7609 GetStdHandle (STD_ERROR_HANDLE),
7610 parent,
7611 &stderr_save,
7613 FALSE,
7614 DUPLICATE_SAME_ACCESS);
7616 fclose (stdin);
7617 fclose (stdout);
7618 fclose (stderr);
7620 if (stdin_save != INVALID_HANDLE_VALUE)
7621 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
7622 else
7623 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
7624 _fdopen (0, "r");
7626 if (stdout_save != INVALID_HANDLE_VALUE)
7627 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
7628 else
7629 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
7630 _fdopen (1, "w");
7632 if (stderr_save != INVALID_HANDLE_VALUE)
7633 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
7634 else
7635 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
7636 _fdopen (2, "w");
7639 /* unfortunately, atexit depends on implementation of malloc */
7640 /* atexit (term_ntproc); */
7641 if (!dumping)
7643 /* Make sure we start with all signals unblocked. */
7644 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
7645 signal (SIGABRT, term_ntproc);
7647 init_timers ();
7649 /* determine which drives are fixed, for GetCachedVolumeInformation */
7651 /* GetDriveType must have trailing backslash. */
7652 char drive[] = "A:\\";
7654 /* Loop over all possible drive letters */
7655 while (*drive <= 'Z')
7657 /* Record if this drive letter refers to a fixed drive. */
7658 fixed_drives[DRIVE_INDEX (*drive)] =
7659 (GetDriveType (drive) == DRIVE_FIXED);
7661 (*drive)++;
7664 /* Reset the volume info cache. */
7665 volume_cache = NULL;
7670 shutdown_handler ensures that buffers' autosave files are
7671 up to date when the user logs off, or the system shuts down.
7673 static BOOL WINAPI
7674 shutdown_handler (DWORD type)
7676 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
7677 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
7678 || type == CTRL_LOGOFF_EVENT /* User logs off. */
7679 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
7681 /* Shut down cleanly, making sure autosave files are up to date. */
7682 shut_down_emacs (0, Qnil);
7685 /* Allow other handlers to handle this signal. */
7686 return FALSE;
7690 globals_of_w32 is used to initialize those global variables that
7691 must always be initialized on startup even when the global variable
7692 initialized is non zero (see the function main in emacs.c).
7694 void
7695 globals_of_w32 (void)
7697 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
7699 get_process_times_fn = (GetProcessTimes_Proc)
7700 GetProcAddress (kernel32, "GetProcessTimes");
7702 DEFSYM (QCloaded_from, ":loaded-from");
7704 g_b_init_is_windows_9x = 0;
7705 g_b_init_open_process_token = 0;
7706 g_b_init_get_token_information = 0;
7707 g_b_init_lookup_account_sid = 0;
7708 g_b_init_get_sid_sub_authority = 0;
7709 g_b_init_get_sid_sub_authority_count = 0;
7710 g_b_init_get_security_info = 0;
7711 g_b_init_get_file_security = 0;
7712 g_b_init_get_security_descriptor_owner = 0;
7713 g_b_init_get_security_descriptor_group = 0;
7714 g_b_init_is_valid_sid = 0;
7715 g_b_init_create_toolhelp32_snapshot = 0;
7716 g_b_init_process32_first = 0;
7717 g_b_init_process32_next = 0;
7718 g_b_init_open_thread_token = 0;
7719 g_b_init_impersonate_self = 0;
7720 g_b_init_revert_to_self = 0;
7721 g_b_init_get_process_memory_info = 0;
7722 g_b_init_get_process_working_set_size = 0;
7723 g_b_init_global_memory_status = 0;
7724 g_b_init_global_memory_status_ex = 0;
7725 g_b_init_equal_sid = 0;
7726 g_b_init_copy_sid = 0;
7727 g_b_init_get_length_sid = 0;
7728 g_b_init_get_native_system_info = 0;
7729 g_b_init_get_system_times = 0;
7730 g_b_init_create_symbolic_link = 0;
7731 g_b_init_get_security_descriptor_dacl = 0;
7732 g_b_init_convert_sd_to_sddl = 0;
7733 g_b_init_convert_sddl_to_sd = 0;
7734 g_b_init_is_valid_security_descriptor = 0;
7735 g_b_init_set_file_security = 0;
7736 num_of_processors = 0;
7737 /* The following sets a handler for shutdown notifications for
7738 console apps. This actually applies to Emacs in both console and
7739 GUI modes, since we had to fool windows into thinking emacs is a
7740 console application to get console mode to work. */
7741 SetConsoleCtrlHandler (shutdown_handler, TRUE);
7743 /* "None" is the default group name on standalone workstations. */
7744 strcpy (dflt_group_name, "None");
7746 /* Reset, in case it has some value inherited from dump time. */
7747 w32_stat_get_owner_group = 0;
7750 /* For make-serial-process */
7752 serial_open (Lisp_Object port_obj)
7754 char *port = SSDATA (port_obj);
7755 HANDLE hnd;
7756 child_process *cp;
7757 int fd = -1;
7759 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
7760 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
7761 if (hnd == INVALID_HANDLE_VALUE)
7762 error ("Could not open %s", port);
7763 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
7764 if (fd == -1)
7765 error ("Could not open %s", port);
7767 cp = new_child ();
7768 if (!cp)
7769 error ("Could not create child process");
7770 cp->fd = fd;
7771 cp->status = STATUS_READ_ACKNOWLEDGED;
7772 fd_info[ fd ].hnd = hnd;
7773 fd_info[ fd ].flags |=
7774 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
7775 if (fd_info[ fd ].cp != NULL)
7777 error ("fd_info[fd = %d] is already in use", fd);
7779 fd_info[ fd ].cp = cp;
7780 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
7781 if (cp->ovl_read.hEvent == NULL)
7782 error ("Could not create read event");
7783 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
7784 if (cp->ovl_write.hEvent == NULL)
7785 error ("Could not create write event");
7787 return fd;
7790 /* For serial-process-configure */
7791 void
7792 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
7794 Lisp_Object childp2 = Qnil;
7795 Lisp_Object tem = Qnil;
7796 HANDLE hnd;
7797 DCB dcb;
7798 COMMTIMEOUTS ct;
7799 char summary[4] = "???"; /* This usually becomes "8N1". */
7801 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
7802 error ("Not a serial process");
7803 hnd = fd_info[ p->outfd ].hnd;
7805 childp2 = Fcopy_sequence (p->childp);
7807 /* Initialize timeouts for blocking read and blocking write. */
7808 if (!GetCommTimeouts (hnd, &ct))
7809 error ("GetCommTimeouts() failed");
7810 ct.ReadIntervalTimeout = 0;
7811 ct.ReadTotalTimeoutMultiplier = 0;
7812 ct.ReadTotalTimeoutConstant = 0;
7813 ct.WriteTotalTimeoutMultiplier = 0;
7814 ct.WriteTotalTimeoutConstant = 0;
7815 if (!SetCommTimeouts (hnd, &ct))
7816 error ("SetCommTimeouts() failed");
7817 /* Read port attributes and prepare default configuration. */
7818 memset (&dcb, 0, sizeof (dcb));
7819 dcb.DCBlength = sizeof (DCB);
7820 if (!GetCommState (hnd, &dcb))
7821 error ("GetCommState() failed");
7822 dcb.fBinary = TRUE;
7823 dcb.fNull = FALSE;
7824 dcb.fAbortOnError = FALSE;
7825 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
7826 dcb.ErrorChar = 0;
7827 dcb.EofChar = 0;
7828 dcb.EvtChar = 0;
7830 /* Configure speed. */
7831 if (!NILP (Fplist_member (contact, QCspeed)))
7832 tem = Fplist_get (contact, QCspeed);
7833 else
7834 tem = Fplist_get (p->childp, QCspeed);
7835 CHECK_NUMBER (tem);
7836 dcb.BaudRate = XINT (tem);
7837 childp2 = Fplist_put (childp2, QCspeed, tem);
7839 /* Configure bytesize. */
7840 if (!NILP (Fplist_member (contact, QCbytesize)))
7841 tem = Fplist_get (contact, QCbytesize);
7842 else
7843 tem = Fplist_get (p->childp, QCbytesize);
7844 if (NILP (tem))
7845 tem = make_number (8);
7846 CHECK_NUMBER (tem);
7847 if (XINT (tem) != 7 && XINT (tem) != 8)
7848 error (":bytesize must be nil (8), 7, or 8");
7849 dcb.ByteSize = XINT (tem);
7850 summary[0] = XINT (tem) + '0';
7851 childp2 = Fplist_put (childp2, QCbytesize, tem);
7853 /* Configure parity. */
7854 if (!NILP (Fplist_member (contact, QCparity)))
7855 tem = Fplist_get (contact, QCparity);
7856 else
7857 tem = Fplist_get (p->childp, QCparity);
7858 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
7859 error (":parity must be nil (no parity), `even', or `odd'");
7860 dcb.fParity = FALSE;
7861 dcb.Parity = NOPARITY;
7862 dcb.fErrorChar = FALSE;
7863 if (NILP (tem))
7865 summary[1] = 'N';
7867 else if (EQ (tem, Qeven))
7869 summary[1] = 'E';
7870 dcb.fParity = TRUE;
7871 dcb.Parity = EVENPARITY;
7872 dcb.fErrorChar = TRUE;
7874 else if (EQ (tem, Qodd))
7876 summary[1] = 'O';
7877 dcb.fParity = TRUE;
7878 dcb.Parity = ODDPARITY;
7879 dcb.fErrorChar = TRUE;
7881 childp2 = Fplist_put (childp2, QCparity, tem);
7883 /* Configure stopbits. */
7884 if (!NILP (Fplist_member (contact, QCstopbits)))
7885 tem = Fplist_get (contact, QCstopbits);
7886 else
7887 tem = Fplist_get (p->childp, QCstopbits);
7888 if (NILP (tem))
7889 tem = make_number (1);
7890 CHECK_NUMBER (tem);
7891 if (XINT (tem) != 1 && XINT (tem) != 2)
7892 error (":stopbits must be nil (1 stopbit), 1, or 2");
7893 summary[2] = XINT (tem) + '0';
7894 if (XINT (tem) == 1)
7895 dcb.StopBits = ONESTOPBIT;
7896 else if (XINT (tem) == 2)
7897 dcb.StopBits = TWOSTOPBITS;
7898 childp2 = Fplist_put (childp2, QCstopbits, tem);
7900 /* Configure flowcontrol. */
7901 if (!NILP (Fplist_member (contact, QCflowcontrol)))
7902 tem = Fplist_get (contact, QCflowcontrol);
7903 else
7904 tem = Fplist_get (p->childp, QCflowcontrol);
7905 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
7906 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
7907 dcb.fOutxCtsFlow = FALSE;
7908 dcb.fOutxDsrFlow = FALSE;
7909 dcb.fDtrControl = DTR_CONTROL_DISABLE;
7910 dcb.fDsrSensitivity = FALSE;
7911 dcb.fTXContinueOnXoff = FALSE;
7912 dcb.fOutX = FALSE;
7913 dcb.fInX = FALSE;
7914 dcb.fRtsControl = RTS_CONTROL_DISABLE;
7915 dcb.XonChar = 17; /* Control-Q */
7916 dcb.XoffChar = 19; /* Control-S */
7917 if (NILP (tem))
7919 /* Already configured. */
7921 else if (EQ (tem, Qhw))
7923 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
7924 dcb.fOutxCtsFlow = TRUE;
7926 else if (EQ (tem, Qsw))
7928 dcb.fOutX = TRUE;
7929 dcb.fInX = TRUE;
7931 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
7933 /* Activate configuration. */
7934 if (!SetCommState (hnd, &dcb))
7935 error ("SetCommState() failed");
7937 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
7938 pset_childp (p, childp2);
7941 #ifdef HAVE_GNUTLS
7943 ssize_t
7944 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
7946 int n, err;
7947 SELECT_TYPE fdset;
7948 struct timespec timeout;
7949 struct Lisp_Process *process = (struct Lisp_Process *)p;
7950 int fd = process->infd;
7952 n = sys_read (fd, (char*)buf, sz);
7954 if (n >= 0)
7955 return n;
7957 err = errno;
7959 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7960 if (err == EWOULDBLOCK)
7961 err = EAGAIN;
7963 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
7965 return -1;
7968 ssize_t
7969 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
7971 struct Lisp_Process *process = (struct Lisp_Process *)p;
7972 int fd = process->outfd;
7973 ssize_t n = sys_write (fd, buf, sz);
7975 /* 0 or more bytes written means everything went fine. */
7976 if (n >= 0)
7977 return n;
7979 /* Negative bytes written means we got an error in errno.
7980 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7981 emacs_gnutls_transport_set_errno (process->gnutls_state,
7982 errno == EWOULDBLOCK ? EAGAIN : errno);
7984 return -1;
7986 #endif /* HAVE_GNUTLS */
7988 /* end of w32.c */