Auto-commit of generated files.
[emacs.git] / src / w32.c
blob21dbf49ed7c763dcd2b0ee2fae9509946fb82de8
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 EMACS_TIME *, 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 struct _utimbuf ut;
2508 if (!timespec)
2510 errno = ENOSYS;
2511 return -1;
2513 if (fd < 0 && !file)
2515 errno = EBADF;
2516 return -1;
2518 ut.actime = timespec[0].tv_sec;
2519 ut.modtime = timespec[1].tv_sec;
2520 if (fd >= 0)
2521 return _futime (fd, &ut);
2522 else
2523 return _utime (file, &ut);
2527 /* ------------------------------------------------------------------------- */
2528 /* IO support and wrapper functions for the Windows API. */
2529 /* ------------------------------------------------------------------------- */
2531 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2532 on network directories, so we handle that case here.
2533 (Ulrich Leodolter, 1/11/95). */
2534 char *
2535 sys_ctime (const time_t *t)
2537 char *str = (char *) ctime (t);
2538 return (str ? str : "Sun Jan 01 00:00:00 1970");
2541 /* Emulate sleep...we could have done this with a define, but that
2542 would necessitate including windows.h in the files that used it.
2543 This is much easier. */
2544 void
2545 sys_sleep (int seconds)
2547 Sleep (seconds * 1000);
2550 /* Internal MSVC functions for low-level descriptor munging */
2551 extern int __cdecl _set_osfhnd (int fd, long h);
2552 extern int __cdecl _free_osfhnd (int fd);
2554 /* parallel array of private info on file handles */
2555 filedesc fd_info [ MAXDESC ];
2557 typedef struct volume_info_data {
2558 struct volume_info_data * next;
2560 /* time when info was obtained */
2561 DWORD timestamp;
2563 /* actual volume info */
2564 char * root_dir;
2565 DWORD serialnum;
2566 DWORD maxcomp;
2567 DWORD flags;
2568 char * name;
2569 char * type;
2570 } volume_info_data;
2572 /* Global referenced by various functions. */
2573 static volume_info_data volume_info;
2575 /* Vector to indicate which drives are local and fixed (for which cached
2576 data never expires). */
2577 static BOOL fixed_drives[26];
2579 /* Consider cached volume information to be stale if older than 10s,
2580 at least for non-local drives. Info for fixed drives is never stale. */
2581 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2582 #define VOLINFO_STILL_VALID( root_dir, info ) \
2583 ( ( isalpha (root_dir[0]) && \
2584 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2585 || GetTickCount () - info->timestamp < 10000 )
2587 /* Cache support functions. */
2589 /* Simple linked list with linear search is sufficient. */
2590 static volume_info_data *volume_cache = NULL;
2592 static volume_info_data *
2593 lookup_volume_info (char * root_dir)
2595 volume_info_data * info;
2597 for (info = volume_cache; info; info = info->next)
2598 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2599 break;
2600 return info;
2603 static void
2604 add_volume_info (char * root_dir, volume_info_data * info)
2606 info->root_dir = xstrdup (root_dir);
2607 info->next = volume_cache;
2608 volume_cache = info;
2612 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2613 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2614 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2615 static volume_info_data *
2616 GetCachedVolumeInformation (char * root_dir)
2618 volume_info_data * info;
2619 char default_root[ MAX_PATH ];
2621 /* NULL for root_dir means use root from current directory. */
2622 if (root_dir == NULL)
2624 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
2625 return NULL;
2626 parse_root (default_root, &root_dir);
2627 *root_dir = 0;
2628 root_dir = default_root;
2631 /* Local fixed drives can be cached permanently. Removable drives
2632 cannot be cached permanently, since the volume name and serial
2633 number (if nothing else) can change. Remote drives should be
2634 treated as if they are removable, since there is no sure way to
2635 tell whether they are or not. Also, the UNC association of drive
2636 letters mapped to remote volumes can be changed at any time (even
2637 by other processes) without notice.
2639 As a compromise, so we can benefit from caching info for remote
2640 volumes, we use a simple expiry mechanism to invalidate cache
2641 entries that are more than ten seconds old. */
2643 #if 0
2644 /* No point doing this, because WNetGetConnection is even slower than
2645 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2646 GetDriveType is about the only call of this type which does not
2647 involve network access, and so is extremely quick). */
2649 /* Map drive letter to UNC if remote. */
2650 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2652 char remote_name[ 256 ];
2653 char drive[3] = { root_dir[0], ':' };
2655 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2656 == NO_ERROR)
2657 /* do something */ ;
2659 #endif
2661 info = lookup_volume_info (root_dir);
2663 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2665 char name[ 256 ];
2666 DWORD serialnum;
2667 DWORD maxcomp;
2668 DWORD flags;
2669 char type[ 256 ];
2671 /* Info is not cached, or is stale. */
2672 if (!GetVolumeInformation (root_dir,
2673 name, sizeof (name),
2674 &serialnum,
2675 &maxcomp,
2676 &flags,
2677 type, sizeof (type)))
2678 return NULL;
2680 /* Cache the volume information for future use, overwriting existing
2681 entry if present. */
2682 if (info == NULL)
2684 info = xmalloc (sizeof (volume_info_data));
2685 add_volume_info (root_dir, info);
2687 else
2689 xfree (info->name);
2690 xfree (info->type);
2693 info->name = xstrdup (name);
2694 info->serialnum = serialnum;
2695 info->maxcomp = maxcomp;
2696 info->flags = flags;
2697 info->type = xstrdup (type);
2698 info->timestamp = GetTickCount ();
2701 return info;
2704 /* Get information on the volume where NAME is held; set path pointer to
2705 start of pathname in NAME (past UNC header\volume header if present),
2706 if pPath is non-NULL.
2708 Note: if NAME includes symlinks, the information is for the volume
2709 of the symlink, not of its target. That's because, even though
2710 GetVolumeInformation returns information about the symlink target
2711 of its argument, we only pass the root directory to
2712 GetVolumeInformation, not the full NAME. */
2713 static int
2714 get_volume_info (const char * name, const char ** pPath)
2716 char temp[MAX_PATH];
2717 char *rootname = NULL; /* default to current volume */
2718 volume_info_data * info;
2720 if (name == NULL)
2721 return FALSE;
2723 /* Find the root name of the volume if given. */
2724 if (isalpha (name[0]) && name[1] == ':')
2726 rootname = temp;
2727 temp[0] = *name++;
2728 temp[1] = *name++;
2729 temp[2] = '\\';
2730 temp[3] = 0;
2732 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2734 char *str = temp;
2735 int slashes = 4;
2736 int dbcs_p = max_filename_mbslen () > 1;
2738 rootname = temp;
2741 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2742 break;
2743 if (!dbcs_p)
2744 *str++ = *name++;
2745 else
2747 const char *p = name;
2749 name = CharNextExA (file_name_codepage, name, 0);
2750 memcpy (str, p, name - p);
2751 str += name - p;
2754 while ( *name );
2756 *str++ = '\\';
2757 *str = 0;
2760 if (pPath)
2761 *pPath = name;
2763 info = GetCachedVolumeInformation (rootname);
2764 if (info != NULL)
2766 /* Set global referenced by other functions. */
2767 volume_info = *info;
2768 return TRUE;
2770 return FALSE;
2773 /* Determine if volume is FAT format (ie. only supports short 8.3
2774 names); also set path pointer to start of pathname in name, if
2775 pPath is non-NULL. */
2776 static int
2777 is_fat_volume (const char * name, const char ** pPath)
2779 if (get_volume_info (name, pPath))
2780 return (volume_info.maxcomp == 12);
2781 return FALSE;
2784 /* Map filename to a valid 8.3 name if necessary.
2785 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2786 const char *
2787 map_w32_filename (const char * name, const char ** pPath)
2789 static char shortname[MAX_PATH];
2790 char * str = shortname;
2791 char c;
2792 char * path;
2793 const char * save_name = name;
2795 if (strlen (name) >= MAX_PATH)
2797 /* Return a filename which will cause callers to fail. */
2798 strcpy (shortname, "?");
2799 return shortname;
2802 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2804 register int left = 8; /* maximum number of chars in part */
2805 register int extn = 0; /* extension added? */
2806 register int dots = 2; /* maximum number of dots allowed */
2808 while (name < path)
2809 *str++ = *name++; /* skip past UNC header */
2811 while ((c = *name++))
2813 switch ( c )
2815 case ':':
2816 case '\\':
2817 case '/':
2818 *str++ = (c == ':' ? ':' : '\\');
2819 extn = 0; /* reset extension flags */
2820 dots = 2; /* max 2 dots */
2821 left = 8; /* max length 8 for main part */
2822 break;
2823 case '.':
2824 if ( dots )
2826 /* Convert path components of the form .xxx to _xxx,
2827 but leave . and .. as they are. This allows .emacs
2828 to be read as _emacs, for example. */
2830 if (! *name ||
2831 *name == '.' ||
2832 IS_DIRECTORY_SEP (*name))
2834 *str++ = '.';
2835 dots--;
2837 else
2839 *str++ = '_';
2840 left--;
2841 dots = 0;
2844 else if ( !extn )
2846 *str++ = '.';
2847 extn = 1; /* we've got an extension */
2848 left = 3; /* 3 chars in extension */
2850 else
2852 /* any embedded dots after the first are converted to _ */
2853 *str++ = '_';
2855 break;
2856 case '~':
2857 case '#': /* don't lose these, they're important */
2858 if ( ! left )
2859 str[-1] = c; /* replace last character of part */
2860 /* FALLTHRU */
2861 default:
2862 if ( left )
2864 *str++ = tolower (c); /* map to lower case (looks nicer) */
2865 left--;
2866 dots = 0; /* started a path component */
2868 break;
2871 *str = '\0';
2873 else
2875 strcpy (shortname, name);
2876 unixtodos_filename (shortname);
2879 if (pPath)
2880 *pPath = shortname + (path - save_name);
2882 return shortname;
2885 static int
2886 is_exec (const char * name)
2888 char * p = strrchr (name, '.');
2889 return
2890 (p != NULL
2891 && (xstrcasecmp (p, ".exe") == 0 ||
2892 xstrcasecmp (p, ".com") == 0 ||
2893 xstrcasecmp (p, ".bat") == 0 ||
2894 xstrcasecmp (p, ".cmd") == 0));
2897 /* Emulate the Unix directory procedures opendir, closedir,
2898 and readdir. We can't use the procedures supplied in sysdep.c,
2899 so we provide them here. */
2901 struct dirent dir_static; /* simulated directory contents */
2902 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2903 static int dir_is_fat;
2904 static char dir_pathname[MAXPATHLEN+1];
2905 static WIN32_FIND_DATA dir_find_data;
2907 /* Support shares on a network resource as subdirectories of a read-only
2908 root directory. */
2909 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2910 static HANDLE open_unc_volume (const char *);
2911 static char *read_unc_volume (HANDLE, char *, int);
2912 static void close_unc_volume (HANDLE);
2914 DIR *
2915 opendir (const char *filename)
2917 DIR *dirp;
2919 /* Opening is done by FindFirstFile. However, a read is inherent to
2920 this operation, so we defer the open until read time. */
2922 if (dir_find_handle != INVALID_HANDLE_VALUE)
2923 return NULL;
2924 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2925 return NULL;
2927 /* Note: We don't support traversal of UNC volumes via symlinks.
2928 Doing so would mean punishing 99.99% of use cases by resolving
2929 all the possible symlinks in FILENAME, recursively. */
2930 if (is_unc_volume (filename))
2932 wnet_enum_handle = open_unc_volume (filename);
2933 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2934 return NULL;
2937 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2938 return NULL;
2940 dirp->dd_fd = 0;
2941 dirp->dd_loc = 0;
2942 dirp->dd_size = 0;
2944 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2945 dir_pathname[MAXPATHLEN] = '\0';
2946 /* Note: We don't support symlinks to file names on FAT volumes.
2947 Doing so would mean punishing 99.99% of use cases by resolving
2948 all the possible symlinks in FILENAME, recursively. */
2949 dir_is_fat = is_fat_volume (filename, NULL);
2951 return dirp;
2954 void
2955 closedir (DIR *dirp)
2957 /* If we have a find-handle open, close it. */
2958 if (dir_find_handle != INVALID_HANDLE_VALUE)
2960 FindClose (dir_find_handle);
2961 dir_find_handle = INVALID_HANDLE_VALUE;
2963 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2965 close_unc_volume (wnet_enum_handle);
2966 wnet_enum_handle = INVALID_HANDLE_VALUE;
2968 xfree ((char *) dirp);
2971 struct dirent *
2972 readdir (DIR *dirp)
2974 int downcase = !NILP (Vw32_downcase_file_names);
2976 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2978 if (!read_unc_volume (wnet_enum_handle,
2979 dir_find_data.cFileName,
2980 MAX_PATH))
2981 return NULL;
2983 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2984 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2986 char filename[MAXNAMLEN + 3];
2987 int ln;
2988 int dbcs_p = max_filename_mbslen () > 1;
2990 strcpy (filename, dir_pathname);
2991 ln = strlen (filename) - 1;
2992 if (!dbcs_p)
2994 if (!IS_DIRECTORY_SEP (filename[ln]))
2995 strcat (filename, "\\");
2997 else
2999 char *end = filename + ln + 1;
3000 char *last_char = CharPrevExA (file_name_codepage, filename, end, 0);
3002 if (!IS_DIRECTORY_SEP (*last_char))
3003 strcat (filename, "\\");
3005 strcat (filename, "*");
3007 /* Note: No need to resolve symlinks in FILENAME, because
3008 FindFirst opens the directory that is the target of a
3009 symlink. */
3010 dir_find_handle = FindFirstFile (filename, &dir_find_data);
3012 if (dir_find_handle == INVALID_HANDLE_VALUE)
3013 return NULL;
3015 else
3017 if (!FindNextFile (dir_find_handle, &dir_find_data))
3018 return NULL;
3021 /* Emacs never uses this value, so don't bother making it match
3022 value returned by stat(). */
3023 dir_static.d_ino = 1;
3025 strcpy (dir_static.d_name, dir_find_data.cFileName);
3027 /* If the file name in cFileName[] includes `?' characters, it means
3028 the original file name used characters that cannot be represented
3029 by the current ANSI codepage. To avoid total lossage, retrieve
3030 the short 8+3 alias of the long file name. */
3031 if (_mbspbrk (dir_static.d_name, "?"))
3033 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
3034 downcase = 1; /* 8+3 aliases are returned in all caps */
3036 dir_static.d_namlen = strlen (dir_static.d_name);
3037 dir_static.d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
3038 dir_static.d_namlen - dir_static.d_namlen % 4;
3040 /* If the file name in cFileName[] includes `?' characters, it means
3041 the original file name used characters that cannot be represented
3042 by the current ANSI codepage. To avoid total lossage, retrieve
3043 the short 8+3 alias of the long file name. */
3044 if (_mbspbrk (dir_find_data.cFileName, "?"))
3046 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
3047 /* 8+3 aliases are returned in all caps, which could break
3048 various alists that look at filenames' extensions. */
3049 downcase = 1;
3051 else
3052 strcpy (dir_static.d_name, dir_find_data.cFileName);
3053 dir_static.d_namlen = strlen (dir_static.d_name);
3054 if (dir_is_fat)
3055 _mbslwr (dir_static.d_name);
3056 else if (downcase)
3058 register char *p;
3059 int dbcs_p = max_filename_mbslen () > 1;
3060 for (p = dir_static.d_name; *p; )
3062 if (*p >= 'a' && *p <= 'z')
3063 break;
3064 if (dbcs_p)
3065 p = CharNextExA (file_name_codepage, p, 0);
3066 else
3067 p++;
3069 if (!*p)
3070 _mbslwr (dir_static.d_name);
3073 return &dir_static;
3076 static HANDLE
3077 open_unc_volume (const char *path)
3079 NETRESOURCE nr;
3080 HANDLE henum;
3081 int result;
3083 nr.dwScope = RESOURCE_GLOBALNET;
3084 nr.dwType = RESOURCETYPE_DISK;
3085 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3086 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
3087 nr.lpLocalName = NULL;
3088 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
3089 nr.lpComment = NULL;
3090 nr.lpProvider = NULL;
3092 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3093 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
3095 if (result == NO_ERROR)
3096 return henum;
3097 else
3098 return INVALID_HANDLE_VALUE;
3101 static char *
3102 read_unc_volume (HANDLE henum, char *readbuf, int size)
3104 DWORD count;
3105 int result;
3106 DWORD bufsize = 512;
3107 char *buffer;
3108 char *ptr;
3109 int dbcs_p = max_filename_mbslen () > 1;
3111 count = 1;
3112 buffer = alloca (bufsize);
3113 result = WNetEnumResource (henum, &count, buffer, &bufsize);
3114 if (result != NO_ERROR)
3115 return NULL;
3117 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3118 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
3119 ptr += 2;
3120 if (!dbcs_p)
3121 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
3122 else
3124 while (*ptr && !IS_DIRECTORY_SEP (*ptr))
3125 ptr = CharNextExA (file_name_codepage, ptr, 0);
3127 ptr++;
3129 strncpy (readbuf, ptr, size);
3130 return readbuf;
3133 static void
3134 close_unc_volume (HANDLE henum)
3136 if (henum != INVALID_HANDLE_VALUE)
3137 WNetCloseEnum (henum);
3140 static DWORD
3141 unc_volume_file_attributes (const char *path)
3143 HANDLE henum;
3144 DWORD attrs;
3146 henum = open_unc_volume (path);
3147 if (henum == INVALID_HANDLE_VALUE)
3148 return -1;
3150 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3152 close_unc_volume (henum);
3154 return attrs;
3157 /* Ensure a network connection is authenticated. */
3158 static void
3159 logon_network_drive (const char *path)
3161 NETRESOURCE resource;
3162 char share[MAX_PATH];
3163 int n_slashes;
3164 char drive[4];
3165 UINT drvtype;
3166 char *p;
3167 int dbcs_p;
3169 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3170 drvtype = DRIVE_REMOTE;
3171 else if (path[0] == '\0' || path[1] != ':')
3172 drvtype = GetDriveType (NULL);
3173 else
3175 drive[0] = path[0];
3176 drive[1] = ':';
3177 drive[2] = '\\';
3178 drive[3] = '\0';
3179 drvtype = GetDriveType (drive);
3182 /* Only logon to networked drives. */
3183 if (drvtype != DRIVE_REMOTE)
3184 return;
3186 n_slashes = 2;
3187 strncpy (share, path, MAX_PATH);
3188 /* Truncate to just server and share name. */
3189 dbcs_p = max_filename_mbslen () > 1;
3190 for (p = share + 2; *p && p < share + MAX_PATH; )
3192 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3194 *p = '\0';
3195 break;
3197 if (dbcs_p)
3198 p = CharNextExA (file_name_codepage, p, 0);
3199 else
3200 p++;
3203 resource.dwType = RESOURCETYPE_DISK;
3204 resource.lpLocalName = NULL;
3205 resource.lpRemoteName = share;
3206 resource.lpProvider = NULL;
3208 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
3211 /* Emulate faccessat(2). */
3213 faccessat (int dirfd, const char * path, int mode, int flags)
3215 DWORD attributes;
3217 if (dirfd != AT_FDCWD
3218 && !(IS_DIRECTORY_SEP (path[0])
3219 || IS_DEVICE_SEP (path[1])))
3221 errno = EBADF;
3222 return -1;
3225 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3226 newer versions blow up when passed D_OK. */
3227 path = map_w32_filename (path, NULL);
3228 /* If the last element of PATH is a symlink, we need to resolve it
3229 to get the attributes of its target file. Note: any symlinks in
3230 PATH elements other than the last one are transparently resolved
3231 by GetFileAttributes below. */
3232 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3233 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3234 path = chase_symlinks (path);
3236 if ((attributes = GetFileAttributes (path)) == -1)
3238 DWORD w32err = GetLastError ();
3240 switch (w32err)
3242 case ERROR_INVALID_NAME:
3243 case ERROR_BAD_PATHNAME:
3244 if (is_unc_volume (path))
3246 attributes = unc_volume_file_attributes (path);
3247 if (attributes == -1)
3249 errno = EACCES;
3250 return -1;
3252 break;
3254 /* FALLTHROUGH */
3255 case ERROR_FILE_NOT_FOUND:
3256 case ERROR_BAD_NETPATH:
3257 errno = ENOENT;
3258 break;
3259 default:
3260 errno = EACCES;
3261 break;
3263 return -1;
3265 if ((mode & X_OK) != 0
3266 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3268 errno = EACCES;
3269 return -1;
3271 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3273 errno = EACCES;
3274 return -1;
3276 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3278 errno = EACCES;
3279 return -1;
3281 return 0;
3284 /* Shadow some MSVC runtime functions to map requests for long filenames
3285 to reasonable short names if necessary. This was originally added to
3286 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3287 long file names. */
3290 sys_chdir (const char * path)
3292 return _chdir (map_w32_filename (path, NULL));
3296 sys_chmod (const char * path, int mode)
3298 path = chase_symlinks (map_w32_filename (path, NULL));
3299 return _chmod (path, mode);
3303 sys_creat (const char * path, int mode)
3305 return _creat (map_w32_filename (path, NULL), mode);
3308 FILE *
3309 sys_fopen (const char * path, const char * mode)
3311 int fd;
3312 int oflag;
3313 const char * mode_save = mode;
3315 /* Force all file handles to be non-inheritable. This is necessary to
3316 ensure child processes don't unwittingly inherit handles that might
3317 prevent future file access. */
3319 if (mode[0] == 'r')
3320 oflag = O_RDONLY;
3321 else if (mode[0] == 'w' || mode[0] == 'a')
3322 oflag = O_WRONLY | O_CREAT | O_TRUNC;
3323 else
3324 return NULL;
3326 /* Only do simplistic option parsing. */
3327 while (*++mode)
3328 if (mode[0] == '+')
3330 oflag &= ~(O_RDONLY | O_WRONLY);
3331 oflag |= O_RDWR;
3333 else if (mode[0] == 'b')
3335 oflag &= ~O_TEXT;
3336 oflag |= O_BINARY;
3338 else if (mode[0] == 't')
3340 oflag &= ~O_BINARY;
3341 oflag |= O_TEXT;
3343 else break;
3345 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
3346 if (fd < 0)
3347 return NULL;
3349 return _fdopen (fd, mode_save);
3352 /* This only works on NTFS volumes, but is useful to have. */
3354 sys_link (const char * old, const char * new)
3356 HANDLE fileh;
3357 int result = -1;
3358 char oldname[MAX_PATH], newname[MAX_PATH];
3360 if (old == NULL || new == NULL)
3362 errno = ENOENT;
3363 return -1;
3366 strcpy (oldname, map_w32_filename (old, NULL));
3367 strcpy (newname, map_w32_filename (new, NULL));
3369 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
3370 FILE_FLAG_BACKUP_SEMANTICS, NULL);
3371 if (fileh != INVALID_HANDLE_VALUE)
3373 int wlen;
3375 /* Confusingly, the "alternate" stream name field does not apply
3376 when restoring a hard link, and instead contains the actual
3377 stream data for the link (ie. the name of the link to create).
3378 The WIN32_STREAM_ID structure before the cStreamName field is
3379 the stream header, which is then immediately followed by the
3380 stream data. */
3382 struct {
3383 WIN32_STREAM_ID wid;
3384 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
3385 } data;
3387 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
3388 data.wid.cStreamName, MAX_PATH);
3389 if (wlen > 0)
3391 LPVOID context = NULL;
3392 DWORD wbytes = 0;
3394 data.wid.dwStreamId = BACKUP_LINK;
3395 data.wid.dwStreamAttributes = 0;
3396 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
3397 data.wid.Size.HighPart = 0;
3398 data.wid.dwStreamNameSize = 0;
3400 if (BackupWrite (fileh, (LPBYTE)&data,
3401 offsetof (WIN32_STREAM_ID, cStreamName)
3402 + data.wid.Size.LowPart,
3403 &wbytes, FALSE, FALSE, &context)
3404 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
3406 /* succeeded */
3407 result = 0;
3409 else
3411 /* Should try mapping GetLastError to errno; for now just
3412 indicate a general error (eg. links not supported). */
3413 errno = EINVAL; // perhaps EMLINK?
3417 CloseHandle (fileh);
3419 else
3420 errno = ENOENT;
3422 return result;
3426 sys_mkdir (const char * path)
3428 return _mkdir (map_w32_filename (path, NULL));
3432 sys_open (const char * path, int oflag, int mode)
3434 const char* mpath = map_w32_filename (path, NULL);
3435 int res = -1;
3437 /* If possible, try to open file without _O_CREAT, to be able to
3438 write to existing hidden and system files. Force all file
3439 handles to be non-inheritable. */
3440 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
3441 res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
3442 if (res < 0)
3443 res = _open (mpath, oflag | _O_NOINHERIT, mode);
3445 return res;
3448 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
3449 when using mktemp.
3451 Standard algorithm for generating a temporary file name seems to be
3452 use pid or tid with a letter on the front (in place of the 6 X's)
3453 and cycle through the letters to find a unique name. We extend
3454 that to allow any reasonable character as the first of the 6 X's,
3455 so that the number of simultaneously used temporary files will be
3456 greater. */
3459 mkostemp (char * template, int flags)
3461 char * p;
3462 int i, fd = -1;
3463 unsigned uid = GetCurrentThreadId ();
3464 int save_errno = errno;
3465 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3467 errno = EINVAL;
3468 if (template == NULL)
3469 return -1;
3471 p = template + strlen (template);
3472 i = 5;
3473 /* replace up to the last 5 X's with uid in decimal */
3474 while (--p >= template && p[0] == 'X' && --i >= 0)
3476 p[0] = '0' + uid % 10;
3477 uid /= 10;
3480 if (i < 0 && p[0] == 'X')
3482 i = 0;
3485 p[0] = first_char[i];
3486 if ((fd = sys_open (template,
3487 flags | _O_CREAT | _O_EXCL | _O_RDWR,
3488 S_IRUSR | S_IWUSR)) >= 0
3489 || errno != EEXIST)
3491 if (fd >= 0)
3492 errno = save_errno;
3493 return fd;
3496 while (++i < sizeof (first_char));
3499 /* Template is badly formed or else we can't generate a unique name. */
3500 return -1;
3504 fchmod (int fd, mode_t mode)
3506 return 0;
3510 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
3512 BOOL result;
3513 char temp[MAX_PATH];
3514 int newname_dev;
3515 int oldname_dev;
3517 /* MoveFile on Windows 95 doesn't correctly change the short file name
3518 alias in a number of circumstances (it is not easy to predict when
3519 just by looking at oldname and newname, unfortunately). In these
3520 cases, renaming through a temporary name avoids the problem.
3522 A second problem on Windows 95 is that renaming through a temp name when
3523 newname is uppercase fails (the final long name ends up in
3524 lowercase, although the short alias might be uppercase) UNLESS the
3525 long temp name is not 8.3.
3527 So, on Windows 95 we always rename through a temp name, and we make sure
3528 the temp name has a long extension to ensure correct renaming. */
3530 strcpy (temp, map_w32_filename (oldname, NULL));
3532 /* volume_info is set indirectly by map_w32_filename. */
3533 oldname_dev = volume_info.serialnum;
3535 if (os_subtype == OS_9X)
3537 char * o;
3538 char * p;
3539 int i = 0;
3541 oldname = map_w32_filename (oldname, NULL);
3542 if ((o = strrchr (oldname, '\\')))
3543 o++;
3544 else
3545 o = (char *) oldname;
3547 if ((p = strrchr (temp, '\\')))
3548 p++;
3549 else
3550 p = temp;
3554 /* Force temp name to require a manufactured 8.3 alias - this
3555 seems to make the second rename work properly. */
3556 sprintf (p, "_.%s.%u", o, i);
3557 i++;
3558 result = rename (oldname, temp);
3560 /* This loop must surely terminate! */
3561 while (result < 0 && errno == EEXIST);
3562 if (result < 0)
3563 return -1;
3566 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
3567 (at least if it is a file; don't do this for directories).
3569 Since we mustn't do this if we are just changing the case of the
3570 file name (we would end up deleting the file we are trying to
3571 rename!), we let rename detect if the destination file already
3572 exists - that way we avoid the possible pitfalls of trying to
3573 determine ourselves whether two names really refer to the same
3574 file, which is not always possible in the general case. (Consider
3575 all the permutations of shared or subst'd drives, etc.) */
3577 newname = map_w32_filename (newname, NULL);
3579 /* volume_info is set indirectly by map_w32_filename. */
3580 newname_dev = volume_info.serialnum;
3582 result = rename (temp, newname);
3584 if (result < 0 && force)
3586 DWORD w32err = GetLastError ();
3588 if (errno == EACCES
3589 && newname_dev != oldname_dev)
3591 /* The implementation of `rename' on Windows does not return
3592 errno = EXDEV when you are moving a directory to a
3593 different storage device (ex. logical disk). It returns
3594 EACCES instead. So here we handle such situations and
3595 return EXDEV. */
3596 DWORD attributes;
3598 if ((attributes = GetFileAttributes (temp)) != -1
3599 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
3600 errno = EXDEV;
3602 else if (errno == EEXIST)
3604 if (_chmod (newname, 0666) != 0)
3605 return result;
3606 if (_unlink (newname) != 0)
3607 return result;
3608 result = rename (temp, newname);
3610 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
3611 && is_symlink (temp))
3613 /* This is Windows prohibiting the user from creating a
3614 symlink in another place, since that requires
3615 privileges. */
3616 errno = EPERM;
3620 return result;
3624 sys_rename (char const *old, char const *new)
3626 return sys_rename_replace (old, new, TRUE);
3630 sys_rmdir (const char * path)
3632 return _rmdir (map_w32_filename (path, NULL));
3636 sys_unlink (const char * path)
3638 path = map_w32_filename (path, NULL);
3640 /* On Unix, unlink works without write permission. */
3641 _chmod (path, 0666);
3642 return _unlink (path);
3645 static FILETIME utc_base_ft;
3646 static ULONGLONG utc_base; /* In 100ns units */
3647 static int init = 0;
3649 #define FILETIME_TO_U64(result, ft) \
3650 do { \
3651 ULARGE_INTEGER uiTemp; \
3652 uiTemp.LowPart = (ft).dwLowDateTime; \
3653 uiTemp.HighPart = (ft).dwHighDateTime; \
3654 result = uiTemp.QuadPart; \
3655 } while (0)
3657 static void
3658 initialize_utc_base (void)
3660 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3661 SYSTEMTIME st;
3663 st.wYear = 1970;
3664 st.wMonth = 1;
3665 st.wDay = 1;
3666 st.wHour = 0;
3667 st.wMinute = 0;
3668 st.wSecond = 0;
3669 st.wMilliseconds = 0;
3671 SystemTimeToFileTime (&st, &utc_base_ft);
3672 FILETIME_TO_U64 (utc_base, utc_base_ft);
3675 static time_t
3676 convert_time (FILETIME ft)
3678 ULONGLONG tmp;
3680 if (!init)
3682 initialize_utc_base ();
3683 init = 1;
3686 if (CompareFileTime (&ft, &utc_base_ft) < 0)
3687 return 0;
3689 FILETIME_TO_U64 (tmp, ft);
3690 return (time_t) ((tmp - utc_base) / 10000000L);
3693 static void
3694 convert_from_time_t (time_t time, FILETIME * pft)
3696 ULARGE_INTEGER tmp;
3698 if (!init)
3700 initialize_utc_base ();
3701 init = 1;
3704 /* time in 100ns units since 1-Jan-1601 */
3705 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
3706 pft->dwHighDateTime = tmp.HighPart;
3707 pft->dwLowDateTime = tmp.LowPart;
3710 #if 0
3711 /* No reason to keep this; faking inode values either by hashing or even
3712 using the file index from GetInformationByHandle, is not perfect and
3713 so by default Emacs doesn't use the inode values on Windows.
3714 Instead, we now determine file-truename correctly (except for
3715 possible drive aliasing etc). */
3717 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3718 static unsigned
3719 hashval (const unsigned char * str)
3721 unsigned h = 0;
3722 while (*str)
3724 h = (h << 4) + *str++;
3725 h ^= (h >> 28);
3727 return h;
3730 /* Return the hash value of the canonical pathname, excluding the
3731 drive/UNC header, to get a hopefully unique inode number. */
3732 static DWORD
3733 generate_inode_val (const char * name)
3735 char fullname[ MAX_PATH ];
3736 char * p;
3737 unsigned hash;
3739 /* Get the truly canonical filename, if it exists. (Note: this
3740 doesn't resolve aliasing due to subst commands, or recognize hard
3741 links. */
3742 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3743 emacs_abort ();
3745 parse_root (fullname, &p);
3746 /* Normal W32 filesystems are still case insensitive. */
3747 _strlwr (p);
3748 return hashval (p);
3751 #endif
3753 static PSECURITY_DESCRIPTOR
3754 get_file_security_desc_by_handle (HANDLE h)
3756 PSECURITY_DESCRIPTOR psd = NULL;
3757 DWORD err;
3758 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3759 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3761 err = get_security_info (h, SE_FILE_OBJECT, si,
3762 NULL, NULL, NULL, NULL, &psd);
3763 if (err != ERROR_SUCCESS)
3764 return NULL;
3766 return psd;
3769 static PSECURITY_DESCRIPTOR
3770 get_file_security_desc_by_name (const char *fname)
3772 PSECURITY_DESCRIPTOR psd = NULL;
3773 DWORD sd_len, err;
3774 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3775 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3777 if (!get_file_security (fname, si, psd, 0, &sd_len))
3779 err = GetLastError ();
3780 if (err != ERROR_INSUFFICIENT_BUFFER)
3781 return NULL;
3784 psd = xmalloc (sd_len);
3785 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3787 xfree (psd);
3788 return NULL;
3791 return psd;
3794 static DWORD
3795 get_rid (PSID sid)
3797 unsigned n_subauthorities;
3799 /* Use the last sub-authority value of the RID, the relative
3800 portion of the SID, as user/group ID. */
3801 n_subauthorities = *get_sid_sub_authority_count (sid);
3802 if (n_subauthorities < 1)
3803 return 0; /* the "World" RID */
3804 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3807 /* Caching SID and account values for faster lokup. */
3809 struct w32_id {
3810 unsigned rid;
3811 struct w32_id *next;
3812 char name[GNLEN+1];
3813 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3816 static struct w32_id *w32_idlist;
3818 static int
3819 w32_cached_id (PSID sid, unsigned *id, char *name)
3821 struct w32_id *tail, *found;
3823 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3825 if (equal_sid ((PSID)tail->sid, sid))
3827 found = tail;
3828 break;
3831 if (found)
3833 *id = found->rid;
3834 strcpy (name, found->name);
3835 return 1;
3837 else
3838 return 0;
3841 static void
3842 w32_add_to_cache (PSID sid, unsigned id, char *name)
3844 DWORD sid_len;
3845 struct w32_id *new_entry;
3847 /* We don't want to leave behind stale cache from when Emacs was
3848 dumped. */
3849 if (initialized)
3851 sid_len = get_length_sid (sid);
3852 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3853 if (new_entry)
3855 new_entry->rid = id;
3856 strcpy (new_entry->name, name);
3857 copy_sid (sid_len, (PSID)new_entry->sid, sid);
3858 new_entry->next = w32_idlist;
3859 w32_idlist = new_entry;
3864 #define UID 1
3865 #define GID 2
3867 static int
3868 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
3870 PSID sid = NULL;
3871 BOOL dflt;
3872 SID_NAME_USE ignore;
3873 char name[UNLEN+1];
3874 DWORD name_len = sizeof (name);
3875 char domain[1024];
3876 DWORD domain_len = sizeof (domain);
3877 int use_dflt = 0;
3878 int result;
3880 if (what == UID)
3881 result = get_security_descriptor_owner (psd, &sid, &dflt);
3882 else if (what == GID)
3883 result = get_security_descriptor_group (psd, &sid, &dflt);
3884 else
3885 result = 0;
3887 if (!result || !is_valid_sid (sid))
3888 use_dflt = 1;
3889 else if (!w32_cached_id (sid, id, nm))
3891 if (!lookup_account_sid (NULL, sid, name, &name_len,
3892 domain, &domain_len, &ignore)
3893 || name_len > UNLEN+1)
3894 use_dflt = 1;
3895 else
3897 *id = get_rid (sid);
3898 strcpy (nm, name);
3899 w32_add_to_cache (sid, *id, name);
3902 return use_dflt;
3905 static void
3906 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
3908 int dflt_usr = 0, dflt_grp = 0;
3910 if (!psd)
3912 dflt_usr = 1;
3913 dflt_grp = 1;
3915 else
3917 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
3918 dflt_usr = 1;
3919 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
3920 dflt_grp = 1;
3922 /* Consider files to belong to current user/group, if we cannot get
3923 more accurate information. */
3924 if (dflt_usr)
3926 st->st_uid = dflt_passwd.pw_uid;
3927 strcpy (st->st_uname, dflt_passwd.pw_name);
3929 if (dflt_grp)
3931 st->st_gid = dflt_passwd.pw_gid;
3932 strcpy (st->st_gname, dflt_group.gr_name);
3936 /* Return non-zero if NAME is a potentially slow filesystem. */
3938 is_slow_fs (const char *name)
3940 char drive_root[4];
3941 UINT devtype;
3943 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
3944 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
3945 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
3946 devtype = GetDriveType (NULL); /* use root of current drive */
3947 else
3949 /* GetDriveType needs the root directory of the drive. */
3950 strncpy (drive_root, name, 2);
3951 drive_root[2] = '\\';
3952 drive_root[3] = '\0';
3953 devtype = GetDriveType (drive_root);
3955 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
3958 /* If this is non-zero, the caller wants accurate information about
3959 file's owner and group, which could be expensive to get. */
3960 int w32_stat_get_owner_group;
3962 /* MSVC stat function can't cope with UNC names and has other bugs, so
3963 replace it with our own. This also allows us to calculate consistent
3964 inode values and owner/group without hacks in the main Emacs code. */
3966 static int
3967 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
3969 char *name, *save_name, *r;
3970 WIN32_FIND_DATA wfd;
3971 HANDLE fh;
3972 unsigned __int64 fake_inode = 0;
3973 int permission;
3974 int len;
3975 int rootdir = FALSE;
3976 PSECURITY_DESCRIPTOR psd = NULL;
3977 int is_a_symlink = 0;
3978 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
3979 DWORD access_rights = 0;
3980 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
3981 FILETIME ctime, atime, wtime;
3982 int dbcs_p;
3984 if (path == NULL || buf == NULL)
3986 errno = EFAULT;
3987 return -1;
3990 save_name = name = (char *) map_w32_filename (path, &path);
3991 /* Must be valid filename, no wild cards or other invalid
3992 characters. We use _mbspbrk to support multibyte strings that
3993 might look to strpbrk as if they included literal *, ?, and other
3994 characters mentioned below that are disallowed by Windows
3995 filesystems. */
3996 if (_mbspbrk (name, "*?|<>\""))
3998 errno = ENOENT;
3999 return -1;
4002 /* Remove trailing directory separator, unless name is the root
4003 directory of a drive or UNC volume in which case ensure there
4004 is a trailing separator. */
4005 len = strlen (name);
4006 name = strcpy (alloca (len + 2), name);
4008 /* Avoid a somewhat costly call to is_symlink if the filesystem
4009 doesn't support symlinks. */
4010 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4011 is_a_symlink = is_symlink (name);
4013 /* Plan A: Open the file and get all the necessary information via
4014 the resulting handle. This solves several issues in one blow:
4016 . retrieves attributes for the target of a symlink, if needed
4017 . gets attributes of root directories and symlinks pointing to
4018 root directories, thus avoiding the need for special-casing
4019 these and detecting them by examining the file-name format
4020 . retrieves more accurate attributes (e.g., non-zero size for
4021 some directories, esp. directories that are junction points)
4022 . correctly resolves "c:/..", "/.." and similar file names
4023 . avoids run-time penalties for 99% of use cases
4025 Plan A is always tried first, unless the user asked not to (but
4026 if the file is a symlink and we need to follow links, we try Plan
4027 A even if the user asked not to).
4029 If Plan A fails, we go to Plan B (below), where various
4030 potentially expensive techniques must be used to handle "special"
4031 files such as UNC volumes etc. */
4032 if (!(NILP (Vw32_get_true_file_attributes)
4033 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
4034 /* Following symlinks requires getting the info by handle. */
4035 || (is_a_symlink && follow_symlinks))
4037 BY_HANDLE_FILE_INFORMATION info;
4039 if (is_a_symlink && !follow_symlinks)
4040 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
4041 /* READ_CONTROL access rights are required to get security info
4042 by handle. But if the OS doesn't support security in the
4043 first place, we don't need to try. */
4044 if (is_windows_9x () != TRUE)
4045 access_rights |= READ_CONTROL;
4047 fh = CreateFile (name, access_rights, 0, NULL, OPEN_EXISTING,
4048 file_flags, NULL);
4049 /* If CreateFile fails with READ_CONTROL, try again with zero as
4050 access rights. */
4051 if (fh == INVALID_HANDLE_VALUE && access_rights)
4052 fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
4053 file_flags, NULL);
4054 if (fh == INVALID_HANDLE_VALUE)
4055 goto no_true_file_attributes;
4057 /* This is more accurate in terms of getting the correct number
4058 of links, but is quite slow (it is noticeable when Emacs is
4059 making a list of file name completions). */
4060 if (GetFileInformationByHandle (fh, &info))
4062 nlinks = info.nNumberOfLinks;
4063 /* Might as well use file index to fake inode values, but this
4064 is not guaranteed to be unique unless we keep a handle open
4065 all the time (even then there are situations where it is
4066 not unique). Reputedly, there are at most 48 bits of info
4067 (on NTFS, presumably less on FAT). */
4068 fake_inode = info.nFileIndexHigh;
4069 fake_inode <<= 32;
4070 fake_inode += info.nFileIndexLow;
4071 serialnum = info.dwVolumeSerialNumber;
4072 fs_high = info.nFileSizeHigh;
4073 fs_low = info.nFileSizeLow;
4074 ctime = info.ftCreationTime;
4075 atime = info.ftLastAccessTime;
4076 wtime = info.ftLastWriteTime;
4077 fattrs = info.dwFileAttributes;
4079 else
4081 /* We don't go to Plan B here, because it's not clear that
4082 it's a good idea. The only known use case where
4083 CreateFile succeeds, but GetFileInformationByHandle fails
4084 (with ERROR_INVALID_FUNCTION) is for character devices
4085 such as NUL, PRN, etc. For these, switching to Plan B is
4086 a net loss, because we lose the character device
4087 attribute returned by GetFileType below (FindFirstFile
4088 doesn't set that bit in the attributes), and the other
4089 fields don't make sense for character devices anyway.
4090 Emacs doesn't really care for non-file entities in the
4091 context of l?stat, so neither do we. */
4093 /* w32err is assigned so one could put a breakpoint here and
4094 examine its value, when GetFileInformationByHandle
4095 fails. */
4096 DWORD w32err = GetLastError ();
4098 switch (w32err)
4100 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
4101 errno = ENOENT;
4102 return -1;
4106 /* Test for a symlink before testing for a directory, since
4107 symlinks to directories have the directory bit set, but we
4108 don't want them to appear as directories. */
4109 if (is_a_symlink && !follow_symlinks)
4110 buf->st_mode = S_IFLNK;
4111 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4112 buf->st_mode = S_IFDIR;
4113 else
4115 DWORD ftype = GetFileType (fh);
4117 switch (ftype)
4119 case FILE_TYPE_DISK:
4120 buf->st_mode = S_IFREG;
4121 break;
4122 case FILE_TYPE_PIPE:
4123 buf->st_mode = S_IFIFO;
4124 break;
4125 case FILE_TYPE_CHAR:
4126 case FILE_TYPE_UNKNOWN:
4127 default:
4128 buf->st_mode = S_IFCHR;
4131 /* We produce the fallback owner and group data, based on the
4132 current user that runs Emacs, in the following cases:
4134 . caller didn't request owner and group info
4135 . this is Windows 9X
4136 . getting security by handle failed, and we need to produce
4137 information for the target of a symlink (this is better
4138 than producing a potentially misleading info about the
4139 symlink itself)
4141 If getting security by handle fails, and we don't need to
4142 resolve symlinks, we try getting security by name. */
4143 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4144 get_file_owner_and_group (NULL, buf);
4145 else
4147 psd = get_file_security_desc_by_handle (fh);
4148 if (psd)
4150 get_file_owner_and_group (psd, buf);
4151 LocalFree (psd);
4153 else if (!(is_a_symlink && follow_symlinks))
4155 psd = get_file_security_desc_by_name (name);
4156 get_file_owner_and_group (psd, buf);
4157 xfree (psd);
4159 else
4160 get_file_owner_and_group (NULL, buf);
4162 CloseHandle (fh);
4164 else
4166 no_true_file_attributes:
4167 /* Plan B: Either getting a handle on the file failed, or the
4168 caller explicitly asked us to not bother making this
4169 information more accurate.
4171 Implementation note: In Plan B, we never bother to resolve
4172 symlinks, even if we got here because we tried Plan A and
4173 failed. That's because, even if the caller asked for extra
4174 precision by setting Vw32_get_true_file_attributes to t,
4175 resolving symlinks requires acquiring a file handle to the
4176 symlink, which we already know will fail. And if the user
4177 did not ask for extra precision, resolving symlinks will fly
4178 in the face of that request, since the user then wants the
4179 lightweight version of the code. */
4180 dbcs_p = max_filename_mbslen () > 1;
4181 rootdir = (path >= save_name + len - 1
4182 && (IS_DIRECTORY_SEP (*path) || *path == 0));
4184 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4185 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
4186 if (IS_DIRECTORY_SEP (r[0])
4187 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
4188 r[1] = r[2] = '\0';
4190 /* Note: If NAME is a symlink to the root of a UNC volume
4191 (i.e. "\\SERVER"), we will not detect that here, and we will
4192 return data about the symlink as result of FindFirst below.
4193 This is unfortunate, but that marginal use case does not
4194 justify a call to chase_symlinks which would impose a penalty
4195 on all the other use cases. (We get here for symlinks to
4196 roots of UNC volumes because CreateFile above fails for them,
4197 unlike with symlinks to root directories X:\ of drives.) */
4198 if (is_unc_volume (name))
4200 fattrs = unc_volume_file_attributes (name);
4201 if (fattrs == -1)
4202 return -1;
4204 ctime = atime = wtime = utc_base_ft;
4206 else if (rootdir)
4208 if (!dbcs_p)
4210 if (!IS_DIRECTORY_SEP (name[len-1]))
4211 strcat (name, "\\");
4213 else
4215 char *end = name + len;
4216 char *n = CharPrevExA (file_name_codepage, name, end, 0);
4218 if (!IS_DIRECTORY_SEP (*n))
4219 strcat (name, "\\");
4221 if (GetDriveType (name) < 2)
4223 errno = ENOENT;
4224 return -1;
4227 fattrs = FILE_ATTRIBUTE_DIRECTORY;
4228 ctime = atime = wtime = utc_base_ft;
4230 else
4232 if (!dbcs_p)
4234 if (IS_DIRECTORY_SEP (name[len-1]))
4235 name[len - 1] = 0;
4237 else
4239 char *end = name + len;
4240 char *n = CharPrevExA (file_name_codepage, name, end, 0);
4242 if (IS_DIRECTORY_SEP (*n))
4243 *n = 0;
4246 /* (This is hacky, but helps when doing file completions on
4247 network drives.) Optimize by using information available from
4248 active readdir if possible. */
4249 len = strlen (dir_pathname);
4250 if (!dbcs_p)
4252 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
4253 len--;
4255 else
4257 char *end = dir_pathname + len;
4258 char *n = CharPrevExA (file_name_codepage, dir_pathname, end, 0);
4260 if (IS_DIRECTORY_SEP (*n))
4261 len--;
4263 if (dir_find_handle != INVALID_HANDLE_VALUE
4264 && !(is_a_symlink && follow_symlinks)
4265 && strnicmp (save_name, dir_pathname, len) == 0
4266 && IS_DIRECTORY_SEP (name[len])
4267 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
4269 /* This was the last entry returned by readdir. */
4270 wfd = dir_find_data;
4272 else
4274 logon_network_drive (name);
4276 fh = FindFirstFile (name, &wfd);
4277 if (fh == INVALID_HANDLE_VALUE)
4279 errno = ENOENT;
4280 return -1;
4282 FindClose (fh);
4284 /* Note: if NAME is a symlink, the information we get from
4285 FindFirstFile is for the symlink, not its target. */
4286 fattrs = wfd.dwFileAttributes;
4287 ctime = wfd.ftCreationTime;
4288 atime = wfd.ftLastAccessTime;
4289 wtime = wfd.ftLastWriteTime;
4290 fs_high = wfd.nFileSizeHigh;
4291 fs_low = wfd.nFileSizeLow;
4292 fake_inode = 0;
4293 nlinks = 1;
4294 serialnum = volume_info.serialnum;
4296 if (is_a_symlink && !follow_symlinks)
4297 buf->st_mode = S_IFLNK;
4298 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4299 buf->st_mode = S_IFDIR;
4300 else
4301 buf->st_mode = S_IFREG;
4303 get_file_owner_and_group (NULL, buf);
4306 #if 0
4307 /* Not sure if there is any point in this. */
4308 if (!NILP (Vw32_generate_fake_inodes))
4309 fake_inode = generate_inode_val (name);
4310 else if (fake_inode == 0)
4312 /* For want of something better, try to make everything unique. */
4313 static DWORD gen_num = 0;
4314 fake_inode = ++gen_num;
4316 #endif
4318 buf->st_ino = fake_inode;
4320 buf->st_dev = serialnum;
4321 buf->st_rdev = serialnum;
4323 buf->st_size = fs_high;
4324 buf->st_size <<= 32;
4325 buf->st_size += fs_low;
4326 buf->st_nlink = nlinks;
4328 /* Convert timestamps to Unix format. */
4329 buf->st_mtime = convert_time (wtime);
4330 buf->st_atime = convert_time (atime);
4331 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
4332 buf->st_ctime = convert_time (ctime);
4333 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
4335 /* determine rwx permissions */
4336 if (is_a_symlink && !follow_symlinks)
4337 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
4338 else
4340 if (fattrs & FILE_ATTRIBUTE_READONLY)
4341 permission = S_IREAD;
4342 else
4343 permission = S_IREAD | S_IWRITE;
4345 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4346 permission |= S_IEXEC;
4347 else if (is_exec (name))
4348 permission |= S_IEXEC;
4351 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
4353 return 0;
4357 stat (const char * path, struct stat * buf)
4359 return stat_worker (path, buf, 1);
4363 lstat (const char * path, struct stat * buf)
4365 return stat_worker (path, buf, 0);
4369 fstatat (int fd, char const *name, struct stat *st, int flags)
4371 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4372 This is good enough for the current usage in Emacs, but is fragile.
4374 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4375 Gnulib does this and can serve as a model. */
4376 char fullname[MAX_PATH];
4378 if (fd != AT_FDCWD)
4380 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
4381 < 0)
4383 errno = ENAMETOOLONG;
4384 return -1;
4386 name = fullname;
4389 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
4392 /* Provide fstat and utime as well as stat for consistent handling of
4393 file timestamps. */
4395 fstat (int desc, struct stat * buf)
4397 HANDLE fh = (HANDLE) _get_osfhandle (desc);
4398 BY_HANDLE_FILE_INFORMATION info;
4399 unsigned __int64 fake_inode;
4400 int permission;
4402 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
4404 case FILE_TYPE_DISK:
4405 buf->st_mode = S_IFREG;
4406 if (!GetFileInformationByHandle (fh, &info))
4408 errno = EACCES;
4409 return -1;
4411 break;
4412 case FILE_TYPE_PIPE:
4413 buf->st_mode = S_IFIFO;
4414 goto non_disk;
4415 case FILE_TYPE_CHAR:
4416 case FILE_TYPE_UNKNOWN:
4417 default:
4418 buf->st_mode = S_IFCHR;
4419 non_disk:
4420 memset (&info, 0, sizeof (info));
4421 info.dwFileAttributes = 0;
4422 info.ftCreationTime = utc_base_ft;
4423 info.ftLastAccessTime = utc_base_ft;
4424 info.ftLastWriteTime = utc_base_ft;
4427 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
4428 buf->st_mode = S_IFDIR;
4430 buf->st_nlink = info.nNumberOfLinks;
4431 /* Might as well use file index to fake inode values, but this
4432 is not guaranteed to be unique unless we keep a handle open
4433 all the time (even then there are situations where it is
4434 not unique). Reputedly, there are at most 48 bits of info
4435 (on NTFS, presumably less on FAT). */
4436 fake_inode = info.nFileIndexHigh;
4437 fake_inode <<= 32;
4438 fake_inode += info.nFileIndexLow;
4440 /* MSVC defines _ino_t to be short; other libc's might not. */
4441 if (sizeof (buf->st_ino) == 2)
4442 buf->st_ino = fake_inode ^ (fake_inode >> 16);
4443 else
4444 buf->st_ino = fake_inode;
4446 /* If the caller so requested, get the true file owner and group.
4447 Otherwise, consider the file to belong to the current user. */
4448 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4449 get_file_owner_and_group (NULL, buf);
4450 else
4452 PSECURITY_DESCRIPTOR psd = NULL;
4454 psd = get_file_security_desc_by_handle (fh);
4455 if (psd)
4457 get_file_owner_and_group (psd, buf);
4458 LocalFree (psd);
4460 else
4461 get_file_owner_and_group (NULL, buf);
4464 buf->st_dev = info.dwVolumeSerialNumber;
4465 buf->st_rdev = info.dwVolumeSerialNumber;
4467 buf->st_size = info.nFileSizeHigh;
4468 buf->st_size <<= 32;
4469 buf->st_size += info.nFileSizeLow;
4471 /* Convert timestamps to Unix format. */
4472 buf->st_mtime = convert_time (info.ftLastWriteTime);
4473 buf->st_atime = convert_time (info.ftLastAccessTime);
4474 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
4475 buf->st_ctime = convert_time (info.ftCreationTime);
4476 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
4478 /* determine rwx permissions */
4479 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
4480 permission = S_IREAD;
4481 else
4482 permission = S_IREAD | S_IWRITE;
4484 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
4485 permission |= S_IEXEC;
4486 else
4488 #if 0 /* no way of knowing the filename */
4489 char * p = strrchr (name, '.');
4490 if (p != NULL &&
4491 (xstrcasecmp (p, ".exe") == 0 ||
4492 xstrcasecmp (p, ".com") == 0 ||
4493 xstrcasecmp (p, ".bat") == 0 ||
4494 xstrcasecmp (p, ".cmd") == 0))
4495 permission |= S_IEXEC;
4496 #endif
4499 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
4501 return 0;
4505 utime (const char *name, struct utimbuf *times)
4507 struct utimbuf deftime;
4508 HANDLE fh;
4509 FILETIME mtime;
4510 FILETIME atime;
4512 if (times == NULL)
4514 deftime.modtime = deftime.actime = time (NULL);
4515 times = &deftime;
4518 /* Need write access to set times. */
4519 fh = CreateFile (name, FILE_WRITE_ATTRIBUTES,
4520 /* If NAME specifies a directory, FILE_SHARE_DELETE
4521 allows other processes to delete files inside it,
4522 while we have the directory open. */
4523 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4524 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
4525 if (fh != INVALID_HANDLE_VALUE)
4527 convert_from_time_t (times->actime, &atime);
4528 convert_from_time_t (times->modtime, &mtime);
4529 if (!SetFileTime (fh, NULL, &atime, &mtime))
4531 CloseHandle (fh);
4532 errno = EACCES;
4533 return -1;
4535 CloseHandle (fh);
4537 else
4539 errno = EINVAL;
4540 return -1;
4542 return 0;
4546 /* Symlink-related functions. */
4547 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4548 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4549 #endif
4552 symlink (char const *filename, char const *linkname)
4554 char linkfn[MAX_PATH], *tgtfn;
4555 DWORD flags = 0;
4556 int dir_access, filename_ends_in_slash;
4557 int dbcs_p;
4559 /* Diagnostics follows Posix as much as possible. */
4560 if (filename == NULL || linkname == NULL)
4562 errno = EFAULT;
4563 return -1;
4565 if (!*filename)
4567 errno = ENOENT;
4568 return -1;
4570 if (strlen (filename) > MAX_PATH || strlen (linkname) > MAX_PATH)
4572 errno = ENAMETOOLONG;
4573 return -1;
4576 strcpy (linkfn, map_w32_filename (linkname, NULL));
4577 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
4579 errno = EPERM;
4580 return -1;
4583 dbcs_p = max_filename_mbslen () > 1;
4585 /* Note: since empty FILENAME was already rejected, we can safely
4586 refer to FILENAME[1]. */
4587 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
4589 /* Non-absolute FILENAME is understood as being relative to
4590 LINKNAME's directory. We need to prepend that directory to
4591 FILENAME to get correct results from faccessat below, since
4592 otherwise it will interpret FILENAME relative to the
4593 directory where the Emacs process runs. Note that
4594 make-symbolic-link always makes sure LINKNAME is a fully
4595 expanded file name. */
4596 char tem[MAX_PATH];
4597 char *p = linkfn + strlen (linkfn);
4599 if (!dbcs_p)
4601 while (p > linkfn && !IS_ANY_SEP (p[-1]))
4602 p--;
4604 else
4606 char *p1 = CharPrevExA (file_name_codepage, linkfn, p, 0);
4608 while (p > linkfn && !IS_ANY_SEP (*p1))
4610 p = p1;
4611 p1 = CharPrevExA (file_name_codepage, linkfn, p1, 0);
4614 if (p > linkfn)
4615 strncpy (tem, linkfn, p - linkfn);
4616 tem[p - linkfn] = '\0';
4617 strcat (tem, filename);
4618 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
4620 else
4621 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
4623 /* Since Windows distinguishes between symlinks to directories and
4624 to files, we provide a kludgy feature: if FILENAME doesn't
4625 exist, but ends in a slash, we create a symlink to directory. If
4626 FILENAME exists and is a directory, we always create a symlink to
4627 directory. */
4628 if (!dbcs_p)
4629 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
4630 else
4632 const char *end = filename + strlen (filename);
4633 const char *n = CharPrevExA (file_name_codepage, filename, end, 0);
4635 filename_ends_in_slash = IS_DIRECTORY_SEP (*n);
4637 if (dir_access == 0 || filename_ends_in_slash)
4638 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
4640 tgtfn = (char *)map_w32_filename (filename, NULL);
4641 if (filename_ends_in_slash)
4642 tgtfn[strlen (tgtfn) - 1] = '\0';
4644 errno = 0;
4645 if (!create_symbolic_link (linkfn, tgtfn, flags))
4647 /* ENOSYS is set by create_symbolic_link, when it detects that
4648 the OS doesn't support the CreateSymbolicLink API. */
4649 if (errno != ENOSYS)
4651 DWORD w32err = GetLastError ();
4653 switch (w32err)
4655 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4656 TGTFN point to the same file name, go figure. */
4657 case ERROR_SUCCESS:
4658 case ERROR_FILE_EXISTS:
4659 errno = EEXIST;
4660 break;
4661 case ERROR_ACCESS_DENIED:
4662 errno = EACCES;
4663 break;
4664 case ERROR_FILE_NOT_FOUND:
4665 case ERROR_PATH_NOT_FOUND:
4666 case ERROR_BAD_NETPATH:
4667 case ERROR_INVALID_REPARSE_DATA:
4668 errno = ENOENT;
4669 break;
4670 case ERROR_DIRECTORY:
4671 errno = EISDIR;
4672 break;
4673 case ERROR_PRIVILEGE_NOT_HELD:
4674 case ERROR_NOT_ALL_ASSIGNED:
4675 errno = EPERM;
4676 break;
4677 case ERROR_DISK_FULL:
4678 errno = ENOSPC;
4679 break;
4680 default:
4681 errno = EINVAL;
4682 break;
4685 return -1;
4687 return 0;
4690 /* A quick inexpensive test of whether FILENAME identifies a file that
4691 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4692 must already be in the normalized form returned by
4693 map_w32_filename.
4695 Note: for repeated operations on many files, it is best to test
4696 whether the underlying volume actually supports symlinks, by
4697 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4698 avoid the call to this function if it doesn't. That's because the
4699 call to GetFileAttributes takes a non-negligible time, especially
4700 on non-local or removable filesystems. See stat_worker for an
4701 example of how to do that. */
4702 static int
4703 is_symlink (const char *filename)
4705 DWORD attrs;
4706 WIN32_FIND_DATA wfd;
4707 HANDLE fh;
4709 attrs = GetFileAttributes (filename);
4710 if (attrs == -1)
4712 DWORD w32err = GetLastError ();
4714 switch (w32err)
4716 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
4717 break;
4718 case ERROR_ACCESS_DENIED:
4719 errno = EACCES;
4720 break;
4721 case ERROR_FILE_NOT_FOUND:
4722 case ERROR_PATH_NOT_FOUND:
4723 default:
4724 errno = ENOENT;
4725 break;
4727 return 0;
4729 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
4730 return 0;
4731 logon_network_drive (filename);
4732 fh = FindFirstFile (filename, &wfd);
4733 if (fh == INVALID_HANDLE_VALUE)
4734 return 0;
4735 FindClose (fh);
4736 return (wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
4737 && (wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
4740 /* If NAME identifies a symbolic link, copy into BUF the file name of
4741 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4742 null-terminate the target name, even if it fits. Return the number
4743 of bytes copied, or -1 if NAME is not a symlink or any error was
4744 encountered while resolving it. The file name copied into BUF is
4745 encoded in the current ANSI codepage. */
4746 ssize_t
4747 readlink (const char *name, char *buf, size_t buf_size)
4749 const char *path;
4750 TOKEN_PRIVILEGES privs;
4751 int restore_privs = 0;
4752 HANDLE sh;
4753 ssize_t retval;
4755 if (name == NULL)
4757 errno = EFAULT;
4758 return -1;
4760 if (!*name)
4762 errno = ENOENT;
4763 return -1;
4766 path = map_w32_filename (name, NULL);
4768 if (strlen (path) > MAX_PATH)
4770 errno = ENAMETOOLONG;
4771 return -1;
4774 errno = 0;
4775 if (is_windows_9x () == TRUE
4776 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
4777 || !is_symlink (path))
4779 if (!errno)
4780 errno = EINVAL; /* not a symlink */
4781 return -1;
4784 /* Done with simple tests, now we're in for some _real_ work. */
4785 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
4786 restore_privs = 1;
4787 /* Implementation note: From here and onward, don't return early,
4788 since that will fail to restore the original set of privileges of
4789 the calling thread. */
4791 retval = -1; /* not too optimistic, are we? */
4793 /* Note: In the next call to CreateFile, we use zero as the 2nd
4794 argument because, when the symlink is a hidden/system file,
4795 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4796 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4797 and directory symlinks. */
4798 sh = CreateFile (path, 0, 0, NULL, OPEN_EXISTING,
4799 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
4800 NULL);
4801 if (sh != INVALID_HANDLE_VALUE)
4803 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
4804 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
4805 DWORD retbytes;
4807 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
4808 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
4809 &retbytes, NULL))
4810 errno = EIO;
4811 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
4812 errno = EINVAL;
4813 else
4815 /* Copy the link target name, in wide characters, from
4816 reparse_data, then convert it to multibyte encoding in
4817 the current locale's codepage. */
4818 WCHAR *lwname;
4819 BYTE lname[MAX_PATH];
4820 USHORT lname_len;
4821 USHORT lwname_len =
4822 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
4823 WCHAR *lwname_src =
4824 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
4825 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
4826 /* This updates file_name_codepage which we need below. */
4827 int dbcs_p = max_filename_mbslen () > 1;
4829 /* According to MSDN, PrintNameLength does not include the
4830 terminating null character. */
4831 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
4832 memcpy (lwname, lwname_src, lwname_len);
4833 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
4835 lname_len = WideCharToMultiByte (file_name_codepage, 0, lwname, -1,
4836 lname, MAX_PATH, NULL, NULL);
4837 if (!lname_len)
4839 /* WideCharToMultiByte failed. */
4840 DWORD w32err1 = GetLastError ();
4842 switch (w32err1)
4844 case ERROR_INSUFFICIENT_BUFFER:
4845 errno = ENAMETOOLONG;
4846 break;
4847 case ERROR_INVALID_PARAMETER:
4848 errno = EFAULT;
4849 break;
4850 case ERROR_NO_UNICODE_TRANSLATION:
4851 errno = ENOENT;
4852 break;
4853 default:
4854 errno = EINVAL;
4855 break;
4858 else
4860 size_t size_to_copy = buf_size;
4861 BYTE *p = lname, *p2;
4862 BYTE *pend = p + lname_len;
4864 /* Normalize like dostounix_filename does, but we don't
4865 want to assume that lname is null-terminated. */
4866 if (dbcs_p)
4867 p2 = CharNextExA (file_name_codepage, p, 0);
4868 else
4869 p2 = p + 1;
4870 if (*p && *p2 == ':' && *p >= 'A' && *p <= 'Z')
4872 *p += 'a' - 'A';
4873 p += 2;
4875 while (p <= pend)
4877 if (*p == '\\')
4878 *p = '/';
4879 if (dbcs_p)
4881 p = CharNextExA (file_name_codepage, p, 0);
4882 /* CharNextExA doesn't advance at null character. */
4883 if (!*p)
4884 break;
4886 else
4887 ++p;
4889 /* Testing for null-terminated LNAME is paranoia:
4890 WideCharToMultiByte should always return a
4891 null-terminated string when its 4th argument is -1
4892 and its 3rd argument is null-terminated (which they
4893 are, see above). */
4894 if (lname[lname_len - 1] == '\0')
4895 lname_len--;
4896 if (lname_len <= buf_size)
4897 size_to_copy = lname_len;
4898 strncpy (buf, lname, size_to_copy);
4899 /* Success! */
4900 retval = size_to_copy;
4903 CloseHandle (sh);
4905 else
4907 /* CreateFile failed. */
4908 DWORD w32err2 = GetLastError ();
4910 switch (w32err2)
4912 case ERROR_FILE_NOT_FOUND:
4913 case ERROR_PATH_NOT_FOUND:
4914 errno = ENOENT;
4915 break;
4916 case ERROR_ACCESS_DENIED:
4917 case ERROR_TOO_MANY_OPEN_FILES:
4918 errno = EACCES;
4919 break;
4920 default:
4921 errno = EPERM;
4922 break;
4925 if (restore_privs)
4927 restore_privilege (&privs);
4928 revert_to_self ();
4931 return retval;
4934 ssize_t
4935 readlinkat (int fd, char const *name, char *buffer,
4936 size_t buffer_size)
4938 /* Rely on a hack: an open directory is modeled as file descriptor 0,
4939 as in fstatat. FIXME: Add proper support for readlinkat. */
4940 char fullname[MAX_PATH];
4942 if (fd != AT_FDCWD)
4944 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
4945 < 0)
4947 errno = ENAMETOOLONG;
4948 return -1;
4950 name = fullname;
4953 return readlink (name, buffer, buffer_size);
4956 /* If FILE is a symlink, return its target (stored in a static
4957 buffer); otherwise return FILE.
4959 This function repeatedly resolves symlinks in the last component of
4960 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4961 until it arrives at a file whose last component is not a symlink,
4962 or some error occurs. It returns the target of the last
4963 successfully resolved symlink in the chain. If it succeeds to
4964 resolve even a single symlink, the value returned is an absolute
4965 file name with backslashes (result of GetFullPathName). By
4966 contrast, if the original FILE is returned, it is unaltered.
4968 Note: This function can set errno even if it succeeds.
4970 Implementation note: we only resolve the last portion ("basename")
4971 of the argument FILE and of each following file in the chain,
4972 disregarding any possible symlinks in its leading directories.
4973 This is because Windows system calls and library functions
4974 transparently resolve symlinks in leading directories and return
4975 correct information, as long as the basename is not a symlink. */
4976 static char *
4977 chase_symlinks (const char *file)
4979 static char target[MAX_PATH];
4980 char link[MAX_PATH];
4981 ssize_t res, link_len;
4982 int loop_count = 0;
4983 int dbcs_p;
4985 if (is_windows_9x () == TRUE || !is_symlink (file))
4986 return (char *)file;
4988 if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0)
4989 return (char *)file;
4991 dbcs_p = max_filename_mbslen () > 1;
4992 target[0] = '\0';
4993 do {
4995 /* Remove trailing slashes, as we want to resolve the last
4996 non-trivial part of the link name. */
4997 if (!dbcs_p)
4999 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
5000 link[link_len--] = '\0';
5002 else if (link_len > 3)
5004 char *n = CharPrevExA (file_name_codepage, link, link + link_len, 0);
5006 while (n >= link + 2 && IS_DIRECTORY_SEP (*n))
5008 n[1] = '\0';
5009 n = CharPrevExA (file_name_codepage, link, n, 0);
5013 res = readlink (link, target, MAX_PATH);
5014 if (res > 0)
5016 target[res] = '\0';
5017 if (!(IS_DEVICE_SEP (target[1])
5018 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
5020 /* Target is relative. Append it to the directory part of
5021 the symlink, then copy the result back to target. */
5022 char *p = link + link_len;
5024 if (!dbcs_p)
5026 while (p > link && !IS_ANY_SEP (p[-1]))
5027 p--;
5029 else
5031 char *p1 = CharPrevExA (file_name_codepage, link, p, 0);
5033 while (p > link && !IS_ANY_SEP (*p1))
5035 p = p1;
5036 p1 = CharPrevExA (file_name_codepage, link, p1, 0);
5039 strcpy (p, target);
5040 strcpy (target, link);
5042 /* Resolve any "." and ".." to get a fully-qualified file name
5043 in link[] again. */
5044 link_len = GetFullPathName (target, MAX_PATH, link, NULL);
5046 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
5048 if (loop_count > 100)
5049 errno = ELOOP;
5051 if (target[0] == '\0') /* not a single call to readlink succeeded */
5052 return (char *)file;
5053 return target;
5057 /* Posix ACL emulation. */
5060 acl_valid (acl_t acl)
5062 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
5065 char *
5066 acl_to_text (acl_t acl, ssize_t *size)
5068 LPTSTR str_acl;
5069 SECURITY_INFORMATION flags =
5070 OWNER_SECURITY_INFORMATION |
5071 GROUP_SECURITY_INFORMATION |
5072 DACL_SECURITY_INFORMATION;
5073 char *retval = NULL;
5074 ULONG local_size;
5075 int e = errno;
5077 errno = 0;
5079 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
5081 errno = e;
5082 /* We don't want to mix heaps, so we duplicate the string in our
5083 heap and free the one allocated by the API. */
5084 retval = xstrdup (str_acl);
5085 if (size)
5086 *size = local_size;
5087 LocalFree (str_acl);
5089 else if (errno != ENOTSUP)
5090 errno = EINVAL;
5092 return retval;
5095 acl_t
5096 acl_from_text (const char *acl_str)
5098 PSECURITY_DESCRIPTOR psd, retval = NULL;
5099 ULONG sd_size;
5100 int e = errno;
5102 errno = 0;
5104 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
5106 errno = e;
5107 retval = xmalloc (sd_size);
5108 memcpy (retval, psd, sd_size);
5109 LocalFree (psd);
5111 else if (errno != ENOTSUP)
5112 errno = EINVAL;
5114 return retval;
5118 acl_free (void *ptr)
5120 xfree (ptr);
5121 return 0;
5124 acl_t
5125 acl_get_file (const char *fname, acl_type_t type)
5127 PSECURITY_DESCRIPTOR psd = NULL;
5128 const char *filename;
5130 if (type == ACL_TYPE_ACCESS)
5132 DWORD sd_len, err;
5133 SECURITY_INFORMATION si =
5134 OWNER_SECURITY_INFORMATION |
5135 GROUP_SECURITY_INFORMATION |
5136 DACL_SECURITY_INFORMATION ;
5137 int e = errno;
5139 filename = map_w32_filename (fname, NULL);
5140 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5141 fname = chase_symlinks (filename);
5142 else
5143 fname = filename;
5145 errno = 0;
5146 if (!get_file_security (fname, si, psd, 0, &sd_len)
5147 && errno != ENOTSUP)
5149 err = GetLastError ();
5150 if (err == ERROR_INSUFFICIENT_BUFFER)
5152 psd = xmalloc (sd_len);
5153 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
5155 xfree (psd);
5156 errno = EIO;
5157 psd = NULL;
5160 else if (err == ERROR_FILE_NOT_FOUND
5161 || err == ERROR_PATH_NOT_FOUND)
5162 errno = ENOENT;
5163 else
5164 errno = EIO;
5166 else if (!errno)
5167 errno = e;
5169 else if (type != ACL_TYPE_DEFAULT)
5170 errno = EINVAL;
5172 return psd;
5176 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
5178 TOKEN_PRIVILEGES old1, old2;
5179 DWORD err;
5180 int st = 0, retval = -1;
5181 SECURITY_INFORMATION flags = 0;
5182 PSID psid;
5183 PACL pacl;
5184 BOOL dflt;
5185 BOOL dacl_present;
5186 int e;
5187 const char *filename;
5189 if (acl_valid (acl) != 0
5190 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
5192 errno = EINVAL;
5193 return -1;
5196 if (type == ACL_TYPE_DEFAULT)
5198 errno = ENOSYS;
5199 return -1;
5202 filename = map_w32_filename (fname, NULL);
5203 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5204 fname = chase_symlinks (filename);
5205 else
5206 fname = filename;
5208 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
5209 && psid)
5210 flags |= OWNER_SECURITY_INFORMATION;
5211 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
5212 && psid)
5213 flags |= GROUP_SECURITY_INFORMATION;
5214 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
5215 &pacl, &dflt)
5216 && dacl_present)
5217 flags |= DACL_SECURITY_INFORMATION;
5218 if (!flags)
5219 return 0;
5221 /* According to KB-245153, setting the owner will succeed if either:
5222 (1) the caller is the user who will be the new owner, and has the
5223 SE_TAKE_OWNERSHIP privilege, or
5224 (2) the caller has the SE_RESTORE privilege, in which case she can
5225 set any valid user or group as the owner
5227 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5228 privileges, and disregard any failures in obtaining them. If
5229 these privileges cannot be obtained, and do not already exist in
5230 the calling thread's security token, this function could fail
5231 with EPERM. */
5232 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
5233 st++;
5234 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
5235 st++;
5237 e = errno;
5238 errno = 0;
5239 if (!set_file_security ((char *)fname, flags, (PSECURITY_DESCRIPTOR)acl))
5241 err = GetLastError ();
5243 if (errno == ENOTSUP)
5245 else if (err == ERROR_INVALID_OWNER
5246 || err == ERROR_NOT_ALL_ASSIGNED
5247 || err == ERROR_ACCESS_DENIED)
5249 /* Maybe the requested ACL and the one the file already has
5250 are identical, in which case we can silently ignore the
5251 failure. (And no, Windows doesn't.) */
5252 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
5254 errno = EPERM;
5255 if (current_acl)
5257 char *acl_from = acl_to_text (current_acl, NULL);
5258 char *acl_to = acl_to_text (acl, NULL);
5260 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
5262 retval = 0;
5263 errno = e;
5265 if (acl_from)
5266 acl_free (acl_from);
5267 if (acl_to)
5268 acl_free (acl_to);
5269 acl_free (current_acl);
5272 else if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
5273 errno = ENOENT;
5274 else
5275 errno = EACCES;
5277 else
5279 retval = 0;
5280 errno = e;
5283 if (st)
5285 if (st >= 2)
5286 restore_privilege (&old2);
5287 restore_privilege (&old1);
5288 revert_to_self ();
5291 return retval;
5295 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5296 have a fixed max size for file names, so we don't need the kind of
5297 alloc/malloc/realloc dance the gnulib version does. We also don't
5298 support FD-relative symlinks. */
5299 char *
5300 careadlinkat (int fd, char const *filename,
5301 char *buffer, size_t buffer_size,
5302 struct allocator const *alloc,
5303 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
5305 char linkname[MAX_PATH];
5306 ssize_t link_size;
5308 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
5310 if (link_size > 0)
5312 char *retval = buffer;
5314 linkname[link_size++] = '\0';
5315 if (link_size > buffer_size)
5316 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
5317 if (retval)
5318 memcpy (retval, linkname, link_size);
5320 return retval;
5322 return NULL;
5326 /* Support for browsing other processes and their attributes. See
5327 process.c for the Lisp bindings. */
5329 /* Helper wrapper functions. */
5331 static HANDLE WINAPI
5332 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
5334 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
5336 if (g_b_init_create_toolhelp32_snapshot == 0)
5338 g_b_init_create_toolhelp32_snapshot = 1;
5339 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
5340 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5341 "CreateToolhelp32Snapshot");
5343 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
5345 return INVALID_HANDLE_VALUE;
5347 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
5350 static BOOL WINAPI
5351 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
5353 static Process32First_Proc s_pfn_Process32_First = NULL;
5355 if (g_b_init_process32_first == 0)
5357 g_b_init_process32_first = 1;
5358 s_pfn_Process32_First = (Process32First_Proc)
5359 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5360 "Process32First");
5362 if (s_pfn_Process32_First == NULL)
5364 return FALSE;
5366 return (s_pfn_Process32_First (hSnapshot, lppe));
5369 static BOOL WINAPI
5370 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
5372 static Process32Next_Proc s_pfn_Process32_Next = NULL;
5374 if (g_b_init_process32_next == 0)
5376 g_b_init_process32_next = 1;
5377 s_pfn_Process32_Next = (Process32Next_Proc)
5378 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5379 "Process32Next");
5381 if (s_pfn_Process32_Next == NULL)
5383 return FALSE;
5385 return (s_pfn_Process32_Next (hSnapshot, lppe));
5388 static BOOL WINAPI
5389 open_thread_token (HANDLE ThreadHandle,
5390 DWORD DesiredAccess,
5391 BOOL OpenAsSelf,
5392 PHANDLE TokenHandle)
5394 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
5395 HMODULE hm_advapi32 = NULL;
5396 if (is_windows_9x () == TRUE)
5398 SetLastError (ERROR_NOT_SUPPORTED);
5399 return FALSE;
5401 if (g_b_init_open_thread_token == 0)
5403 g_b_init_open_thread_token = 1;
5404 hm_advapi32 = LoadLibrary ("Advapi32.dll");
5405 s_pfn_Open_Thread_Token =
5406 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
5408 if (s_pfn_Open_Thread_Token == NULL)
5410 SetLastError (ERROR_NOT_SUPPORTED);
5411 return FALSE;
5413 return (
5414 s_pfn_Open_Thread_Token (
5415 ThreadHandle,
5416 DesiredAccess,
5417 OpenAsSelf,
5418 TokenHandle)
5422 static BOOL WINAPI
5423 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
5425 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
5426 HMODULE hm_advapi32 = NULL;
5427 if (is_windows_9x () == TRUE)
5429 return FALSE;
5431 if (g_b_init_impersonate_self == 0)
5433 g_b_init_impersonate_self = 1;
5434 hm_advapi32 = LoadLibrary ("Advapi32.dll");
5435 s_pfn_Impersonate_Self =
5436 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
5438 if (s_pfn_Impersonate_Self == NULL)
5440 return FALSE;
5442 return s_pfn_Impersonate_Self (ImpersonationLevel);
5445 static BOOL WINAPI
5446 revert_to_self (void)
5448 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
5449 HMODULE hm_advapi32 = NULL;
5450 if (is_windows_9x () == TRUE)
5452 return FALSE;
5454 if (g_b_init_revert_to_self == 0)
5456 g_b_init_revert_to_self = 1;
5457 hm_advapi32 = LoadLibrary ("Advapi32.dll");
5458 s_pfn_Revert_To_Self =
5459 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
5461 if (s_pfn_Revert_To_Self == NULL)
5463 return FALSE;
5465 return s_pfn_Revert_To_Self ();
5468 static BOOL WINAPI
5469 get_process_memory_info (HANDLE h_proc,
5470 PPROCESS_MEMORY_COUNTERS mem_counters,
5471 DWORD bufsize)
5473 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
5474 HMODULE hm_psapi = NULL;
5475 if (is_windows_9x () == TRUE)
5477 return FALSE;
5479 if (g_b_init_get_process_memory_info == 0)
5481 g_b_init_get_process_memory_info = 1;
5482 hm_psapi = LoadLibrary ("Psapi.dll");
5483 if (hm_psapi)
5484 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
5485 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
5487 if (s_pfn_Get_Process_Memory_Info == NULL)
5489 return FALSE;
5491 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
5494 static BOOL WINAPI
5495 get_process_working_set_size (HANDLE h_proc,
5496 PSIZE_T minrss,
5497 PSIZE_T maxrss)
5499 static GetProcessWorkingSetSize_Proc
5500 s_pfn_Get_Process_Working_Set_Size = NULL;
5502 if (is_windows_9x () == TRUE)
5504 return FALSE;
5506 if (g_b_init_get_process_working_set_size == 0)
5508 g_b_init_get_process_working_set_size = 1;
5509 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
5510 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5511 "GetProcessWorkingSetSize");
5513 if (s_pfn_Get_Process_Working_Set_Size == NULL)
5515 return FALSE;
5517 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
5520 static BOOL WINAPI
5521 global_memory_status (MEMORYSTATUS *buf)
5523 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
5525 if (is_windows_9x () == TRUE)
5527 return FALSE;
5529 if (g_b_init_global_memory_status == 0)
5531 g_b_init_global_memory_status = 1;
5532 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
5533 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5534 "GlobalMemoryStatus");
5536 if (s_pfn_Global_Memory_Status == NULL)
5538 return FALSE;
5540 return s_pfn_Global_Memory_Status (buf);
5543 static BOOL WINAPI
5544 global_memory_status_ex (MEMORY_STATUS_EX *buf)
5546 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
5548 if (is_windows_9x () == TRUE)
5550 return FALSE;
5552 if (g_b_init_global_memory_status_ex == 0)
5554 g_b_init_global_memory_status_ex = 1;
5555 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
5556 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5557 "GlobalMemoryStatusEx");
5559 if (s_pfn_Global_Memory_Status_Ex == NULL)
5561 return FALSE;
5563 return s_pfn_Global_Memory_Status_Ex (buf);
5566 Lisp_Object
5567 list_system_processes (void)
5569 struct gcpro gcpro1;
5570 Lisp_Object proclist = Qnil;
5571 HANDLE h_snapshot;
5573 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
5575 if (h_snapshot != INVALID_HANDLE_VALUE)
5577 PROCESSENTRY32 proc_entry;
5578 DWORD proc_id;
5579 BOOL res;
5581 GCPRO1 (proclist);
5583 proc_entry.dwSize = sizeof (PROCESSENTRY32);
5584 for (res = process32_first (h_snapshot, &proc_entry); res;
5585 res = process32_next (h_snapshot, &proc_entry))
5587 proc_id = proc_entry.th32ProcessID;
5588 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
5591 CloseHandle (h_snapshot);
5592 UNGCPRO;
5593 proclist = Fnreverse (proclist);
5596 return proclist;
5599 static int
5600 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
5602 TOKEN_PRIVILEGES priv;
5603 DWORD priv_size = sizeof (priv);
5604 DWORD opriv_size = sizeof (*old_priv);
5605 HANDLE h_token = NULL;
5606 HANDLE h_thread = GetCurrentThread ();
5607 int ret_val = 0;
5608 BOOL res;
5610 res = open_thread_token (h_thread,
5611 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
5612 FALSE, &h_token);
5613 if (!res && GetLastError () == ERROR_NO_TOKEN)
5615 if (impersonate_self (SecurityImpersonation))
5616 res = open_thread_token (h_thread,
5617 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
5618 FALSE, &h_token);
5620 if (res)
5622 priv.PrivilegeCount = 1;
5623 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
5624 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
5625 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
5626 old_priv, &opriv_size)
5627 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
5628 ret_val = 1;
5630 if (h_token)
5631 CloseHandle (h_token);
5633 return ret_val;
5636 static int
5637 restore_privilege (TOKEN_PRIVILEGES *priv)
5639 DWORD priv_size = sizeof (*priv);
5640 HANDLE h_token = NULL;
5641 int ret_val = 0;
5643 if (open_thread_token (GetCurrentThread (),
5644 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
5645 FALSE, &h_token))
5647 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
5648 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
5649 ret_val = 1;
5651 if (h_token)
5652 CloseHandle (h_token);
5654 return ret_val;
5657 static Lisp_Object
5658 ltime (ULONGLONG time_100ns)
5660 ULONGLONG time_sec = time_100ns / 10000000;
5661 int subsec = time_100ns % 10000000;
5662 return list4i (time_sec >> 16, time_sec & 0xffff,
5663 subsec / 10, subsec % 10 * 100000);
5666 #define U64_TO_LISP_TIME(time) ltime (time)
5668 static int
5669 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
5670 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
5671 double *pcpu)
5673 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
5674 ULONGLONG tem1, tem2, tem3, tem;
5676 if (!h_proc
5677 || !get_process_times_fn
5678 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
5679 &ft_kernel, &ft_user))
5680 return 0;
5682 GetSystemTimeAsFileTime (&ft_current);
5684 FILETIME_TO_U64 (tem1, ft_kernel);
5685 *stime = U64_TO_LISP_TIME (tem1);
5687 FILETIME_TO_U64 (tem2, ft_user);
5688 *utime = U64_TO_LISP_TIME (tem2);
5690 tem3 = tem1 + tem2;
5691 *ttime = U64_TO_LISP_TIME (tem3);
5693 FILETIME_TO_U64 (tem, ft_creation);
5694 /* Process no 4 (System) returns zero creation time. */
5695 if (tem)
5696 tem -= utc_base;
5697 *ctime = U64_TO_LISP_TIME (tem);
5699 if (tem)
5701 FILETIME_TO_U64 (tem3, ft_current);
5702 tem = (tem3 - utc_base) - tem;
5704 *etime = U64_TO_LISP_TIME (tem);
5706 if (tem)
5708 *pcpu = 100.0 * (tem1 + tem2) / tem;
5709 if (*pcpu > 100)
5710 *pcpu = 100.0;
5712 else
5713 *pcpu = 0;
5715 return 1;
5718 Lisp_Object
5719 system_process_attributes (Lisp_Object pid)
5721 struct gcpro gcpro1, gcpro2, gcpro3;
5722 Lisp_Object attrs = Qnil;
5723 Lisp_Object cmd_str, decoded_cmd, tem;
5724 HANDLE h_snapshot, h_proc;
5725 DWORD proc_id;
5726 int found_proc = 0;
5727 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
5728 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
5729 DWORD glength = sizeof (gname);
5730 HANDLE token = NULL;
5731 SID_NAME_USE user_type;
5732 unsigned char *buf = NULL;
5733 DWORD blen = 0;
5734 TOKEN_USER user_token;
5735 TOKEN_PRIMARY_GROUP group_token;
5736 unsigned euid;
5737 unsigned egid;
5738 PROCESS_MEMORY_COUNTERS mem;
5739 PROCESS_MEMORY_COUNTERS_EX mem_ex;
5740 SIZE_T minrss, maxrss;
5741 MEMORYSTATUS memst;
5742 MEMORY_STATUS_EX memstex;
5743 double totphys = 0.0;
5744 Lisp_Object ctime, stime, utime, etime, ttime;
5745 double pcpu;
5746 BOOL result = FALSE;
5748 CHECK_NUMBER_OR_FLOAT (pid);
5749 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
5751 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
5753 GCPRO3 (attrs, decoded_cmd, tem);
5755 if (h_snapshot != INVALID_HANDLE_VALUE)
5757 PROCESSENTRY32 pe;
5758 BOOL res;
5760 pe.dwSize = sizeof (PROCESSENTRY32);
5761 for (res = process32_first (h_snapshot, &pe); res;
5762 res = process32_next (h_snapshot, &pe))
5764 if (proc_id == pe.th32ProcessID)
5766 if (proc_id == 0)
5767 decoded_cmd = build_string ("Idle");
5768 else
5770 /* Decode the command name from locale-specific
5771 encoding. */
5772 cmd_str = build_unibyte_string (pe.szExeFile);
5774 decoded_cmd =
5775 code_convert_string_norecord (cmd_str,
5776 Vlocale_coding_system, 0);
5778 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
5779 attrs = Fcons (Fcons (Qppid,
5780 make_fixnum_or_float (pe.th32ParentProcessID)),
5781 attrs);
5782 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
5783 attrs);
5784 attrs = Fcons (Fcons (Qthcount,
5785 make_fixnum_or_float (pe.cntThreads)),
5786 attrs);
5787 found_proc = 1;
5788 break;
5792 CloseHandle (h_snapshot);
5795 if (!found_proc)
5797 UNGCPRO;
5798 return Qnil;
5801 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
5802 FALSE, proc_id);
5803 /* If we were denied a handle to the process, try again after
5804 enabling the SeDebugPrivilege in our process. */
5805 if (!h_proc)
5807 TOKEN_PRIVILEGES priv_current;
5809 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
5811 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
5812 FALSE, proc_id);
5813 restore_privilege (&priv_current);
5814 revert_to_self ();
5817 if (h_proc)
5819 result = open_process_token (h_proc, TOKEN_QUERY, &token);
5820 if (result)
5822 result = get_token_information (token, TokenUser, NULL, 0, &blen);
5823 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
5825 buf = xmalloc (blen);
5826 result = get_token_information (token, TokenUser,
5827 (LPVOID)buf, blen, &needed);
5828 if (result)
5830 memcpy (&user_token, buf, sizeof (user_token));
5831 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
5833 euid = get_rid (user_token.User.Sid);
5834 result = lookup_account_sid (NULL, user_token.User.Sid,
5835 uname, &ulength,
5836 domain, &dlength,
5837 &user_type);
5838 if (result)
5839 w32_add_to_cache (user_token.User.Sid, euid, uname);
5840 else
5842 strcpy (uname, "unknown");
5843 result = TRUE;
5846 ulength = strlen (uname);
5850 if (result)
5852 /* Determine a reasonable euid and gid values. */
5853 if (xstrcasecmp ("administrator", uname) == 0)
5855 euid = 500; /* well-known Administrator uid */
5856 egid = 513; /* well-known None gid */
5858 else
5860 /* Get group id and name. */
5861 result = get_token_information (token, TokenPrimaryGroup,
5862 (LPVOID)buf, blen, &needed);
5863 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
5865 buf = xrealloc (buf, blen = needed);
5866 result = get_token_information (token, TokenPrimaryGroup,
5867 (LPVOID)buf, blen, &needed);
5869 if (result)
5871 memcpy (&group_token, buf, sizeof (group_token));
5872 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
5874 egid = get_rid (group_token.PrimaryGroup);
5875 dlength = sizeof (domain);
5876 result =
5877 lookup_account_sid (NULL, group_token.PrimaryGroup,
5878 gname, &glength, NULL, &dlength,
5879 &user_type);
5880 if (result)
5881 w32_add_to_cache (group_token.PrimaryGroup,
5882 egid, gname);
5883 else
5885 strcpy (gname, "None");
5886 result = TRUE;
5889 glength = strlen (gname);
5893 xfree (buf);
5895 if (!result)
5897 if (!is_windows_9x ())
5899 /* We couldn't open the process token, presumably because of
5900 insufficient access rights. Assume this process is run
5901 by the system. */
5902 strcpy (uname, "SYSTEM");
5903 strcpy (gname, "None");
5904 euid = 18; /* SYSTEM */
5905 egid = 513; /* None */
5906 glength = strlen (gname);
5907 ulength = strlen (uname);
5909 /* If we are running under Windows 9X, where security calls are
5910 not supported, we assume all processes are run by the current
5911 user. */
5912 else if (GetUserName (uname, &ulength))
5914 if (xstrcasecmp ("administrator", uname) == 0)
5915 euid = 0;
5916 else
5917 euid = 123;
5918 egid = euid;
5919 strcpy (gname, "None");
5920 glength = strlen (gname);
5921 ulength = strlen (uname);
5923 else
5925 euid = 123;
5926 egid = 123;
5927 strcpy (uname, "administrator");
5928 ulength = strlen (uname);
5929 strcpy (gname, "None");
5930 glength = strlen (gname);
5932 if (token)
5933 CloseHandle (token);
5936 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
5937 tem = make_unibyte_string (uname, ulength);
5938 attrs = Fcons (Fcons (Quser,
5939 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
5940 attrs);
5941 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
5942 tem = make_unibyte_string (gname, glength);
5943 attrs = Fcons (Fcons (Qgroup,
5944 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
5945 attrs);
5947 if (global_memory_status_ex (&memstex))
5948 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
5949 totphys = memstex.ullTotalPhys / 1024.0;
5950 #else
5951 /* Visual Studio 6 cannot convert an unsigned __int64 type to
5952 double, so we need to do this for it... */
5954 DWORD tot_hi = memstex.ullTotalPhys >> 32;
5955 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
5956 DWORD tot_lo = memstex.ullTotalPhys % 1024;
5958 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
5960 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5961 else if (global_memory_status (&memst))
5962 totphys = memst.dwTotalPhys / 1024.0;
5964 if (h_proc
5965 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
5966 sizeof (mem_ex)))
5968 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
5970 attrs = Fcons (Fcons (Qmajflt,
5971 make_fixnum_or_float (mem_ex.PageFaultCount)),
5972 attrs);
5973 attrs = Fcons (Fcons (Qvsize,
5974 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
5975 attrs);
5976 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
5977 if (totphys)
5978 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
5980 else if (h_proc
5981 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
5983 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
5985 attrs = Fcons (Fcons (Qmajflt,
5986 make_fixnum_or_float (mem.PageFaultCount)),
5987 attrs);
5988 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
5989 if (totphys)
5990 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
5992 else if (h_proc
5993 && get_process_working_set_size (h_proc, &minrss, &maxrss))
5995 DWORD rss = maxrss / 1024;
5997 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
5998 if (totphys)
5999 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6002 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
6004 attrs = Fcons (Fcons (Qutime, utime), attrs);
6005 attrs = Fcons (Fcons (Qstime, stime), attrs);
6006 attrs = Fcons (Fcons (Qtime, ttime), attrs);
6007 attrs = Fcons (Fcons (Qstart, ctime), attrs);
6008 attrs = Fcons (Fcons (Qetime, etime), attrs);
6009 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
6012 /* FIXME: Retrieve command line by walking the PEB of the process. */
6014 if (h_proc)
6015 CloseHandle (h_proc);
6016 UNGCPRO;
6017 return attrs;
6021 /* Wrappers for winsock functions to map between our file descriptors
6022 and winsock's handles; also set h_errno for convenience.
6024 To allow Emacs to run on systems which don't have winsock support
6025 installed, we dynamically link to winsock on startup if present, and
6026 otherwise provide the minimum necessary functionality
6027 (eg. gethostname). */
6029 /* function pointers for relevant socket functions */
6030 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
6031 void (PASCAL *pfn_WSASetLastError) (int iError);
6032 int (PASCAL *pfn_WSAGetLastError) (void);
6033 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
6034 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
6035 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
6036 int (PASCAL *pfn_socket) (int af, int type, int protocol);
6037 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
6038 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
6039 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
6040 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
6041 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
6042 int (PASCAL *pfn_closesocket) (SOCKET s);
6043 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
6044 int (PASCAL *pfn_WSACleanup) (void);
6046 u_short (PASCAL *pfn_htons) (u_short hostshort);
6047 u_short (PASCAL *pfn_ntohs) (u_short netshort);
6048 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
6049 int (PASCAL *pfn_gethostname) (char * name, int namelen);
6050 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
6051 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
6052 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
6053 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
6054 const char * optval, int optlen);
6055 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
6056 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
6057 int * namelen);
6058 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
6059 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
6060 struct sockaddr * from, int * fromlen);
6061 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
6062 const struct sockaddr * to, int tolen);
6064 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6065 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
6066 #ifndef HANDLE_FLAG_INHERIT
6067 #define HANDLE_FLAG_INHERIT 1
6068 #endif
6070 HANDLE winsock_lib;
6071 static int winsock_inuse;
6073 BOOL
6074 term_winsock (void)
6076 if (winsock_lib != NULL && winsock_inuse == 0)
6078 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6079 after WSAStartup returns successfully, but it seems reasonable
6080 to allow unloading winsock anyway in that case. */
6081 if (pfn_WSACleanup () == 0 ||
6082 pfn_WSAGetLastError () == WSAENETDOWN)
6084 if (FreeLibrary (winsock_lib))
6085 winsock_lib = NULL;
6086 return TRUE;
6089 return FALSE;
6092 BOOL
6093 init_winsock (int load_now)
6095 WSADATA winsockData;
6097 if (winsock_lib != NULL)
6098 return TRUE;
6100 pfn_SetHandleInformation
6101 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6102 "SetHandleInformation");
6104 winsock_lib = LoadLibrary ("Ws2_32.dll");
6106 if (winsock_lib != NULL)
6108 /* dynamically link to socket functions */
6110 #define LOAD_PROC(fn) \
6111 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6112 goto fail;
6114 LOAD_PROC (WSAStartup);
6115 LOAD_PROC (WSASetLastError);
6116 LOAD_PROC (WSAGetLastError);
6117 LOAD_PROC (WSAEventSelect);
6118 LOAD_PROC (WSACreateEvent);
6119 LOAD_PROC (WSACloseEvent);
6120 LOAD_PROC (socket);
6121 LOAD_PROC (bind);
6122 LOAD_PROC (connect);
6123 LOAD_PROC (ioctlsocket);
6124 LOAD_PROC (recv);
6125 LOAD_PROC (send);
6126 LOAD_PROC (closesocket);
6127 LOAD_PROC (shutdown);
6128 LOAD_PROC (htons);
6129 LOAD_PROC (ntohs);
6130 LOAD_PROC (inet_addr);
6131 LOAD_PROC (gethostname);
6132 LOAD_PROC (gethostbyname);
6133 LOAD_PROC (getservbyname);
6134 LOAD_PROC (getpeername);
6135 LOAD_PROC (WSACleanup);
6136 LOAD_PROC (setsockopt);
6137 LOAD_PROC (listen);
6138 LOAD_PROC (getsockname);
6139 LOAD_PROC (accept);
6140 LOAD_PROC (recvfrom);
6141 LOAD_PROC (sendto);
6142 #undef LOAD_PROC
6144 /* specify version 1.1 of winsock */
6145 if (pfn_WSAStartup (0x101, &winsockData) == 0)
6147 if (winsockData.wVersion != 0x101)
6148 goto fail;
6150 if (!load_now)
6152 /* Report that winsock exists and is usable, but leave
6153 socket functions disabled. I am assuming that calling
6154 WSAStartup does not require any network interaction,
6155 and in particular does not cause or require a dial-up
6156 connection to be established. */
6158 pfn_WSACleanup ();
6159 FreeLibrary (winsock_lib);
6160 winsock_lib = NULL;
6162 winsock_inuse = 0;
6163 return TRUE;
6166 fail:
6167 FreeLibrary (winsock_lib);
6168 winsock_lib = NULL;
6171 return FALSE;
6175 int h_errno = 0;
6177 /* Function to map winsock error codes to errno codes for those errno
6178 code defined in errno.h (errno values not defined by errno.h are
6179 already in nt/inc/sys/socket.h). */
6180 static void
6181 set_errno (void)
6183 int wsa_err;
6185 h_errno = 0;
6186 if (winsock_lib == NULL)
6187 wsa_err = EINVAL;
6188 else
6189 wsa_err = pfn_WSAGetLastError ();
6191 switch (wsa_err)
6193 case WSAEACCES: errno = EACCES; break;
6194 case WSAEBADF: errno = EBADF; break;
6195 case WSAEFAULT: errno = EFAULT; break;
6196 case WSAEINTR: errno = EINTR; break;
6197 case WSAEINVAL: errno = EINVAL; break;
6198 case WSAEMFILE: errno = EMFILE; break;
6199 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
6200 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
6201 default: errno = wsa_err; break;
6205 static void
6206 check_errno (void)
6208 h_errno = 0;
6209 if (winsock_lib != NULL)
6210 pfn_WSASetLastError (0);
6213 /* Extend strerror to handle the winsock-specific error codes. */
6214 struct {
6215 int errnum;
6216 char * msg;
6217 } _wsa_errlist[] = {
6218 {WSAEINTR , "Interrupted function call"},
6219 {WSAEBADF , "Bad file descriptor"},
6220 {WSAEACCES , "Permission denied"},
6221 {WSAEFAULT , "Bad address"},
6222 {WSAEINVAL , "Invalid argument"},
6223 {WSAEMFILE , "Too many open files"},
6225 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
6226 {WSAEINPROGRESS , "Operation now in progress"},
6227 {WSAEALREADY , "Operation already in progress"},
6228 {WSAENOTSOCK , "Socket operation on non-socket"},
6229 {WSAEDESTADDRREQ , "Destination address required"},
6230 {WSAEMSGSIZE , "Message too long"},
6231 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
6232 {WSAENOPROTOOPT , "Bad protocol option"},
6233 {WSAEPROTONOSUPPORT , "Protocol not supported"},
6234 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
6235 {WSAEOPNOTSUPP , "Operation not supported"},
6236 {WSAEPFNOSUPPORT , "Protocol family not supported"},
6237 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
6238 {WSAEADDRINUSE , "Address already in use"},
6239 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
6240 {WSAENETDOWN , "Network is down"},
6241 {WSAENETUNREACH , "Network is unreachable"},
6242 {WSAENETRESET , "Network dropped connection on reset"},
6243 {WSAECONNABORTED , "Software caused connection abort"},
6244 {WSAECONNRESET , "Connection reset by peer"},
6245 {WSAENOBUFS , "No buffer space available"},
6246 {WSAEISCONN , "Socket is already connected"},
6247 {WSAENOTCONN , "Socket is not connected"},
6248 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
6249 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
6250 {WSAETIMEDOUT , "Connection timed out"},
6251 {WSAECONNREFUSED , "Connection refused"},
6252 {WSAELOOP , "Network loop"}, /* not sure */
6253 {WSAENAMETOOLONG , "Name is too long"},
6254 {WSAEHOSTDOWN , "Host is down"},
6255 {WSAEHOSTUNREACH , "No route to host"},
6256 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
6257 {WSAEPROCLIM , "Too many processes"},
6258 {WSAEUSERS , "Too many users"}, /* not sure */
6259 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
6260 {WSAESTALE , "Data is stale"}, /* not sure */
6261 {WSAEREMOTE , "Remote error"}, /* not sure */
6263 {WSASYSNOTREADY , "Network subsystem is unavailable"},
6264 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
6265 {WSANOTINITIALISED , "Winsock not initialized successfully"},
6266 {WSAEDISCON , "Graceful shutdown in progress"},
6267 #ifdef WSAENOMORE
6268 {WSAENOMORE , "No more operations allowed"}, /* not sure */
6269 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
6270 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
6271 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
6272 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
6273 {WSASYSCALLFAILURE , "System call failure"},
6274 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
6275 {WSATYPE_NOT_FOUND , "Class type not found"},
6276 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
6277 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
6278 {WSAEREFUSED , "Operation refused"}, /* not sure */
6279 #endif
6281 {WSAHOST_NOT_FOUND , "Host not found"},
6282 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
6283 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
6284 {WSANO_DATA , "Valid name, no data record of requested type"},
6286 {-1, NULL}
6289 char *
6290 sys_strerror (int error_no)
6292 int i;
6293 static char unknown_msg[40];
6295 if (error_no >= 0 && error_no < sys_nerr)
6296 return sys_errlist[error_no];
6298 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
6299 if (_wsa_errlist[i].errnum == error_no)
6300 return _wsa_errlist[i].msg;
6302 sprintf (unknown_msg, "Unidentified error: %d", error_no);
6303 return unknown_msg;
6306 /* [andrewi 3-May-96] I've had conflicting results using both methods,
6307 but I believe the method of keeping the socket handle separate (and
6308 insuring it is not inheritable) is the correct one. */
6310 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
6312 static int socket_to_fd (SOCKET s);
6315 sys_socket (int af, int type, int protocol)
6317 SOCKET s;
6319 if (winsock_lib == NULL)
6321 errno = ENETDOWN;
6322 return INVALID_SOCKET;
6325 check_errno ();
6327 /* call the real socket function */
6328 s = pfn_socket (af, type, protocol);
6330 if (s != INVALID_SOCKET)
6331 return socket_to_fd (s);
6333 set_errno ();
6334 return -1;
6337 /* Convert a SOCKET to a file descriptor. */
6338 static int
6339 socket_to_fd (SOCKET s)
6341 int fd;
6342 child_process * cp;
6344 /* Although under NT 3.5 _open_osfhandle will accept a socket
6345 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
6346 that does not work under NT 3.1. However, we can get the same
6347 effect by using a backdoor function to replace an existing
6348 descriptor handle with the one we want. */
6350 /* allocate a file descriptor (with appropriate flags) */
6351 fd = _open ("NUL:", _O_RDWR);
6352 if (fd >= 0)
6354 /* Make a non-inheritable copy of the socket handle. Note
6355 that it is possible that sockets aren't actually kernel
6356 handles, which appears to be the case on Windows 9x when
6357 the MS Proxy winsock client is installed. */
6359 /* Apparently there is a bug in NT 3.51 with some service
6360 packs, which prevents using DuplicateHandle to make a
6361 socket handle non-inheritable (causes WSACleanup to
6362 hang). The work-around is to use SetHandleInformation
6363 instead if it is available and implemented. */
6364 if (pfn_SetHandleInformation)
6366 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
6368 else
6370 HANDLE parent = GetCurrentProcess ();
6371 HANDLE new_s = INVALID_HANDLE_VALUE;
6373 if (DuplicateHandle (parent,
6374 (HANDLE) s,
6375 parent,
6376 &new_s,
6378 FALSE,
6379 DUPLICATE_SAME_ACCESS))
6381 /* It is possible that DuplicateHandle succeeds even
6382 though the socket wasn't really a kernel handle,
6383 because a real handle has the same value. So
6384 test whether the new handle really is a socket. */
6385 long nonblocking = 0;
6386 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
6388 pfn_closesocket (s);
6389 s = (SOCKET) new_s;
6391 else
6393 CloseHandle (new_s);
6398 eassert (fd < MAXDESC);
6399 fd_info[fd].hnd = (HANDLE) s;
6401 /* set our own internal flags */
6402 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
6404 cp = new_child ();
6405 if (cp)
6407 cp->fd = fd;
6408 cp->status = STATUS_READ_ACKNOWLEDGED;
6410 /* attach child_process to fd_info */
6411 if (fd_info[ fd ].cp != NULL)
6413 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
6414 emacs_abort ();
6417 fd_info[ fd ].cp = cp;
6419 /* success! */
6420 winsock_inuse++; /* count open sockets */
6421 return fd;
6424 /* clean up */
6425 _close (fd);
6427 else
6428 pfn_closesocket (s);
6429 errno = EMFILE;
6430 return -1;
6434 sys_bind (int s, const struct sockaddr * addr, int namelen)
6436 if (winsock_lib == NULL)
6438 errno = ENOTSOCK;
6439 return SOCKET_ERROR;
6442 check_errno ();
6443 if (fd_info[s].flags & FILE_SOCKET)
6445 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
6446 if (rc == SOCKET_ERROR)
6447 set_errno ();
6448 return rc;
6450 errno = ENOTSOCK;
6451 return SOCKET_ERROR;
6455 sys_connect (int s, const struct sockaddr * name, int namelen)
6457 if (winsock_lib == NULL)
6459 errno = ENOTSOCK;
6460 return SOCKET_ERROR;
6463 check_errno ();
6464 if (fd_info[s].flags & FILE_SOCKET)
6466 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
6467 if (rc == SOCKET_ERROR)
6468 set_errno ();
6469 return rc;
6471 errno = ENOTSOCK;
6472 return SOCKET_ERROR;
6475 u_short
6476 sys_htons (u_short hostshort)
6478 return (winsock_lib != NULL) ?
6479 pfn_htons (hostshort) : hostshort;
6482 u_short
6483 sys_ntohs (u_short netshort)
6485 return (winsock_lib != NULL) ?
6486 pfn_ntohs (netshort) : netshort;
6489 unsigned long
6490 sys_inet_addr (const char * cp)
6492 return (winsock_lib != NULL) ?
6493 pfn_inet_addr (cp) : INADDR_NONE;
6497 sys_gethostname (char * name, int namelen)
6499 if (winsock_lib != NULL)
6501 int retval;
6503 check_errno ();
6504 retval = pfn_gethostname (name, namelen);
6505 if (retval == SOCKET_ERROR)
6506 set_errno ();
6507 return retval;
6510 if (namelen > MAX_COMPUTERNAME_LENGTH)
6511 return !GetComputerName (name, (DWORD *)&namelen);
6513 errno = EFAULT;
6514 return SOCKET_ERROR;
6517 struct hostent *
6518 sys_gethostbyname (const char * name)
6520 struct hostent * host;
6521 int h_err = h_errno;
6523 if (winsock_lib == NULL)
6525 h_errno = NO_RECOVERY;
6526 errno = ENETDOWN;
6527 return NULL;
6530 check_errno ();
6531 host = pfn_gethostbyname (name);
6532 if (!host)
6534 set_errno ();
6535 h_errno = errno;
6537 else
6538 h_errno = h_err;
6539 return host;
6542 struct servent *
6543 sys_getservbyname (const char * name, const char * proto)
6545 struct servent * serv;
6547 if (winsock_lib == NULL)
6549 errno = ENETDOWN;
6550 return NULL;
6553 check_errno ();
6554 serv = pfn_getservbyname (name, proto);
6555 if (!serv)
6556 set_errno ();
6557 return serv;
6561 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
6563 if (winsock_lib == NULL)
6565 errno = ENETDOWN;
6566 return SOCKET_ERROR;
6569 check_errno ();
6570 if (fd_info[s].flags & FILE_SOCKET)
6572 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
6573 if (rc == SOCKET_ERROR)
6574 set_errno ();
6575 return rc;
6577 errno = ENOTSOCK;
6578 return SOCKET_ERROR;
6582 sys_shutdown (int s, int how)
6584 if (winsock_lib == NULL)
6586 errno = ENETDOWN;
6587 return SOCKET_ERROR;
6590 check_errno ();
6591 if (fd_info[s].flags & FILE_SOCKET)
6593 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
6594 if (rc == SOCKET_ERROR)
6595 set_errno ();
6596 return rc;
6598 errno = ENOTSOCK;
6599 return SOCKET_ERROR;
6603 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
6605 if (winsock_lib == NULL)
6607 errno = ENETDOWN;
6608 return SOCKET_ERROR;
6611 check_errno ();
6612 if (fd_info[s].flags & FILE_SOCKET)
6614 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
6615 (const char *)optval, optlen);
6616 if (rc == SOCKET_ERROR)
6617 set_errno ();
6618 return rc;
6620 errno = ENOTSOCK;
6621 return SOCKET_ERROR;
6625 sys_listen (int s, int backlog)
6627 if (winsock_lib == NULL)
6629 errno = ENETDOWN;
6630 return SOCKET_ERROR;
6633 check_errno ();
6634 if (fd_info[s].flags & FILE_SOCKET)
6636 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
6637 if (rc == SOCKET_ERROR)
6638 set_errno ();
6639 else
6640 fd_info[s].flags |= FILE_LISTEN;
6641 return rc;
6643 errno = ENOTSOCK;
6644 return SOCKET_ERROR;
6648 sys_getsockname (int s, struct sockaddr * name, int * namelen)
6650 if (winsock_lib == NULL)
6652 errno = ENETDOWN;
6653 return SOCKET_ERROR;
6656 check_errno ();
6657 if (fd_info[s].flags & FILE_SOCKET)
6659 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
6660 if (rc == SOCKET_ERROR)
6661 set_errno ();
6662 return rc;
6664 errno = ENOTSOCK;
6665 return SOCKET_ERROR;
6669 sys_accept (int s, struct sockaddr * addr, int * addrlen)
6671 if (winsock_lib == NULL)
6673 errno = ENETDOWN;
6674 return -1;
6677 check_errno ();
6678 if (fd_info[s].flags & FILE_LISTEN)
6680 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
6681 int fd = -1;
6682 if (t == INVALID_SOCKET)
6683 set_errno ();
6684 else
6685 fd = socket_to_fd (t);
6687 if (fd >= 0)
6689 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
6690 ResetEvent (fd_info[s].cp->char_avail);
6692 return fd;
6694 errno = ENOTSOCK;
6695 return -1;
6699 sys_recvfrom (int s, char * buf, int len, int flags,
6700 struct sockaddr * from, int * fromlen)
6702 if (winsock_lib == NULL)
6704 errno = ENETDOWN;
6705 return SOCKET_ERROR;
6708 check_errno ();
6709 if (fd_info[s].flags & FILE_SOCKET)
6711 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
6712 if (rc == SOCKET_ERROR)
6713 set_errno ();
6714 return rc;
6716 errno = ENOTSOCK;
6717 return SOCKET_ERROR;
6721 sys_sendto (int s, const char * buf, int len, int flags,
6722 const struct sockaddr * to, int tolen)
6724 if (winsock_lib == NULL)
6726 errno = ENETDOWN;
6727 return SOCKET_ERROR;
6730 check_errno ();
6731 if (fd_info[s].flags & FILE_SOCKET)
6733 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
6734 if (rc == SOCKET_ERROR)
6735 set_errno ();
6736 return rc;
6738 errno = ENOTSOCK;
6739 return SOCKET_ERROR;
6742 /* Windows does not have an fcntl function. Provide an implementation
6743 good enough for Emacs. */
6745 fcntl (int s, int cmd, int options)
6747 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
6748 invoked in a context where fd1 is closed and all descriptors less
6749 than fd1 are open, so sys_dup is an adequate implementation. */
6750 if (cmd == F_DUPFD_CLOEXEC)
6751 return sys_dup (s);
6753 if (winsock_lib == NULL)
6755 errno = ENETDOWN;
6756 return -1;
6759 check_errno ();
6760 if (fd_info[s].flags & FILE_SOCKET)
6762 if (cmd == F_SETFL && options == O_NONBLOCK)
6764 unsigned long nblock = 1;
6765 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
6766 if (rc == SOCKET_ERROR)
6767 set_errno ();
6768 /* Keep track of the fact that we set this to non-blocking. */
6769 fd_info[s].flags |= FILE_NDELAY;
6770 return rc;
6772 else
6774 errno = EINVAL;
6775 return SOCKET_ERROR;
6778 errno = ENOTSOCK;
6779 return SOCKET_ERROR;
6783 /* Shadow main io functions: we need to handle pipes and sockets more
6784 intelligently, and implement non-blocking mode as well. */
6787 sys_close (int fd)
6789 int rc;
6791 if (fd < 0)
6793 errno = EBADF;
6794 return -1;
6797 if (fd < MAXDESC && fd_info[fd].cp)
6799 child_process * cp = fd_info[fd].cp;
6801 fd_info[fd].cp = NULL;
6803 if (CHILD_ACTIVE (cp))
6805 /* if last descriptor to active child_process then cleanup */
6806 int i;
6807 for (i = 0; i < MAXDESC; i++)
6809 if (i == fd)
6810 continue;
6811 if (fd_info[i].cp == cp)
6812 break;
6814 if (i == MAXDESC)
6816 if (fd_info[fd].flags & FILE_SOCKET)
6818 if (winsock_lib == NULL) emacs_abort ();
6820 pfn_shutdown (SOCK_HANDLE (fd), 2);
6821 rc = pfn_closesocket (SOCK_HANDLE (fd));
6823 winsock_inuse--; /* count open sockets */
6825 /* If the process handle is NULL, it's either a socket
6826 or serial connection, or a subprocess that was
6827 already reaped by reap_subprocess, but whose
6828 resources were not yet freed, because its output was
6829 not fully read yet by the time it was reaped. (This
6830 usually happens with async subprocesses whose output
6831 is being read by Emacs.) Otherwise, this process was
6832 not reaped yet, so we set its FD to a negative value
6833 to make sure sys_select will eventually get to
6834 calling the SIGCHLD handler for it, which will then
6835 invoke waitpid and reap_subprocess. */
6836 if (cp->procinfo.hProcess == NULL)
6837 delete_child (cp);
6838 else
6839 cp->fd = -1;
6844 if (fd >= 0 && fd < MAXDESC)
6845 fd_info[fd].flags = 0;
6847 /* Note that sockets do not need special treatment here (at least on
6848 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
6849 closesocket is equivalent to CloseHandle, which is to be expected
6850 because socket handles are fully fledged kernel handles. */
6851 rc = _close (fd);
6853 return rc;
6857 sys_dup (int fd)
6859 int new_fd;
6861 new_fd = _dup (fd);
6862 if (new_fd >= 0 && new_fd < MAXDESC)
6864 /* duplicate our internal info as well */
6865 fd_info[new_fd] = fd_info[fd];
6867 return new_fd;
6871 sys_dup2 (int src, int dst)
6873 int rc;
6875 if (dst < 0 || dst >= MAXDESC)
6877 errno = EBADF;
6878 return -1;
6881 /* make sure we close the destination first if it's a pipe or socket */
6882 if (src != dst && fd_info[dst].flags != 0)
6883 sys_close (dst);
6885 rc = _dup2 (src, dst);
6886 if (rc == 0)
6888 /* duplicate our internal info as well */
6889 fd_info[dst] = fd_info[src];
6891 return rc;
6895 pipe2 (int * phandles, int pipe2_flags)
6897 int rc;
6898 unsigned flags;
6900 eassert (pipe2_flags == O_CLOEXEC);
6902 /* make pipe handles non-inheritable; when we spawn a child, we
6903 replace the relevant handle with an inheritable one. Also put
6904 pipes into binary mode; we will do text mode translation ourselves
6905 if required. */
6906 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
6908 if (rc == 0)
6910 /* Protect against overflow, since Windows can open more handles than
6911 our fd_info array has room for. */
6912 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
6914 _close (phandles[0]);
6915 _close (phandles[1]);
6916 errno = EMFILE;
6917 rc = -1;
6919 else
6921 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
6922 fd_info[phandles[0]].flags = flags;
6924 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
6925 fd_info[phandles[1]].flags = flags;
6929 return rc;
6932 /* Function to do blocking read of one byte, needed to implement
6933 select. It is only allowed on communication ports, sockets, or
6934 pipes. */
6936 _sys_read_ahead (int fd)
6938 child_process * cp;
6939 int rc;
6941 if (fd < 0 || fd >= MAXDESC)
6942 return STATUS_READ_ERROR;
6944 cp = fd_info[fd].cp;
6946 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
6947 return STATUS_READ_ERROR;
6949 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
6950 || (fd_info[fd].flags & FILE_READ) == 0)
6952 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
6953 emacs_abort ();
6956 cp->status = STATUS_READ_IN_PROGRESS;
6958 if (fd_info[fd].flags & FILE_PIPE)
6960 rc = _read (fd, &cp->chr, sizeof (char));
6962 /* Give subprocess time to buffer some more output for us before
6963 reporting that input is available; we need this because Windows 95
6964 connects DOS programs to pipes by making the pipe appear to be
6965 the normal console stdout - as a result most DOS programs will
6966 write to stdout without buffering, ie. one character at a
6967 time. Even some W32 programs do this - "dir" in a command
6968 shell on NT is very slow if we don't do this. */
6969 if (rc > 0)
6971 int wait = w32_pipe_read_delay;
6973 if (wait > 0)
6974 Sleep (wait);
6975 else if (wait < 0)
6976 while (++wait <= 0)
6977 /* Yield remainder of our time slice, effectively giving a
6978 temporary priority boost to the child process. */
6979 Sleep (0);
6982 else if (fd_info[fd].flags & FILE_SERIAL)
6984 HANDLE hnd = fd_info[fd].hnd;
6985 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
6986 COMMTIMEOUTS ct;
6988 /* Configure timeouts for blocking read. */
6989 if (!GetCommTimeouts (hnd, &ct))
6991 cp->status = STATUS_READ_ERROR;
6992 return STATUS_READ_ERROR;
6994 ct.ReadIntervalTimeout = 0;
6995 ct.ReadTotalTimeoutMultiplier = 0;
6996 ct.ReadTotalTimeoutConstant = 0;
6997 if (!SetCommTimeouts (hnd, &ct))
6999 cp->status = STATUS_READ_ERROR;
7000 return STATUS_READ_ERROR;
7003 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
7005 if (GetLastError () != ERROR_IO_PENDING)
7007 cp->status = STATUS_READ_ERROR;
7008 return STATUS_READ_ERROR;
7010 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
7012 cp->status = STATUS_READ_ERROR;
7013 return STATUS_READ_ERROR;
7017 else if (fd_info[fd].flags & FILE_SOCKET)
7019 unsigned long nblock = 0;
7020 /* We always want this to block, so temporarily disable NDELAY. */
7021 if (fd_info[fd].flags & FILE_NDELAY)
7022 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7024 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
7026 if (fd_info[fd].flags & FILE_NDELAY)
7028 nblock = 1;
7029 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7033 if (rc == sizeof (char))
7034 cp->status = STATUS_READ_SUCCEEDED;
7035 else
7036 cp->status = STATUS_READ_FAILED;
7038 return cp->status;
7042 _sys_wait_accept (int fd)
7044 HANDLE hEv;
7045 child_process * cp;
7046 int rc;
7048 if (fd < 0 || fd >= MAXDESC)
7049 return STATUS_READ_ERROR;
7051 cp = fd_info[fd].cp;
7053 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7054 return STATUS_READ_ERROR;
7056 cp->status = STATUS_READ_FAILED;
7058 hEv = pfn_WSACreateEvent ();
7059 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
7060 if (rc != SOCKET_ERROR)
7062 rc = WaitForSingleObject (hEv, INFINITE);
7063 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
7064 if (rc == WAIT_OBJECT_0)
7065 cp->status = STATUS_READ_SUCCEEDED;
7067 pfn_WSACloseEvent (hEv);
7069 return cp->status;
7073 sys_read (int fd, char * buffer, unsigned int count)
7075 int nchars;
7076 int to_read;
7077 DWORD waiting;
7078 char * orig_buffer = buffer;
7080 if (fd < 0)
7082 errno = EBADF;
7083 return -1;
7086 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
7088 child_process *cp = fd_info[fd].cp;
7090 if ((fd_info[fd].flags & FILE_READ) == 0)
7092 errno = EBADF;
7093 return -1;
7096 nchars = 0;
7098 /* re-read CR carried over from last read */
7099 if (fd_info[fd].flags & FILE_LAST_CR)
7101 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
7102 *buffer++ = 0x0d;
7103 count--;
7104 nchars++;
7105 fd_info[fd].flags &= ~FILE_LAST_CR;
7108 /* presence of a child_process structure means we are operating in
7109 non-blocking mode - otherwise we just call _read directly.
7110 Note that the child_process structure might be missing because
7111 reap_subprocess has been called; in this case the pipe is
7112 already broken, so calling _read on it is okay. */
7113 if (cp)
7115 int current_status = cp->status;
7117 switch (current_status)
7119 case STATUS_READ_FAILED:
7120 case STATUS_READ_ERROR:
7121 /* report normal EOF if nothing in buffer */
7122 if (nchars <= 0)
7123 fd_info[fd].flags |= FILE_AT_EOF;
7124 return nchars;
7126 case STATUS_READ_READY:
7127 case STATUS_READ_IN_PROGRESS:
7128 DebPrint (("sys_read called when read is in progress\n"));
7129 errno = EWOULDBLOCK;
7130 return -1;
7132 case STATUS_READ_SUCCEEDED:
7133 /* consume read-ahead char */
7134 *buffer++ = cp->chr;
7135 count--;
7136 nchars++;
7137 cp->status = STATUS_READ_ACKNOWLEDGED;
7138 ResetEvent (cp->char_avail);
7140 case STATUS_READ_ACKNOWLEDGED:
7141 break;
7143 default:
7144 DebPrint (("sys_read: bad status %d\n", current_status));
7145 errno = EBADF;
7146 return -1;
7149 if (fd_info[fd].flags & FILE_PIPE)
7151 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
7152 to_read = min (waiting, (DWORD) count);
7154 if (to_read > 0)
7155 nchars += _read (fd, buffer, to_read);
7157 else if (fd_info[fd].flags & FILE_SERIAL)
7159 HANDLE hnd = fd_info[fd].hnd;
7160 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7161 int rc = 0;
7162 COMMTIMEOUTS ct;
7164 if (count > 0)
7166 /* Configure timeouts for non-blocking read. */
7167 if (!GetCommTimeouts (hnd, &ct))
7169 errno = EIO;
7170 return -1;
7172 ct.ReadIntervalTimeout = MAXDWORD;
7173 ct.ReadTotalTimeoutMultiplier = 0;
7174 ct.ReadTotalTimeoutConstant = 0;
7175 if (!SetCommTimeouts (hnd, &ct))
7177 errno = EIO;
7178 return -1;
7181 if (!ResetEvent (ovl->hEvent))
7183 errno = EIO;
7184 return -1;
7186 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
7188 if (GetLastError () != ERROR_IO_PENDING)
7190 errno = EIO;
7191 return -1;
7193 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
7195 errno = EIO;
7196 return -1;
7199 nchars += rc;
7202 else /* FILE_SOCKET */
7204 if (winsock_lib == NULL) emacs_abort ();
7206 /* do the equivalent of a non-blocking read */
7207 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
7208 if (waiting == 0 && nchars == 0)
7210 errno = EWOULDBLOCK;
7211 return -1;
7214 if (waiting)
7216 /* always use binary mode for sockets */
7217 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
7218 if (res == SOCKET_ERROR)
7220 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
7221 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
7222 set_errno ();
7223 return -1;
7225 nchars += res;
7229 else
7231 int nread = _read (fd, buffer, count);
7232 if (nread >= 0)
7233 nchars += nread;
7234 else if (nchars == 0)
7235 nchars = nread;
7238 if (nchars <= 0)
7239 fd_info[fd].flags |= FILE_AT_EOF;
7240 /* Perform text mode translation if required. */
7241 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
7243 nchars = crlf_to_lf (nchars, orig_buffer);
7244 /* If buffer contains only CR, return that. To be absolutely
7245 sure we should attempt to read the next char, but in
7246 practice a CR to be followed by LF would not appear by
7247 itself in the buffer. */
7248 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
7250 fd_info[fd].flags |= FILE_LAST_CR;
7251 nchars--;
7255 else
7256 nchars = _read (fd, buffer, count);
7258 return nchars;
7261 /* From w32xfns.c */
7262 extern HANDLE interrupt_handle;
7264 /* For now, don't bother with a non-blocking mode */
7266 sys_write (int fd, const void * buffer, unsigned int count)
7268 int nchars;
7270 if (fd < 0)
7272 errno = EBADF;
7273 return -1;
7276 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
7278 if ((fd_info[fd].flags & FILE_WRITE) == 0)
7280 errno = EBADF;
7281 return -1;
7284 /* Perform text mode translation if required. */
7285 if ((fd_info[fd].flags & FILE_BINARY) == 0)
7287 char * tmpbuf = alloca (count * 2);
7288 unsigned char * src = (void *)buffer;
7289 unsigned char * dst = tmpbuf;
7290 int nbytes = count;
7292 while (1)
7294 unsigned char *next;
7295 /* copy next line or remaining bytes */
7296 next = _memccpy (dst, src, '\n', nbytes);
7297 if (next)
7299 /* copied one line ending with '\n' */
7300 int copied = next - dst;
7301 nbytes -= copied;
7302 src += copied;
7303 /* insert '\r' before '\n' */
7304 next[-1] = '\r';
7305 next[0] = '\n';
7306 dst = next + 1;
7307 count++;
7309 else
7310 /* copied remaining partial line -> now finished */
7311 break;
7313 buffer = tmpbuf;
7317 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
7319 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
7320 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
7321 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
7322 DWORD active = 0;
7324 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
7326 if (GetLastError () != ERROR_IO_PENDING)
7328 errno = EIO;
7329 return -1;
7331 if (detect_input_pending ())
7332 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
7333 QS_ALLINPUT);
7334 else
7335 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
7336 if (active == WAIT_OBJECT_0)
7337 { /* User pressed C-g, cancel write, then leave. Don't bother
7338 cleaning up as we may only get stuck in buggy drivers. */
7339 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
7340 CancelIo (hnd);
7341 errno = EIO;
7342 return -1;
7344 if (active == WAIT_OBJECT_0 + 1
7345 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
7347 errno = EIO;
7348 return -1;
7352 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
7354 unsigned long nblock = 0;
7355 if (winsock_lib == NULL) emacs_abort ();
7357 /* TODO: implement select() properly so non-blocking I/O works. */
7358 /* For now, make sure the write blocks. */
7359 if (fd_info[fd].flags & FILE_NDELAY)
7360 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7362 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
7364 /* Set the socket back to non-blocking if it was before,
7365 for other operations that support it. */
7366 if (fd_info[fd].flags & FILE_NDELAY)
7368 nblock = 1;
7369 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7372 if (nchars == SOCKET_ERROR)
7374 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
7375 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
7376 set_errno ();
7379 else
7381 /* Some networked filesystems don't like too large writes, so
7382 break them into smaller chunks. See the Comments section of
7383 the MSDN documentation of WriteFile for details behind the
7384 choice of the value of CHUNK below. See also the thread
7385 http://thread.gmane.org/gmane.comp.version-control.git/145294
7386 in the git mailing list. */
7387 const unsigned char *p = buffer;
7388 const unsigned chunk = 30 * 1024 * 1024;
7390 nchars = 0;
7391 while (count > 0)
7393 unsigned this_chunk = count < chunk ? count : chunk;
7394 int n = _write (fd, p, this_chunk);
7396 nchars += n;
7397 if (n < 0)
7399 nchars = n;
7400 break;
7402 else if (n < this_chunk)
7403 break;
7404 count -= n;
7405 p += n;
7409 return nchars;
7412 /* The Windows CRT functions are "optimized for speed", so they don't
7413 check for timezone and DST changes if they were last called less
7414 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
7415 all Emacs features that repeatedly call time functions (e.g.,
7416 display-time) are in real danger of missing timezone and DST
7417 changes. Calling tzset before each localtime call fixes that. */
7418 struct tm *
7419 sys_localtime (const time_t *t)
7421 tzset ();
7422 return localtime (t);
7427 /* Try loading LIBRARY_ID from the file(s) specified in
7428 Vdynamic_library_alist. If the library is loaded successfully,
7429 return the handle of the DLL, and record the filename in the
7430 property :loaded-from of LIBRARY_ID. If the library could not be
7431 found, or when it was already loaded (because the handle is not
7432 recorded anywhere, and so is lost after use), return NULL.
7434 We could also save the handle in :loaded-from, but currently
7435 there's no use case for it. */
7436 HMODULE
7437 w32_delayed_load (Lisp_Object library_id)
7439 HMODULE library_dll = NULL;
7441 CHECK_SYMBOL (library_id);
7443 if (CONSP (Vdynamic_library_alist)
7444 && NILP (Fassq (library_id, Vlibrary_cache)))
7446 Lisp_Object found = Qnil;
7447 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
7449 if (CONSP (dlls))
7450 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
7452 CHECK_STRING_CAR (dlls);
7453 if ((library_dll = LoadLibrary (SDATA (XCAR (dlls)))))
7455 char name[MAX_PATH];
7456 DWORD len;
7458 len = GetModuleFileNameA (library_dll, name, sizeof (name));
7459 found = Fcons (XCAR (dlls),
7460 (len > 0)
7461 /* Possibly truncated */
7462 ? make_specified_string (name, -1, len, 1)
7463 : Qnil);
7464 break;
7468 Fput (library_id, QCloaded_from, found);
7471 return library_dll;
7475 void
7476 check_windows_init_file (void)
7478 /* A common indication that Emacs is not installed properly is when
7479 it cannot find the Windows installation file. If this file does
7480 not exist in the expected place, tell the user. */
7482 if (!noninteractive && !inhibit_window_system
7483 /* Vload_path is not yet initialized when we are loading
7484 loadup.el. */
7485 && NILP (Vpurify_flag))
7487 Lisp_Object init_file;
7488 int fd;
7490 init_file = build_string ("term/w32-win");
7491 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
7492 if (fd < 0)
7494 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
7495 char *init_file_name = SDATA (init_file);
7496 char *load_path = SDATA (load_path_print);
7497 char *buffer = alloca (1024
7498 + strlen (init_file_name)
7499 + strlen (load_path));
7501 sprintf (buffer,
7502 "The Emacs Windows initialization file \"%s.el\" "
7503 "could not be found in your Emacs installation. "
7504 "Emacs checked the following directories for this file:\n"
7505 "\n%s\n\n"
7506 "When Emacs cannot find this file, it usually means that it "
7507 "was not installed properly, or its distribution file was "
7508 "not unpacked properly.\nSee the README.W32 file in the "
7509 "top-level Emacs directory for more information.",
7510 init_file_name, load_path);
7511 MessageBox (NULL,
7512 buffer,
7513 "Emacs Abort Dialog",
7514 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
7515 /* Use the low-level system abort. */
7516 abort ();
7518 else
7520 _close (fd);
7525 void
7526 term_ntproc (int ignored)
7528 (void)ignored;
7530 term_timers ();
7532 /* shutdown the socket interface if necessary */
7533 term_winsock ();
7535 term_w32select ();
7538 void
7539 init_ntproc (int dumping)
7541 sigset_t initial_mask = 0;
7543 /* Initialize the socket interface now if available and requested by
7544 the user by defining PRELOAD_WINSOCK; otherwise loading will be
7545 delayed until open-network-stream is called (w32-has-winsock can
7546 also be used to dynamically load or reload winsock).
7548 Conveniently, init_environment is called before us, so
7549 PRELOAD_WINSOCK can be set in the registry. */
7551 /* Always initialize this correctly. */
7552 winsock_lib = NULL;
7554 if (getenv ("PRELOAD_WINSOCK") != NULL)
7555 init_winsock (TRUE);
7557 /* Initial preparation for subprocess support: replace our standard
7558 handles with non-inheritable versions. */
7560 HANDLE parent;
7561 HANDLE stdin_save = INVALID_HANDLE_VALUE;
7562 HANDLE stdout_save = INVALID_HANDLE_VALUE;
7563 HANDLE stderr_save = INVALID_HANDLE_VALUE;
7565 parent = GetCurrentProcess ();
7567 /* ignore errors when duplicating and closing; typically the
7568 handles will be invalid when running as a gui program. */
7569 DuplicateHandle (parent,
7570 GetStdHandle (STD_INPUT_HANDLE),
7571 parent,
7572 &stdin_save,
7574 FALSE,
7575 DUPLICATE_SAME_ACCESS);
7577 DuplicateHandle (parent,
7578 GetStdHandle (STD_OUTPUT_HANDLE),
7579 parent,
7580 &stdout_save,
7582 FALSE,
7583 DUPLICATE_SAME_ACCESS);
7585 DuplicateHandle (parent,
7586 GetStdHandle (STD_ERROR_HANDLE),
7587 parent,
7588 &stderr_save,
7590 FALSE,
7591 DUPLICATE_SAME_ACCESS);
7593 fclose (stdin);
7594 fclose (stdout);
7595 fclose (stderr);
7597 if (stdin_save != INVALID_HANDLE_VALUE)
7598 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
7599 else
7600 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
7601 _fdopen (0, "r");
7603 if (stdout_save != INVALID_HANDLE_VALUE)
7604 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
7605 else
7606 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
7607 _fdopen (1, "w");
7609 if (stderr_save != INVALID_HANDLE_VALUE)
7610 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
7611 else
7612 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
7613 _fdopen (2, "w");
7616 /* unfortunately, atexit depends on implementation of malloc */
7617 /* atexit (term_ntproc); */
7618 if (!dumping)
7620 /* Make sure we start with all signals unblocked. */
7621 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
7622 signal (SIGABRT, term_ntproc);
7624 init_timers ();
7626 /* determine which drives are fixed, for GetCachedVolumeInformation */
7628 /* GetDriveType must have trailing backslash. */
7629 char drive[] = "A:\\";
7631 /* Loop over all possible drive letters */
7632 while (*drive <= 'Z')
7634 /* Record if this drive letter refers to a fixed drive. */
7635 fixed_drives[DRIVE_INDEX (*drive)] =
7636 (GetDriveType (drive) == DRIVE_FIXED);
7638 (*drive)++;
7641 /* Reset the volume info cache. */
7642 volume_cache = NULL;
7647 shutdown_handler ensures that buffers' autosave files are
7648 up to date when the user logs off, or the system shuts down.
7650 static BOOL WINAPI
7651 shutdown_handler (DWORD type)
7653 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
7654 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
7655 || type == CTRL_LOGOFF_EVENT /* User logs off. */
7656 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
7658 /* Shut down cleanly, making sure autosave files are up to date. */
7659 shut_down_emacs (0, Qnil);
7662 /* Allow other handlers to handle this signal. */
7663 return FALSE;
7667 globals_of_w32 is used to initialize those global variables that
7668 must always be initialized on startup even when the global variable
7669 initialized is non zero (see the function main in emacs.c).
7671 void
7672 globals_of_w32 (void)
7674 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
7676 get_process_times_fn = (GetProcessTimes_Proc)
7677 GetProcAddress (kernel32, "GetProcessTimes");
7679 DEFSYM (QCloaded_from, ":loaded-from");
7681 g_b_init_is_windows_9x = 0;
7682 g_b_init_open_process_token = 0;
7683 g_b_init_get_token_information = 0;
7684 g_b_init_lookup_account_sid = 0;
7685 g_b_init_get_sid_sub_authority = 0;
7686 g_b_init_get_sid_sub_authority_count = 0;
7687 g_b_init_get_security_info = 0;
7688 g_b_init_get_file_security = 0;
7689 g_b_init_get_security_descriptor_owner = 0;
7690 g_b_init_get_security_descriptor_group = 0;
7691 g_b_init_is_valid_sid = 0;
7692 g_b_init_create_toolhelp32_snapshot = 0;
7693 g_b_init_process32_first = 0;
7694 g_b_init_process32_next = 0;
7695 g_b_init_open_thread_token = 0;
7696 g_b_init_impersonate_self = 0;
7697 g_b_init_revert_to_self = 0;
7698 g_b_init_get_process_memory_info = 0;
7699 g_b_init_get_process_working_set_size = 0;
7700 g_b_init_global_memory_status = 0;
7701 g_b_init_global_memory_status_ex = 0;
7702 g_b_init_equal_sid = 0;
7703 g_b_init_copy_sid = 0;
7704 g_b_init_get_length_sid = 0;
7705 g_b_init_get_native_system_info = 0;
7706 g_b_init_get_system_times = 0;
7707 g_b_init_create_symbolic_link = 0;
7708 g_b_init_get_security_descriptor_dacl = 0;
7709 g_b_init_convert_sd_to_sddl = 0;
7710 g_b_init_convert_sddl_to_sd = 0;
7711 g_b_init_is_valid_security_descriptor = 0;
7712 g_b_init_set_file_security = 0;
7713 num_of_processors = 0;
7714 /* The following sets a handler for shutdown notifications for
7715 console apps. This actually applies to Emacs in both console and
7716 GUI modes, since we had to fool windows into thinking emacs is a
7717 console application to get console mode to work. */
7718 SetConsoleCtrlHandler (shutdown_handler, TRUE);
7720 /* "None" is the default group name on standalone workstations. */
7721 strcpy (dflt_group_name, "None");
7723 /* Reset, in case it has some value inherited from dump time. */
7724 w32_stat_get_owner_group = 0;
7727 /* For make-serial-process */
7729 serial_open (Lisp_Object port_obj)
7731 char *port = SSDATA (port_obj);
7732 HANDLE hnd;
7733 child_process *cp;
7734 int fd = -1;
7736 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
7737 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
7738 if (hnd == INVALID_HANDLE_VALUE)
7739 error ("Could not open %s", port);
7740 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
7741 if (fd == -1)
7742 error ("Could not open %s", port);
7744 cp = new_child ();
7745 if (!cp)
7746 error ("Could not create child process");
7747 cp->fd = fd;
7748 cp->status = STATUS_READ_ACKNOWLEDGED;
7749 fd_info[ fd ].hnd = hnd;
7750 fd_info[ fd ].flags |=
7751 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
7752 if (fd_info[ fd ].cp != NULL)
7754 error ("fd_info[fd = %d] is already in use", fd);
7756 fd_info[ fd ].cp = cp;
7757 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
7758 if (cp->ovl_read.hEvent == NULL)
7759 error ("Could not create read event");
7760 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
7761 if (cp->ovl_write.hEvent == NULL)
7762 error ("Could not create write event");
7764 return fd;
7767 /* For serial-process-configure */
7768 void
7769 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
7771 Lisp_Object childp2 = Qnil;
7772 Lisp_Object tem = Qnil;
7773 HANDLE hnd;
7774 DCB dcb;
7775 COMMTIMEOUTS ct;
7776 char summary[4] = "???"; /* This usually becomes "8N1". */
7778 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
7779 error ("Not a serial process");
7780 hnd = fd_info[ p->outfd ].hnd;
7782 childp2 = Fcopy_sequence (p->childp);
7784 /* Initialize timeouts for blocking read and blocking write. */
7785 if (!GetCommTimeouts (hnd, &ct))
7786 error ("GetCommTimeouts() failed");
7787 ct.ReadIntervalTimeout = 0;
7788 ct.ReadTotalTimeoutMultiplier = 0;
7789 ct.ReadTotalTimeoutConstant = 0;
7790 ct.WriteTotalTimeoutMultiplier = 0;
7791 ct.WriteTotalTimeoutConstant = 0;
7792 if (!SetCommTimeouts (hnd, &ct))
7793 error ("SetCommTimeouts() failed");
7794 /* Read port attributes and prepare default configuration. */
7795 memset (&dcb, 0, sizeof (dcb));
7796 dcb.DCBlength = sizeof (DCB);
7797 if (!GetCommState (hnd, &dcb))
7798 error ("GetCommState() failed");
7799 dcb.fBinary = TRUE;
7800 dcb.fNull = FALSE;
7801 dcb.fAbortOnError = FALSE;
7802 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
7803 dcb.ErrorChar = 0;
7804 dcb.EofChar = 0;
7805 dcb.EvtChar = 0;
7807 /* Configure speed. */
7808 if (!NILP (Fplist_member (contact, QCspeed)))
7809 tem = Fplist_get (contact, QCspeed);
7810 else
7811 tem = Fplist_get (p->childp, QCspeed);
7812 CHECK_NUMBER (tem);
7813 dcb.BaudRate = XINT (tem);
7814 childp2 = Fplist_put (childp2, QCspeed, tem);
7816 /* Configure bytesize. */
7817 if (!NILP (Fplist_member (contact, QCbytesize)))
7818 tem = Fplist_get (contact, QCbytesize);
7819 else
7820 tem = Fplist_get (p->childp, QCbytesize);
7821 if (NILP (tem))
7822 tem = make_number (8);
7823 CHECK_NUMBER (tem);
7824 if (XINT (tem) != 7 && XINT (tem) != 8)
7825 error (":bytesize must be nil (8), 7, or 8");
7826 dcb.ByteSize = XINT (tem);
7827 summary[0] = XINT (tem) + '0';
7828 childp2 = Fplist_put (childp2, QCbytesize, tem);
7830 /* Configure parity. */
7831 if (!NILP (Fplist_member (contact, QCparity)))
7832 tem = Fplist_get (contact, QCparity);
7833 else
7834 tem = Fplist_get (p->childp, QCparity);
7835 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
7836 error (":parity must be nil (no parity), `even', or `odd'");
7837 dcb.fParity = FALSE;
7838 dcb.Parity = NOPARITY;
7839 dcb.fErrorChar = FALSE;
7840 if (NILP (tem))
7842 summary[1] = 'N';
7844 else if (EQ (tem, Qeven))
7846 summary[1] = 'E';
7847 dcb.fParity = TRUE;
7848 dcb.Parity = EVENPARITY;
7849 dcb.fErrorChar = TRUE;
7851 else if (EQ (tem, Qodd))
7853 summary[1] = 'O';
7854 dcb.fParity = TRUE;
7855 dcb.Parity = ODDPARITY;
7856 dcb.fErrorChar = TRUE;
7858 childp2 = Fplist_put (childp2, QCparity, tem);
7860 /* Configure stopbits. */
7861 if (!NILP (Fplist_member (contact, QCstopbits)))
7862 tem = Fplist_get (contact, QCstopbits);
7863 else
7864 tem = Fplist_get (p->childp, QCstopbits);
7865 if (NILP (tem))
7866 tem = make_number (1);
7867 CHECK_NUMBER (tem);
7868 if (XINT (tem) != 1 && XINT (tem) != 2)
7869 error (":stopbits must be nil (1 stopbit), 1, or 2");
7870 summary[2] = XINT (tem) + '0';
7871 if (XINT (tem) == 1)
7872 dcb.StopBits = ONESTOPBIT;
7873 else if (XINT (tem) == 2)
7874 dcb.StopBits = TWOSTOPBITS;
7875 childp2 = Fplist_put (childp2, QCstopbits, tem);
7877 /* Configure flowcontrol. */
7878 if (!NILP (Fplist_member (contact, QCflowcontrol)))
7879 tem = Fplist_get (contact, QCflowcontrol);
7880 else
7881 tem = Fplist_get (p->childp, QCflowcontrol);
7882 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
7883 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
7884 dcb.fOutxCtsFlow = FALSE;
7885 dcb.fOutxDsrFlow = FALSE;
7886 dcb.fDtrControl = DTR_CONTROL_DISABLE;
7887 dcb.fDsrSensitivity = FALSE;
7888 dcb.fTXContinueOnXoff = FALSE;
7889 dcb.fOutX = FALSE;
7890 dcb.fInX = FALSE;
7891 dcb.fRtsControl = RTS_CONTROL_DISABLE;
7892 dcb.XonChar = 17; /* Control-Q */
7893 dcb.XoffChar = 19; /* Control-S */
7894 if (NILP (tem))
7896 /* Already configured. */
7898 else if (EQ (tem, Qhw))
7900 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
7901 dcb.fOutxCtsFlow = TRUE;
7903 else if (EQ (tem, Qsw))
7905 dcb.fOutX = TRUE;
7906 dcb.fInX = TRUE;
7908 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
7910 /* Activate configuration. */
7911 if (!SetCommState (hnd, &dcb))
7912 error ("SetCommState() failed");
7914 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
7915 pset_childp (p, childp2);
7918 #ifdef HAVE_GNUTLS
7920 ssize_t
7921 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
7923 int n, err;
7924 SELECT_TYPE fdset;
7925 EMACS_TIME timeout;
7926 struct Lisp_Process *process = (struct Lisp_Process *)p;
7927 int fd = process->infd;
7929 n = sys_read (fd, (char*)buf, sz);
7931 if (n >= 0)
7932 return n;
7934 err = errno;
7936 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7937 if (err == EWOULDBLOCK)
7938 err = EAGAIN;
7940 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
7942 return -1;
7945 ssize_t
7946 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
7948 struct Lisp_Process *process = (struct Lisp_Process *)p;
7949 int fd = process->outfd;
7950 ssize_t n = sys_write (fd, buf, sz);
7952 /* 0 or more bytes written means everything went fine. */
7953 if (n >= 0)
7954 return n;
7956 /* Negative bytes written means we got an error in errno.
7957 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7958 emacs_gnutls_transport_set_errno (process->gnutls_state,
7959 errno == EWOULDBLOCK ? EAGAIN : errno);
7961 return -1;
7963 #endif /* HAVE_GNUTLS */
7965 /* end of w32.c */