Update copyright year to 2014 by running admin/update-copyright.
[emacs.git] / src / w32.c
blob8aca8c1b71ccc25b2ff85937b45fba8e830dda90
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
3 Copyright (C) 1994-1995, 2000-2014 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
24 #include <mingw_time.h>
25 #include <stddef.h> /* for offsetof */
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <float.h> /* for DBL_EPSILON */
29 #include <io.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <ctype.h>
33 #include <signal.h>
34 #include <sys/file.h>
35 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
36 #include <sys/time.h>
37 #include <sys/utime.h>
38 #include <math.h>
40 /* must include CRT headers *before* config.h */
42 #include <config.h>
43 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
45 #undef access
46 #undef chdir
47 #undef chmod
48 #undef creat
49 #undef ctime
50 #undef fopen
51 #undef link
52 #undef mkdir
53 #undef open
54 #undef rename
55 #undef rmdir
56 #undef unlink
58 #undef close
59 #undef dup
60 #undef dup2
61 #undef pipe
62 #undef read
63 #undef write
65 #undef strerror
67 #undef localtime
69 #include "lisp.h"
70 #include "epaths.h" /* for SHELL */
72 #include <pwd.h>
73 #include <grp.h>
75 /* MinGW64 (_W64) defines these in its _mingw.h. */
76 #if defined(__GNUC__) && !defined(_W64)
77 #define _ANONYMOUS_UNION
78 #define _ANONYMOUS_STRUCT
79 #endif
80 #include <windows.h>
81 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
82 use a different name to avoid compilation problems. */
83 typedef struct _MEMORY_STATUS_EX {
84 DWORD dwLength;
85 DWORD dwMemoryLoad;
86 DWORDLONG ullTotalPhys;
87 DWORDLONG ullAvailPhys;
88 DWORDLONG ullTotalPageFile;
89 DWORDLONG ullAvailPageFile;
90 DWORDLONG ullTotalVirtual;
91 DWORDLONG ullAvailVirtual;
92 DWORDLONG ullAvailExtendedVirtual;
93 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
95 /* These are here so that GDB would know about these data types. This
96 allows to attach GDB to Emacs when a fatal exception is triggered
97 and Windows pops up the "application needs to be closed" dialog.
98 At that point, _gnu_exception_handler, the top-level exception
99 handler installed by the MinGW startup code, is somewhere on the
100 call-stack of the main thread, so going to that call frame and
101 looking at the argument to _gnu_exception_handler, which is a
102 PEXCEPTION_POINTERS pointer, can reveal the exception code
103 (excptr->ExceptionRecord->ExceptionCode) and the address where the
104 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
105 well as some additional information specific to the exception. */
106 PEXCEPTION_POINTERS excptr;
107 PEXCEPTION_RECORD excprec;
108 PCONTEXT ctxrec;
110 #include <lmcons.h>
111 #include <shlobj.h>
113 #include <tlhelp32.h>
114 #include <psapi.h>
115 #ifndef _MSC_VER
116 #include <w32api.h>
117 #endif
118 #if _WIN32_WINNT < 0x0500
119 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
120 /* This either is not in psapi.h or guarded by higher value of
121 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
122 defines it in psapi.h */
123 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
124 DWORD cb;
125 DWORD PageFaultCount;
126 SIZE_T PeakWorkingSetSize;
127 SIZE_T WorkingSetSize;
128 SIZE_T QuotaPeakPagedPoolUsage;
129 SIZE_T QuotaPagedPoolUsage;
130 SIZE_T QuotaPeakNonPagedPoolUsage;
131 SIZE_T QuotaNonPagedPoolUsage;
132 SIZE_T PagefileUsage;
133 SIZE_T PeakPagefileUsage;
134 SIZE_T PrivateUsage;
135 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
136 #endif
137 #endif
139 #include <winioctl.h>
140 #include <aclapi.h>
141 #include <sddl.h>
143 #include <sys/acl.h>
144 #include <acl.h>
146 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
147 define them by hand if not already defined. */
148 #ifndef SDDL_REVISION_1
149 #define SDDL_REVISION_1 1
150 #endif /* SDDL_REVISION_1 */
152 #if defined(_MSC_VER) || defined(_W64)
153 /* MSVC and MinGW64 don't provide the definition of
154 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
155 which cannot be included because it triggers conflicts with other
156 Windows API headers. So we define it here by hand. */
158 typedef struct _REPARSE_DATA_BUFFER {
159 ULONG ReparseTag;
160 USHORT ReparseDataLength;
161 USHORT Reserved;
162 union {
163 struct {
164 USHORT SubstituteNameOffset;
165 USHORT SubstituteNameLength;
166 USHORT PrintNameOffset;
167 USHORT PrintNameLength;
168 ULONG Flags;
169 WCHAR PathBuffer[1];
170 } SymbolicLinkReparseBuffer;
171 struct {
172 USHORT SubstituteNameOffset;
173 USHORT SubstituteNameLength;
174 USHORT PrintNameOffset;
175 USHORT PrintNameLength;
176 WCHAR PathBuffer[1];
177 } MountPointReparseBuffer;
178 struct {
179 UCHAR DataBuffer[1];
180 } GenericReparseBuffer;
181 } DUMMYUNIONNAME;
182 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
184 #ifndef FILE_DEVICE_FILE_SYSTEM
185 #define FILE_DEVICE_FILE_SYSTEM 9
186 #endif
187 #ifndef METHOD_BUFFERED
188 #define METHOD_BUFFERED 0
189 #endif
190 #ifndef FILE_ANY_ACCESS
191 #define FILE_ANY_ACCESS 0x00000000
192 #endif
193 #ifndef CTL_CODE
194 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
195 #endif
196 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
197 #ifndef FSCTL_GET_REPARSE_POINT
198 #define FSCTL_GET_REPARSE_POINT \
199 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
200 #endif
201 #endif
203 /* TCP connection support. */
204 #include <sys/socket.h>
205 #undef socket
206 #undef bind
207 #undef connect
208 #undef htons
209 #undef ntohs
210 #undef inet_addr
211 #undef gethostname
212 #undef gethostbyname
213 #undef getservbyname
214 #undef getpeername
215 #undef shutdown
216 #undef setsockopt
217 #undef listen
218 #undef getsockname
219 #undef accept
220 #undef recvfrom
221 #undef sendto
223 #include <iphlpapi.h> /* should be after winsock2.h */
225 #include "w32.h"
226 #include <dirent.h>
227 #include "w32common.h"
228 #include "w32heap.h"
229 #include "w32select.h"
230 #include "systime.h"
231 #include "dispextern.h" /* for xstrcasecmp */
232 #include "coding.h" /* for Vlocale_coding_system */
234 #include "careadlinkat.h"
235 #include "allocator.h"
237 /* For serial_configure and serial_open. */
238 #include "process.h"
240 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
241 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
243 Lisp_Object QCloaded_from;
245 void globals_of_w32 (void);
246 static DWORD get_rid (PSID);
247 static int is_symlink (const char *);
248 static char * chase_symlinks (const char *);
249 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
250 static int restore_privilege (TOKEN_PRIVILEGES *);
251 static BOOL WINAPI revert_to_self (void);
253 static int sys_access (const char *, int);
254 extern void *e_malloc (size_t);
255 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
256 struct timespec *, void *);
257 extern int sys_dup (int);
262 /* Initialization states.
264 WARNING: If you add any more such variables for additional APIs,
265 you MUST add initialization for them to globals_of_w32
266 below. This is because these variables might get set
267 to non-NULL values during dumping, but the dumped Emacs
268 cannot reuse those values, because it could be run on a
269 different version of the OS, where API addresses are
270 different. */
271 static BOOL g_b_init_is_windows_9x;
272 static BOOL g_b_init_open_process_token;
273 static BOOL g_b_init_get_token_information;
274 static BOOL g_b_init_lookup_account_sid;
275 static BOOL g_b_init_get_sid_sub_authority;
276 static BOOL g_b_init_get_sid_sub_authority_count;
277 static BOOL g_b_init_get_security_info;
278 static BOOL g_b_init_get_file_security_w;
279 static BOOL g_b_init_get_file_security_a;
280 static BOOL g_b_init_get_security_descriptor_owner;
281 static BOOL g_b_init_get_security_descriptor_group;
282 static BOOL g_b_init_is_valid_sid;
283 static BOOL g_b_init_create_toolhelp32_snapshot;
284 static BOOL g_b_init_process32_first;
285 static BOOL g_b_init_process32_next;
286 static BOOL g_b_init_open_thread_token;
287 static BOOL g_b_init_impersonate_self;
288 static BOOL g_b_init_revert_to_self;
289 static BOOL g_b_init_get_process_memory_info;
290 static BOOL g_b_init_get_process_working_set_size;
291 static BOOL g_b_init_global_memory_status;
292 static BOOL g_b_init_global_memory_status_ex;
293 static BOOL g_b_init_get_length_sid;
294 static BOOL g_b_init_equal_sid;
295 static BOOL g_b_init_copy_sid;
296 static BOOL g_b_init_get_native_system_info;
297 static BOOL g_b_init_get_system_times;
298 static BOOL g_b_init_create_symbolic_link_w;
299 static BOOL g_b_init_create_symbolic_link_a;
300 static BOOL g_b_init_get_security_descriptor_dacl;
301 static BOOL g_b_init_convert_sd_to_sddl;
302 static BOOL g_b_init_convert_sddl_to_sd;
303 static BOOL g_b_init_is_valid_security_descriptor;
304 static BOOL g_b_init_set_file_security_w;
305 static BOOL g_b_init_set_file_security_a;
306 static BOOL g_b_init_set_named_security_info_w;
307 static BOOL g_b_init_set_named_security_info_a;
308 static BOOL g_b_init_get_adapters_info;
311 BEGIN: Wrapper functions around OpenProcessToken
312 and other functions in advapi32.dll that are only
313 supported in Windows NT / 2k / XP
315 /* ** Function pointer typedefs ** */
316 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
317 HANDLE ProcessHandle,
318 DWORD DesiredAccess,
319 PHANDLE TokenHandle);
320 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
321 HANDLE TokenHandle,
322 TOKEN_INFORMATION_CLASS TokenInformationClass,
323 LPVOID TokenInformation,
324 DWORD TokenInformationLength,
325 PDWORD ReturnLength);
326 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
327 HANDLE process_handle,
328 LPFILETIME creation_time,
329 LPFILETIME exit_time,
330 LPFILETIME kernel_time,
331 LPFILETIME user_time);
333 GetProcessTimes_Proc get_process_times_fn = NULL;
335 #ifdef _UNICODE
336 const char * const LookupAccountSid_Name = "LookupAccountSidW";
337 #else
338 const char * const LookupAccountSid_Name = "LookupAccountSidA";
339 #endif
340 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
341 LPCTSTR lpSystemName,
342 PSID Sid,
343 LPTSTR Name,
344 LPDWORD cbName,
345 LPTSTR DomainName,
346 LPDWORD cbDomainName,
347 PSID_NAME_USE peUse);
348 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
349 PSID pSid,
350 DWORD n);
351 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
352 PSID pSid);
353 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
354 HANDLE handle,
355 SE_OBJECT_TYPE ObjectType,
356 SECURITY_INFORMATION SecurityInfo,
357 PSID *ppsidOwner,
358 PSID *ppsidGroup,
359 PACL *ppDacl,
360 PACL *ppSacl,
361 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
362 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
363 LPCWSTR lpFileName,
364 SECURITY_INFORMATION RequestedInformation,
365 PSECURITY_DESCRIPTOR pSecurityDescriptor,
366 DWORD nLength,
367 LPDWORD lpnLengthNeeded);
368 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
369 LPCSTR lpFileName,
370 SECURITY_INFORMATION RequestedInformation,
371 PSECURITY_DESCRIPTOR pSecurityDescriptor,
372 DWORD nLength,
373 LPDWORD lpnLengthNeeded);
374 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
375 LPCWSTR lpFileName,
376 SECURITY_INFORMATION SecurityInformation,
377 PSECURITY_DESCRIPTOR pSecurityDescriptor);
378 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
379 LPCSTR lpFileName,
380 SECURITY_INFORMATION SecurityInformation,
381 PSECURITY_DESCRIPTOR pSecurityDescriptor);
382 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
383 LPCWSTR lpObjectName,
384 SE_OBJECT_TYPE ObjectType,
385 SECURITY_INFORMATION SecurityInformation,
386 PSID psidOwner,
387 PSID psidGroup,
388 PACL pDacl,
389 PACL pSacl);
390 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
391 LPCSTR lpObjectName,
392 SE_OBJECT_TYPE ObjectType,
393 SECURITY_INFORMATION SecurityInformation,
394 PSID psidOwner,
395 PSID psidGroup,
396 PACL pDacl,
397 PACL pSacl);
398 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
399 PSECURITY_DESCRIPTOR pSecurityDescriptor,
400 PSID *pOwner,
401 LPBOOL lpbOwnerDefaulted);
402 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
403 PSECURITY_DESCRIPTOR pSecurityDescriptor,
404 PSID *pGroup,
405 LPBOOL lpbGroupDefaulted);
406 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
407 PSECURITY_DESCRIPTOR pSecurityDescriptor,
408 LPBOOL lpbDaclPresent,
409 PACL *pDacl,
410 LPBOOL lpbDaclDefaulted);
411 typedef BOOL (WINAPI * IsValidSid_Proc) (
412 PSID sid);
413 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
414 DWORD dwFlags,
415 DWORD th32ProcessID);
416 typedef BOOL (WINAPI * Process32First_Proc) (
417 HANDLE hSnapshot,
418 LPPROCESSENTRY32 lppe);
419 typedef BOOL (WINAPI * Process32Next_Proc) (
420 HANDLE hSnapshot,
421 LPPROCESSENTRY32 lppe);
422 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
423 HANDLE ThreadHandle,
424 DWORD DesiredAccess,
425 BOOL OpenAsSelf,
426 PHANDLE TokenHandle);
427 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
428 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
429 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
430 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
431 HANDLE Process,
432 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
433 DWORD cb);
434 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
435 HANDLE hProcess,
436 PSIZE_T lpMinimumWorkingSetSize,
437 PSIZE_T lpMaximumWorkingSetSize);
438 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
439 LPMEMORYSTATUS lpBuffer);
440 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
441 LPMEMORY_STATUS_EX lpBuffer);
442 typedef BOOL (WINAPI * CopySid_Proc) (
443 DWORD nDestinationSidLength,
444 PSID pDestinationSid,
445 PSID pSourceSid);
446 typedef BOOL (WINAPI * EqualSid_Proc) (
447 PSID pSid1,
448 PSID pSid2);
449 typedef DWORD (WINAPI * GetLengthSid_Proc) (
450 PSID pSid);
451 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
452 LPSYSTEM_INFO lpSystemInfo);
453 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
454 LPFILETIME lpIdleTime,
455 LPFILETIME lpKernelTime,
456 LPFILETIME lpUserTime);
457 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
458 LPCWSTR lpSymlinkFileName,
459 LPCWSTR lpTargetFileName,
460 DWORD dwFlags);
461 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
462 LPCSTR lpSymlinkFileName,
463 LPCSTR lpTargetFileName,
464 DWORD dwFlags);
465 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
466 LPCTSTR StringSecurityDescriptor,
467 DWORD StringSDRevision,
468 PSECURITY_DESCRIPTOR *SecurityDescriptor,
469 PULONG SecurityDescriptorSize);
470 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
471 PSECURITY_DESCRIPTOR SecurityDescriptor,
472 DWORD RequestedStringSDRevision,
473 SECURITY_INFORMATION SecurityInformation,
474 LPTSTR *StringSecurityDescriptor,
475 PULONG StringSecurityDescriptorLen);
476 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
477 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
478 PIP_ADAPTER_INFO pAdapterInfo,
479 PULONG pOutBufLen);
481 /* ** A utility function ** */
482 static BOOL
483 is_windows_9x (void)
485 static BOOL s_b_ret = 0;
486 OSVERSIONINFO os_ver;
487 if (g_b_init_is_windows_9x == 0)
489 g_b_init_is_windows_9x = 1;
490 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
491 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
492 if (GetVersionEx (&os_ver))
494 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
497 return s_b_ret;
500 static Lisp_Object ltime (ULONGLONG);
502 /* Get total user and system times for get-internal-run-time.
503 Returns a list of integers if the times are provided by the OS
504 (NT derivatives), otherwise it returns the result of current-time. */
505 Lisp_Object
506 w32_get_internal_run_time (void)
508 if (get_process_times_fn)
510 FILETIME create, exit, kernel, user;
511 HANDLE proc = GetCurrentProcess ();
512 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
514 LARGE_INTEGER user_int, kernel_int, total;
515 user_int.LowPart = user.dwLowDateTime;
516 user_int.HighPart = user.dwHighDateTime;
517 kernel_int.LowPart = kernel.dwLowDateTime;
518 kernel_int.HighPart = kernel.dwHighDateTime;
519 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
520 return ltime (total.QuadPart);
524 return Fcurrent_time ();
527 /* ** The wrapper functions ** */
529 static BOOL WINAPI
530 open_process_token (HANDLE ProcessHandle,
531 DWORD DesiredAccess,
532 PHANDLE TokenHandle)
534 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
535 HMODULE hm_advapi32 = NULL;
536 if (is_windows_9x () == TRUE)
538 return FALSE;
540 if (g_b_init_open_process_token == 0)
542 g_b_init_open_process_token = 1;
543 hm_advapi32 = LoadLibrary ("Advapi32.dll");
544 s_pfn_Open_Process_Token =
545 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
547 if (s_pfn_Open_Process_Token == NULL)
549 return FALSE;
551 return (
552 s_pfn_Open_Process_Token (
553 ProcessHandle,
554 DesiredAccess,
555 TokenHandle)
559 static BOOL WINAPI
560 get_token_information (HANDLE TokenHandle,
561 TOKEN_INFORMATION_CLASS TokenInformationClass,
562 LPVOID TokenInformation,
563 DWORD TokenInformationLength,
564 PDWORD ReturnLength)
566 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
567 HMODULE hm_advapi32 = NULL;
568 if (is_windows_9x () == TRUE)
570 return FALSE;
572 if (g_b_init_get_token_information == 0)
574 g_b_init_get_token_information = 1;
575 hm_advapi32 = LoadLibrary ("Advapi32.dll");
576 s_pfn_Get_Token_Information =
577 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
579 if (s_pfn_Get_Token_Information == NULL)
581 return FALSE;
583 return (
584 s_pfn_Get_Token_Information (
585 TokenHandle,
586 TokenInformationClass,
587 TokenInformation,
588 TokenInformationLength,
589 ReturnLength)
593 static BOOL WINAPI
594 lookup_account_sid (LPCTSTR lpSystemName,
595 PSID Sid,
596 LPTSTR Name,
597 LPDWORD cbName,
598 LPTSTR DomainName,
599 LPDWORD cbDomainName,
600 PSID_NAME_USE peUse)
602 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
603 HMODULE hm_advapi32 = NULL;
604 if (is_windows_9x () == TRUE)
606 return FALSE;
608 if (g_b_init_lookup_account_sid == 0)
610 g_b_init_lookup_account_sid = 1;
611 hm_advapi32 = LoadLibrary ("Advapi32.dll");
612 s_pfn_Lookup_Account_Sid =
613 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
615 if (s_pfn_Lookup_Account_Sid == NULL)
617 return FALSE;
619 return (
620 s_pfn_Lookup_Account_Sid (
621 lpSystemName,
622 Sid,
623 Name,
624 cbName,
625 DomainName,
626 cbDomainName,
627 peUse)
631 static PDWORD WINAPI
632 get_sid_sub_authority (PSID pSid, DWORD n)
634 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
635 static DWORD zero = 0U;
636 HMODULE hm_advapi32 = NULL;
637 if (is_windows_9x () == TRUE)
639 return &zero;
641 if (g_b_init_get_sid_sub_authority == 0)
643 g_b_init_get_sid_sub_authority = 1;
644 hm_advapi32 = LoadLibrary ("Advapi32.dll");
645 s_pfn_Get_Sid_Sub_Authority =
646 (GetSidSubAuthority_Proc) GetProcAddress (
647 hm_advapi32, "GetSidSubAuthority");
649 if (s_pfn_Get_Sid_Sub_Authority == NULL)
651 return &zero;
653 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
656 static PUCHAR WINAPI
657 get_sid_sub_authority_count (PSID pSid)
659 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
660 static UCHAR zero = 0U;
661 HMODULE hm_advapi32 = NULL;
662 if (is_windows_9x () == TRUE)
664 return &zero;
666 if (g_b_init_get_sid_sub_authority_count == 0)
668 g_b_init_get_sid_sub_authority_count = 1;
669 hm_advapi32 = LoadLibrary ("Advapi32.dll");
670 s_pfn_Get_Sid_Sub_Authority_Count =
671 (GetSidSubAuthorityCount_Proc) GetProcAddress (
672 hm_advapi32, "GetSidSubAuthorityCount");
674 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
676 return &zero;
678 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
681 static DWORD WINAPI
682 get_security_info (HANDLE handle,
683 SE_OBJECT_TYPE ObjectType,
684 SECURITY_INFORMATION SecurityInfo,
685 PSID *ppsidOwner,
686 PSID *ppsidGroup,
687 PACL *ppDacl,
688 PACL *ppSacl,
689 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
691 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
692 HMODULE hm_advapi32 = NULL;
693 if (is_windows_9x () == TRUE)
695 return FALSE;
697 if (g_b_init_get_security_info == 0)
699 g_b_init_get_security_info = 1;
700 hm_advapi32 = LoadLibrary ("Advapi32.dll");
701 s_pfn_Get_Security_Info =
702 (GetSecurityInfo_Proc) GetProcAddress (
703 hm_advapi32, "GetSecurityInfo");
705 if (s_pfn_Get_Security_Info == NULL)
707 return FALSE;
709 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
710 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
711 ppSecurityDescriptor));
714 static BOOL WINAPI
715 get_file_security (const char *lpFileName,
716 SECURITY_INFORMATION RequestedInformation,
717 PSECURITY_DESCRIPTOR pSecurityDescriptor,
718 DWORD nLength,
719 LPDWORD lpnLengthNeeded)
721 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
722 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
723 HMODULE hm_advapi32 = NULL;
724 if (is_windows_9x () == TRUE)
726 errno = ENOTSUP;
727 return FALSE;
729 if (w32_unicode_filenames)
731 wchar_t filename_w[MAX_PATH];
733 if (g_b_init_get_file_security_w == 0)
735 g_b_init_get_file_security_w = 1;
736 hm_advapi32 = LoadLibrary ("Advapi32.dll");
737 s_pfn_Get_File_SecurityW =
738 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
739 "GetFileSecurityW");
741 if (s_pfn_Get_File_SecurityW == NULL)
743 errno = ENOTSUP;
744 return FALSE;
746 filename_to_utf16 (lpFileName, filename_w);
747 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
748 pSecurityDescriptor, nLength,
749 lpnLengthNeeded));
751 else
753 char filename_a[MAX_PATH];
755 if (g_b_init_get_file_security_a == 0)
757 g_b_init_get_file_security_a = 1;
758 hm_advapi32 = LoadLibrary ("Advapi32.dll");
759 s_pfn_Get_File_SecurityA =
760 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
761 "GetFileSecurityA");
763 if (s_pfn_Get_File_SecurityA == NULL)
765 errno = ENOTSUP;
766 return FALSE;
768 filename_to_ansi (lpFileName, filename_a);
769 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
770 pSecurityDescriptor, nLength,
771 lpnLengthNeeded));
775 static BOOL WINAPI
776 set_file_security (const char *lpFileName,
777 SECURITY_INFORMATION SecurityInformation,
778 PSECURITY_DESCRIPTOR pSecurityDescriptor)
780 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
781 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
782 HMODULE hm_advapi32 = NULL;
783 if (is_windows_9x () == TRUE)
785 errno = ENOTSUP;
786 return FALSE;
788 if (w32_unicode_filenames)
790 wchar_t filename_w[MAX_PATH];
792 if (g_b_init_set_file_security_w == 0)
794 g_b_init_set_file_security_w = 1;
795 hm_advapi32 = LoadLibrary ("Advapi32.dll");
796 s_pfn_Set_File_SecurityW =
797 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
798 "SetFileSecurityW");
800 if (s_pfn_Set_File_SecurityW == NULL)
802 errno = ENOTSUP;
803 return FALSE;
805 filename_to_utf16 (lpFileName, filename_w);
806 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
807 pSecurityDescriptor));
809 else
811 char filename_a[MAX_PATH];
813 if (g_b_init_set_file_security_a == 0)
815 g_b_init_set_file_security_a = 1;
816 hm_advapi32 = LoadLibrary ("Advapi32.dll");
817 s_pfn_Set_File_SecurityA =
818 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
819 "SetFileSecurityA");
821 if (s_pfn_Set_File_SecurityA == NULL)
823 errno = ENOTSUP;
824 return FALSE;
826 filename_to_ansi (lpFileName, filename_a);
827 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
828 pSecurityDescriptor));
832 static DWORD WINAPI
833 set_named_security_info (LPCTSTR lpObjectName,
834 SE_OBJECT_TYPE ObjectType,
835 SECURITY_INFORMATION SecurityInformation,
836 PSID psidOwner,
837 PSID psidGroup,
838 PACL pDacl,
839 PACL pSacl)
841 static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
842 static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
843 HMODULE hm_advapi32 = NULL;
844 if (is_windows_9x () == TRUE)
846 errno = ENOTSUP;
847 return ENOTSUP;
849 if (w32_unicode_filenames)
851 wchar_t filename_w[MAX_PATH];
853 if (g_b_init_set_named_security_info_w == 0)
855 g_b_init_set_named_security_info_w = 1;
856 hm_advapi32 = LoadLibrary ("Advapi32.dll");
857 s_pfn_Set_Named_Security_InfoW =
858 (SetNamedSecurityInfoW_Proc) GetProcAddress (hm_advapi32,
859 "SetNamedSecurityInfoW");
861 if (s_pfn_Set_Named_Security_InfoW == NULL)
863 errno = ENOTSUP;
864 return ENOTSUP;
866 filename_to_utf16 (lpObjectName, filename_w);
867 return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
868 SecurityInformation, psidOwner,
869 psidGroup, pDacl, pSacl));
871 else
873 char filename_a[MAX_PATH];
875 if (g_b_init_set_named_security_info_a == 0)
877 g_b_init_set_named_security_info_a = 1;
878 hm_advapi32 = LoadLibrary ("Advapi32.dll");
879 s_pfn_Set_Named_Security_InfoA =
880 (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
881 "SetNamedSecurityInfoA");
883 if (s_pfn_Set_Named_Security_InfoA == NULL)
885 errno = ENOTSUP;
886 return ENOTSUP;
888 filename_to_ansi (lpObjectName, filename_a);
889 return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
890 SecurityInformation, psidOwner,
891 psidGroup, pDacl, pSacl));
895 static BOOL WINAPI
896 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
897 PSID *pOwner,
898 LPBOOL lpbOwnerDefaulted)
900 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
901 HMODULE hm_advapi32 = NULL;
902 if (is_windows_9x () == TRUE)
904 errno = ENOTSUP;
905 return FALSE;
907 if (g_b_init_get_security_descriptor_owner == 0)
909 g_b_init_get_security_descriptor_owner = 1;
910 hm_advapi32 = LoadLibrary ("Advapi32.dll");
911 s_pfn_Get_Security_Descriptor_Owner =
912 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
913 hm_advapi32, "GetSecurityDescriptorOwner");
915 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
917 errno = ENOTSUP;
918 return FALSE;
920 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
921 lpbOwnerDefaulted));
924 static BOOL WINAPI
925 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
926 PSID *pGroup,
927 LPBOOL lpbGroupDefaulted)
929 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
930 HMODULE hm_advapi32 = NULL;
931 if (is_windows_9x () == TRUE)
933 errno = ENOTSUP;
934 return FALSE;
936 if (g_b_init_get_security_descriptor_group == 0)
938 g_b_init_get_security_descriptor_group = 1;
939 hm_advapi32 = LoadLibrary ("Advapi32.dll");
940 s_pfn_Get_Security_Descriptor_Group =
941 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
942 hm_advapi32, "GetSecurityDescriptorGroup");
944 if (s_pfn_Get_Security_Descriptor_Group == NULL)
946 errno = ENOTSUP;
947 return FALSE;
949 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
950 lpbGroupDefaulted));
953 static BOOL WINAPI
954 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
955 LPBOOL lpbDaclPresent,
956 PACL *pDacl,
957 LPBOOL lpbDaclDefaulted)
959 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
960 HMODULE hm_advapi32 = NULL;
961 if (is_windows_9x () == TRUE)
963 errno = ENOTSUP;
964 return FALSE;
966 if (g_b_init_get_security_descriptor_dacl == 0)
968 g_b_init_get_security_descriptor_dacl = 1;
969 hm_advapi32 = LoadLibrary ("Advapi32.dll");
970 s_pfn_Get_Security_Descriptor_Dacl =
971 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
972 hm_advapi32, "GetSecurityDescriptorDacl");
974 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
976 errno = ENOTSUP;
977 return FALSE;
979 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
980 lpbDaclPresent, pDacl,
981 lpbDaclDefaulted));
984 static BOOL WINAPI
985 is_valid_sid (PSID sid)
987 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
988 HMODULE hm_advapi32 = NULL;
989 if (is_windows_9x () == TRUE)
991 return FALSE;
993 if (g_b_init_is_valid_sid == 0)
995 g_b_init_is_valid_sid = 1;
996 hm_advapi32 = LoadLibrary ("Advapi32.dll");
997 s_pfn_Is_Valid_Sid =
998 (IsValidSid_Proc) GetProcAddress (
999 hm_advapi32, "IsValidSid");
1001 if (s_pfn_Is_Valid_Sid == NULL)
1003 return FALSE;
1005 return (s_pfn_Is_Valid_Sid (sid));
1008 static BOOL WINAPI
1009 equal_sid (PSID sid1, PSID sid2)
1011 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
1012 HMODULE hm_advapi32 = NULL;
1013 if (is_windows_9x () == TRUE)
1015 return FALSE;
1017 if (g_b_init_equal_sid == 0)
1019 g_b_init_equal_sid = 1;
1020 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1021 s_pfn_Equal_Sid =
1022 (EqualSid_Proc) GetProcAddress (
1023 hm_advapi32, "EqualSid");
1025 if (s_pfn_Equal_Sid == NULL)
1027 return FALSE;
1029 return (s_pfn_Equal_Sid (sid1, sid2));
1032 static DWORD WINAPI
1033 get_length_sid (PSID sid)
1035 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
1036 HMODULE hm_advapi32 = NULL;
1037 if (is_windows_9x () == TRUE)
1039 return 0;
1041 if (g_b_init_get_length_sid == 0)
1043 g_b_init_get_length_sid = 1;
1044 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1045 s_pfn_Get_Length_Sid =
1046 (GetLengthSid_Proc) GetProcAddress (
1047 hm_advapi32, "GetLengthSid");
1049 if (s_pfn_Get_Length_Sid == NULL)
1051 return 0;
1053 return (s_pfn_Get_Length_Sid (sid));
1056 static BOOL WINAPI
1057 copy_sid (DWORD destlen, PSID dest, PSID src)
1059 static CopySid_Proc s_pfn_Copy_Sid = NULL;
1060 HMODULE hm_advapi32 = NULL;
1061 if (is_windows_9x () == TRUE)
1063 return FALSE;
1065 if (g_b_init_copy_sid == 0)
1067 g_b_init_copy_sid = 1;
1068 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1069 s_pfn_Copy_Sid =
1070 (CopySid_Proc) GetProcAddress (
1071 hm_advapi32, "CopySid");
1073 if (s_pfn_Copy_Sid == NULL)
1075 return FALSE;
1077 return (s_pfn_Copy_Sid (destlen, dest, src));
1081 END: Wrapper functions around OpenProcessToken
1082 and other functions in advapi32.dll that are only
1083 supported in Windows NT / 2k / XP
1086 static void WINAPI
1087 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1089 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1090 if (is_windows_9x () != TRUE)
1092 if (g_b_init_get_native_system_info == 0)
1094 g_b_init_get_native_system_info = 1;
1095 s_pfn_Get_Native_System_Info =
1096 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1097 "GetNativeSystemInfo");
1099 if (s_pfn_Get_Native_System_Info != NULL)
1100 s_pfn_Get_Native_System_Info (lpSystemInfo);
1102 else
1103 lpSystemInfo->dwNumberOfProcessors = -1;
1106 static BOOL WINAPI
1107 get_system_times (LPFILETIME lpIdleTime,
1108 LPFILETIME lpKernelTime,
1109 LPFILETIME lpUserTime)
1111 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1112 if (is_windows_9x () == TRUE)
1114 return FALSE;
1116 if (g_b_init_get_system_times == 0)
1118 g_b_init_get_system_times = 1;
1119 s_pfn_Get_System_times =
1120 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1121 "GetSystemTimes");
1123 if (s_pfn_Get_System_times == NULL)
1124 return FALSE;
1125 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1128 static BOOLEAN WINAPI
1129 create_symbolic_link (LPCSTR lpSymlinkFilename,
1130 LPCSTR lpTargetFileName,
1131 DWORD dwFlags)
1133 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1134 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1135 BOOLEAN retval;
1137 if (is_windows_9x () == TRUE)
1139 errno = ENOSYS;
1140 return 0;
1142 if (w32_unicode_filenames)
1144 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1146 if (g_b_init_create_symbolic_link_w == 0)
1148 g_b_init_create_symbolic_link_w = 1;
1149 s_pfn_Create_Symbolic_LinkW =
1150 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1151 "CreateSymbolicLinkW");
1153 if (s_pfn_Create_Symbolic_LinkW == NULL)
1155 errno = ENOSYS;
1156 return 0;
1159 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1160 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1161 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1162 /* If we were denied creation of the symlink, try again after
1163 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1164 if (!retval)
1166 TOKEN_PRIVILEGES priv_current;
1168 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1169 &priv_current))
1171 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1172 restore_privilege (&priv_current);
1173 revert_to_self ();
1177 else
1179 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1181 if (g_b_init_create_symbolic_link_a == 0)
1183 g_b_init_create_symbolic_link_a = 1;
1184 s_pfn_Create_Symbolic_LinkA =
1185 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1186 "CreateSymbolicLinkA");
1188 if (s_pfn_Create_Symbolic_LinkA == NULL)
1190 errno = ENOSYS;
1191 return 0;
1194 filename_to_ansi (lpSymlinkFilename, symfn_a);
1195 filename_to_ansi (lpTargetFileName, tgtfn_a);
1196 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1197 /* If we were denied creation of the symlink, try again after
1198 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1199 if (!retval)
1201 TOKEN_PRIVILEGES priv_current;
1203 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1204 &priv_current))
1206 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1207 restore_privilege (&priv_current);
1208 revert_to_self ();
1212 return retval;
1215 static BOOL WINAPI
1216 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1218 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1220 if (is_windows_9x () == TRUE)
1222 errno = ENOTSUP;
1223 return FALSE;
1226 if (g_b_init_is_valid_security_descriptor == 0)
1228 g_b_init_is_valid_security_descriptor = 1;
1229 s_pfn_Is_Valid_Security_Descriptor_Proc =
1230 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1231 "IsValidSecurityDescriptor");
1233 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1235 errno = ENOTSUP;
1236 return FALSE;
1239 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1242 static BOOL WINAPI
1243 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1244 DWORD RequestedStringSDRevision,
1245 SECURITY_INFORMATION SecurityInformation,
1246 LPTSTR *StringSecurityDescriptor,
1247 PULONG StringSecurityDescriptorLen)
1249 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1250 BOOL retval;
1252 if (is_windows_9x () == TRUE)
1254 errno = ENOTSUP;
1255 return FALSE;
1258 if (g_b_init_convert_sd_to_sddl == 0)
1260 g_b_init_convert_sd_to_sddl = 1;
1261 #ifdef _UNICODE
1262 s_pfn_Convert_SD_To_SDDL =
1263 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1264 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1265 #else
1266 s_pfn_Convert_SD_To_SDDL =
1267 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1268 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1269 #endif
1271 if (s_pfn_Convert_SD_To_SDDL == NULL)
1273 errno = ENOTSUP;
1274 return FALSE;
1277 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1278 RequestedStringSDRevision,
1279 SecurityInformation,
1280 StringSecurityDescriptor,
1281 StringSecurityDescriptorLen);
1283 return retval;
1286 static BOOL WINAPI
1287 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1288 DWORD StringSDRevision,
1289 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1290 PULONG SecurityDescriptorSize)
1292 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1293 BOOL retval;
1295 if (is_windows_9x () == TRUE)
1297 errno = ENOTSUP;
1298 return FALSE;
1301 if (g_b_init_convert_sddl_to_sd == 0)
1303 g_b_init_convert_sddl_to_sd = 1;
1304 #ifdef _UNICODE
1305 s_pfn_Convert_SDDL_To_SD =
1306 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1307 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1308 #else
1309 s_pfn_Convert_SDDL_To_SD =
1310 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1311 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1312 #endif
1314 if (s_pfn_Convert_SDDL_To_SD == NULL)
1316 errno = ENOTSUP;
1317 return FALSE;
1320 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1321 StringSDRevision,
1322 SecurityDescriptor,
1323 SecurityDescriptorSize);
1325 return retval;
1328 static DWORD WINAPI
1329 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1331 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1332 HMODULE hm_iphlpapi = NULL;
1334 if (is_windows_9x () == TRUE)
1335 return ERROR_NOT_SUPPORTED;
1337 if (g_b_init_get_adapters_info == 0)
1339 g_b_init_get_adapters_info = 1;
1340 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1341 if (hm_iphlpapi)
1342 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1343 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1345 if (s_pfn_Get_Adapters_Info == NULL)
1346 return ERROR_NOT_SUPPORTED;
1347 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1352 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1353 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1355 This is called from alloc.c:valid_pointer_p. */
1357 w32_valid_pointer_p (void *p, int size)
1359 SIZE_T done;
1360 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1362 if (h)
1364 unsigned char *buf = alloca (size);
1365 int retval = ReadProcessMemory (h, p, buf, size, &done);
1367 CloseHandle (h);
1368 return retval;
1370 else
1371 return -1;
1376 /* Here's an overview of how the Windows build supports file names
1377 that cannot be encoded by the current system codepage.
1379 From the POV of Lisp and layers of C code above the functions here,
1380 Emacs on Windows pretends that its file names are encoded in UTF-8;
1381 see encode_file and decode_file on coding.c. Any file name that is
1382 passed as a unibyte string to C functions defined here is assumed
1383 to be in UTF-8 encoding. Any file name returned by functions
1384 defined here must be in UTF-8 encoding, with only a few exceptions
1385 reserved for a couple of special cases. (Be sure to use
1386 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1387 as they can be much longer than MAX_PATH!)
1389 The UTF-8 encoded file names cannot be passed to system APIs, as
1390 Windows does not support that. Therefore, they are converted
1391 either to UTF-16 or to the ANSI codepage, depending on the value of
1392 w32-unicode-filenames, before calling any system APIs or CRT library
1393 functions. The default value of that variable is determined by the
1394 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1395 user can change that default (although I don't see why would she
1396 want to).
1398 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1399 filename_from_utf16, and filename_from_ansi, are the workhorses of
1400 these conversions. They rely on Windows native APIs
1401 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1402 functions from coding.c here, because they allocate memory, which
1403 is a bad idea on the level of libc, which is what the functions
1404 here emulate. (If you worry about performance due to constant
1405 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1406 it was measured to take only a few microseconds on a not-so-fast
1407 machine, and second, that's exactly what the ANSI APIs we used
1408 before do anyway, because they are just thin wrappers around the
1409 Unicode APIs.)
1411 The variables file-name-coding-system and default-file-name-coding-system
1412 still exist, but are actually used only when a file name needs to
1413 be converted to the ANSI codepage. This happens all the time when
1414 w32-unicode-filenames is nil, but can also happen from time to time
1415 when it is t. Otherwise, these variables have no effect on file-name
1416 encoding when w32-unicode-filenames is t; this is similar to
1417 selection-coding-system.
1419 This arrangement works very well, but it has a few gotchas and
1420 limitations:
1422 . Lisp code that encodes or decodes file names manually should
1423 normally use 'utf-8' as the coding-system on Windows,
1424 disregarding file-name-coding-system. This is a somewhat
1425 unpleasant consequence, but it cannot be avoided. Fortunately,
1426 very few Lisp packages need to do that.
1428 More generally, passing to library functions (e.g., fopen or
1429 opendir) file names already encoded in the ANSI codepage is
1430 explicitly *verboten*, as all those functions, as shadowed and
1431 emulated here, assume they will receive UTF-8 encoded file names.
1433 For the same reasons, no CRT function or Win32 API can be called
1434 directly in Emacs sources, without either converting the file
1435 name sfrom UTF-8 to either UTF-16 or ANSI codepage, or going
1436 through some shadowing function defined here.
1438 . Environment variables stored in Vprocess_environment are encoded
1439 in the ANSI codepage, so if getenv/egetenv is used for a variable
1440 whose value is a file name or a list of directories, it needs to
1441 be converted to UTF-8, before it is used as argument to functions
1442 or decoded into a Lisp string.
1444 . File names passed to external libraries, like the image libraries
1445 and GnuTLS, need special handling. These libraries generally
1446 don't support UTF-16 or UTF-8 file names, so they must get file
1447 names encoded in the ANSI codepage. To facilitate using these
1448 libraries with file names that are not encodable in the ANSI
1449 codepage, use the function ansi_encode_filename, which will try
1450 to use the short 8+3 alias of a file name if that file name is
1451 not encodable in the ANSI codepage. See image.c and gnutls.c for
1452 examples of how this should be done.
1454 . Running subprocesses in non-ASCII directories and with non-ASCII
1455 file arguments is limited to the current codepage (even though
1456 Emacs is perfectly capable of finding an executable program file
1457 even in a directory whose name cannot be encoded in the current
1458 codepage). This is because the command-line arguments are
1459 encoded _before_ they get to the w32-specific level, and the
1460 encoding is not known in advance (it doesn't have to be the
1461 current ANSI codepage), so w32proc.c functions cannot re-encode
1462 them in UTF-16. This should be fixed, but will also require
1463 changes in cmdproxy. The current limitation is not terribly bad
1464 anyway, since very few, if any, Windows console programs that are
1465 likely to be invoked by Emacs support UTF-16 encoded command
1466 lines.
1468 . For similar reasons, server.el and emacsclient are also limited
1469 to the current ANSI codepage for now.
1471 . Emacs itself can only handle command-line arguments encoded in
1472 the current codepage.
1474 . Turning on w32-unicode-filename on Windows 9X (if it at all
1475 works) requires UNICOWS.DLL, which is currently loaded only in a
1476 GUI session. */
1480 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1481 codepage defined by file-name-coding-system. */
1483 /* Current codepage for encoding file names. */
1484 static int file_name_codepage;
1486 /* Produce a Windows ANSI codepage suitable for encoding file names.
1487 Return the information about that codepage in CP_INFO. */
1488 static int
1489 codepage_for_filenames (CPINFO *cp_info)
1491 /* A simple cache to avoid calling GetCPInfo every time we need to
1492 encode/decode a file name. The file-name encoding is not
1493 supposed to be changed too frequently, if ever. */
1494 static Lisp_Object last_file_name_encoding;
1495 static CPINFO cp;
1496 Lisp_Object current_encoding;
1498 current_encoding = Vfile_name_coding_system;
1499 if (NILP (current_encoding))
1500 current_encoding = Vdefault_file_name_coding_system;
1502 if (!EQ (last_file_name_encoding, current_encoding))
1504 /* Default to the current ANSI codepage. */
1505 file_name_codepage = w32_ansi_code_page;
1507 if (NILP (current_encoding))
1509 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1510 char *cp = NULL, *end;
1511 int cpnum;
1513 if (strncmp (cpname, "cp", 2) == 0)
1514 cp = cpname + 2;
1515 else if (strncmp (cpname, "windows-", 8) == 0)
1516 cp = cpname + 8;
1518 if (cp)
1520 end = cp;
1521 cpnum = strtol (cp, &end, 10);
1522 if (cpnum && *end == '\0' && end - cp >= 2)
1523 file_name_codepage = cpnum;
1527 if (!file_name_codepage)
1528 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1530 if (!GetCPInfo (file_name_codepage, &cp))
1532 file_name_codepage = CP_ACP;
1533 if (!GetCPInfo (file_name_codepage, &cp))
1534 emacs_abort ();
1537 if (cp_info)
1538 *cp_info = cp;
1540 return file_name_codepage;
1544 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1546 int result = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
1547 fn_out, MAX_PATH);
1549 if (!result)
1551 DWORD err = GetLastError ();
1553 switch (err)
1555 case ERROR_INVALID_FLAGS:
1556 case ERROR_INVALID_PARAMETER:
1557 errno = EINVAL;
1558 break;
1559 case ERROR_INSUFFICIENT_BUFFER:
1560 case ERROR_NO_UNICODE_TRANSLATION:
1561 default:
1562 errno = ENOENT;
1563 break;
1565 return -1;
1567 return 0;
1571 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1573 int result = WideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1574 fn_out, MAX_UTF8_PATH, NULL, NULL);
1576 if (!result)
1578 DWORD err = GetLastError ();
1580 switch (err)
1582 case ERROR_INVALID_FLAGS:
1583 case ERROR_INVALID_PARAMETER:
1584 errno = EINVAL;
1585 break;
1586 case ERROR_INSUFFICIENT_BUFFER:
1587 case ERROR_NO_UNICODE_TRANSLATION:
1588 default:
1589 errno = ENOENT;
1590 break;
1592 return -1;
1594 return 0;
1598 filename_to_ansi (const char *fn_in, char *fn_out)
1600 wchar_t fn_utf16[MAX_PATH];
1602 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1604 int result;
1605 int codepage = codepage_for_filenames (NULL);
1607 result = WideCharToMultiByte (codepage, 0, fn_utf16, -1,
1608 fn_out, MAX_PATH, NULL, NULL);
1609 if (!result)
1611 DWORD err = GetLastError ();
1613 switch (err)
1615 case ERROR_INVALID_FLAGS:
1616 case ERROR_INVALID_PARAMETER:
1617 errno = EINVAL;
1618 break;
1619 case ERROR_INSUFFICIENT_BUFFER:
1620 case ERROR_NO_UNICODE_TRANSLATION:
1621 default:
1622 errno = ENOENT;
1623 break;
1625 return -1;
1627 return 0;
1629 return -1;
1633 filename_from_ansi (const char *fn_in, char *fn_out)
1635 wchar_t fn_utf16[MAX_PATH];
1636 int codepage = codepage_for_filenames (NULL);
1637 int result = MultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
1638 fn_utf16, MAX_PATH);
1640 if (!result)
1642 DWORD err = GetLastError ();
1644 switch (err)
1646 case ERROR_INVALID_FLAGS:
1647 case ERROR_INVALID_PARAMETER:
1648 errno = EINVAL;
1649 break;
1650 case ERROR_INSUFFICIENT_BUFFER:
1651 case ERROR_NO_UNICODE_TRANSLATION:
1652 default:
1653 errno = ENOENT;
1654 break;
1656 return -1;
1658 return filename_from_utf16 (fn_utf16, fn_out);
1663 /* The directory where we started, in UTF-8. */
1664 static char startup_dir[MAX_UTF8_PATH];
1666 /* Get the current working directory. */
1667 char *
1668 getcwd (char *dir, int dirsize)
1670 if (!dirsize)
1672 errno = EINVAL;
1673 return NULL;
1675 if (dirsize <= strlen (startup_dir))
1677 errno = ERANGE;
1678 return NULL;
1680 #if 0
1681 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1682 return dir;
1683 return NULL;
1684 #else
1685 /* Emacs doesn't actually change directory itself, it stays in the
1686 same directory where it was started. */
1687 strcpy (dir, startup_dir);
1688 return dir;
1689 #endif
1692 /* Emulate getloadavg. */
1694 struct load_sample {
1695 time_t sample_time;
1696 ULONGLONG idle;
1697 ULONGLONG kernel;
1698 ULONGLONG user;
1701 /* Number of processors on this machine. */
1702 static unsigned num_of_processors;
1704 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1705 static struct load_sample samples[16*60];
1706 static int first_idx = -1, last_idx = -1;
1707 static int max_idx = sizeof (samples) / sizeof (samples[0]);
1709 static int
1710 buf_next (int from)
1712 int next_idx = from + 1;
1714 if (next_idx >= max_idx)
1715 next_idx = 0;
1717 return next_idx;
1720 static int
1721 buf_prev (int from)
1723 int prev_idx = from - 1;
1725 if (prev_idx < 0)
1726 prev_idx = max_idx - 1;
1728 return prev_idx;
1731 static void
1732 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1734 SYSTEM_INFO sysinfo;
1735 FILETIME ft_idle, ft_user, ft_kernel;
1737 /* Initialize the number of processors on this machine. */
1738 if (num_of_processors <= 0)
1740 get_native_system_info (&sysinfo);
1741 num_of_processors = sysinfo.dwNumberOfProcessors;
1742 if (num_of_processors <= 0)
1744 GetSystemInfo (&sysinfo);
1745 num_of_processors = sysinfo.dwNumberOfProcessors;
1747 if (num_of_processors <= 0)
1748 num_of_processors = 1;
1751 /* TODO: Take into account threads that are ready to run, by
1752 sampling the "\System\Processor Queue Length" performance
1753 counter. The code below accounts only for threads that are
1754 actually running. */
1756 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1758 ULARGE_INTEGER uidle, ukernel, uuser;
1760 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1761 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1762 memcpy (&uuser, &ft_user, sizeof (ft_user));
1763 *idle = uidle.QuadPart;
1764 *kernel = ukernel.QuadPart;
1765 *user = uuser.QuadPart;
1767 else
1769 *idle = 0;
1770 *kernel = 0;
1771 *user = 0;
1775 /* Produce the load average for a given time interval, using the
1776 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1777 1-minute, 5-minute, or 15-minute average, respectively. */
1778 static double
1779 getavg (int which)
1781 double retval = -1.0;
1782 double tdiff;
1783 int idx;
1784 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1785 time_t now = samples[last_idx].sample_time;
1787 if (first_idx != last_idx)
1789 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1791 tdiff = difftime (now, samples[idx].sample_time);
1792 if (tdiff >= span - 2*DBL_EPSILON*now)
1794 long double sys =
1795 samples[last_idx].kernel + samples[last_idx].user
1796 - (samples[idx].kernel + samples[idx].user);
1797 long double idl = samples[last_idx].idle - samples[idx].idle;
1799 retval = (1.0 - idl / sys) * num_of_processors;
1800 break;
1802 if (idx == first_idx)
1803 break;
1807 return retval;
1811 getloadavg (double loadavg[], int nelem)
1813 int elem;
1814 ULONGLONG idle, kernel, user;
1815 time_t now = time (NULL);
1817 /* If system time jumped back for some reason, delete all samples
1818 whose time is later than the current wall-clock time. This
1819 prevents load average figures from becoming frozen for prolonged
1820 periods of time, when system time is reset backwards. */
1821 if (last_idx >= 0)
1823 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1825 if (last_idx == first_idx)
1827 first_idx = last_idx = -1;
1828 break;
1830 last_idx = buf_prev (last_idx);
1834 /* Store another sample. We ignore samples that are less than 1 sec
1835 apart. */
1836 if (last_idx < 0
1837 || (difftime (now, samples[last_idx].sample_time)
1838 >= 1.0 - 2*DBL_EPSILON*now))
1840 sample_system_load (&idle, &kernel, &user);
1841 last_idx = buf_next (last_idx);
1842 samples[last_idx].sample_time = now;
1843 samples[last_idx].idle = idle;
1844 samples[last_idx].kernel = kernel;
1845 samples[last_idx].user = user;
1846 /* If the buffer has more that 15 min worth of samples, discard
1847 the old ones. */
1848 if (first_idx == -1)
1849 first_idx = last_idx;
1850 while (first_idx != last_idx
1851 && (difftime (now, samples[first_idx].sample_time)
1852 >= 15.0*60 + 2*DBL_EPSILON*now))
1853 first_idx = buf_next (first_idx);
1856 for (elem = 0; elem < nelem; elem++)
1858 double avg = getavg (elem);
1860 if (avg < 0)
1861 break;
1862 loadavg[elem] = avg;
1865 return elem;
1868 /* Emulate getpwuid, getpwnam and others. */
1870 #define PASSWD_FIELD_SIZE 256
1872 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1873 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1874 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1875 static char dflt_passwd_dir[MAX_UTF8_PATH];
1876 static char dflt_passwd_shell[MAX_UTF8_PATH];
1878 static struct passwd dflt_passwd =
1880 dflt_passwd_name,
1881 dflt_passwd_passwd,
1885 dflt_passwd_gecos,
1886 dflt_passwd_dir,
1887 dflt_passwd_shell,
1890 static char dflt_group_name[GNLEN+1];
1892 static struct group dflt_group =
1894 /* When group information is not available, we return this as the
1895 group for all files. */
1896 dflt_group_name,
1900 unsigned
1901 getuid (void)
1903 return dflt_passwd.pw_uid;
1906 unsigned
1907 geteuid (void)
1909 /* I could imagine arguing for checking to see whether the user is
1910 in the Administrators group and returning a UID of 0 for that
1911 case, but I don't know how wise that would be in the long run. */
1912 return getuid ();
1915 unsigned
1916 getgid (void)
1918 return dflt_passwd.pw_gid;
1921 unsigned
1922 getegid (void)
1924 return getgid ();
1927 struct passwd *
1928 getpwuid (unsigned uid)
1930 if (uid == dflt_passwd.pw_uid)
1931 return &dflt_passwd;
1932 return NULL;
1935 struct group *
1936 getgrgid (gid_t gid)
1938 return &dflt_group;
1941 struct passwd *
1942 getpwnam (char *name)
1944 struct passwd *pw;
1946 pw = getpwuid (getuid ());
1947 if (!pw)
1948 return pw;
1950 if (xstrcasecmp (name, pw->pw_name))
1951 return NULL;
1953 return pw;
1956 static void
1957 init_user_info (void)
1959 /* Find the user's real name by opening the process token and
1960 looking up the name associated with the user-sid in that token.
1962 Use the relative portion of the identifier authority value from
1963 the user-sid as the user id value (same for group id using the
1964 primary group sid from the process token). */
1966 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1967 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1968 DWORD glength = sizeof (gname);
1969 HANDLE token = NULL;
1970 SID_NAME_USE user_type;
1971 unsigned char *buf = NULL;
1972 DWORD blen = 0;
1973 TOKEN_USER user_token;
1974 TOKEN_PRIMARY_GROUP group_token;
1975 BOOL result;
1977 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1978 if (result)
1980 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1981 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1983 buf = xmalloc (blen);
1984 result = get_token_information (token, TokenUser,
1985 (LPVOID)buf, blen, &needed);
1986 if (result)
1988 memcpy (&user_token, buf, sizeof (user_token));
1989 result = lookup_account_sid (NULL, user_token.User.Sid,
1990 uname, &ulength,
1991 domain, &dlength, &user_type);
1994 else
1995 result = FALSE;
1997 if (result)
1999 strcpy (dflt_passwd.pw_name, uname);
2000 /* Determine a reasonable uid value. */
2001 if (xstrcasecmp ("administrator", uname) == 0)
2003 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
2004 dflt_passwd.pw_gid = 513; /* well-known None gid */
2006 else
2008 /* Use the last sub-authority value of the RID, the relative
2009 portion of the SID, as user/group ID. */
2010 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
2012 /* Get group id and name. */
2013 result = get_token_information (token, TokenPrimaryGroup,
2014 (LPVOID)buf, blen, &needed);
2015 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2017 buf = xrealloc (buf, blen = needed);
2018 result = get_token_information (token, TokenPrimaryGroup,
2019 (LPVOID)buf, blen, &needed);
2021 if (result)
2023 memcpy (&group_token, buf, sizeof (group_token));
2024 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
2025 dlength = sizeof (domain);
2026 /* If we can get at the real Primary Group name, use that.
2027 Otherwise, the default group name was already set to
2028 "None" in globals_of_w32. */
2029 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
2030 gname, &glength, NULL, &dlength,
2031 &user_type))
2032 strcpy (dflt_group_name, gname);
2034 else
2035 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2038 /* If security calls are not supported (presumably because we
2039 are running under Windows 9X), fallback to this: */
2040 else if (GetUserName (uname, &ulength))
2042 strcpy (dflt_passwd.pw_name, uname);
2043 if (xstrcasecmp ("administrator", uname) == 0)
2044 dflt_passwd.pw_uid = 0;
2045 else
2046 dflt_passwd.pw_uid = 123;
2047 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2049 else
2051 strcpy (dflt_passwd.pw_name, "unknown");
2052 dflt_passwd.pw_uid = 123;
2053 dflt_passwd.pw_gid = 123;
2055 dflt_group.gr_gid = dflt_passwd.pw_gid;
2057 /* Set dir and shell from environment variables. */
2058 if (w32_unicode_filenames)
2060 wchar_t *home = _wgetenv (L"HOME");
2061 wchar_t *shell = _wgetenv (L"SHELL");
2063 /* Ensure HOME and SHELL are defined. */
2064 if (home == NULL)
2065 emacs_abort ();
2066 if (shell == NULL)
2067 emacs_abort ();
2068 filename_from_utf16 (home, dflt_passwd.pw_dir);
2069 filename_from_utf16 (shell, dflt_passwd.pw_shell);
2071 else
2073 char *home = getenv ("HOME");
2074 char *shell = getenv ("SHELL");
2076 if (home == NULL)
2077 emacs_abort ();
2078 if (shell == NULL)
2079 emacs_abort ();
2080 filename_from_ansi (home, dflt_passwd.pw_dir);
2081 filename_from_ansi (shell, dflt_passwd.pw_shell);
2084 xfree (buf);
2085 if (token)
2086 CloseHandle (token);
2090 random (void)
2092 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
2093 return ((rand () << 15) | rand ());
2096 void
2097 srandom (int seed)
2099 srand (seed);
2102 /* Return the maximum length in bytes of a multibyte character
2103 sequence encoded in the current ANSI codepage. This is required to
2104 correctly walk the encoded file names one character at a time. */
2105 static int
2106 max_filename_mbslen (void)
2108 CPINFO cp_info;
2110 codepage_for_filenames (&cp_info);
2111 return cp_info.MaxCharSize;
2114 /* Normalize filename by converting in-place all of its path
2115 separators to the separator specified by PATH_SEP. */
2117 static void
2118 normalize_filename (register char *fp, char path_sep)
2120 char *p2;
2122 /* Always lower-case drive letters a-z, even if the filesystem
2123 preserves case in filenames.
2124 This is so filenames can be compared by string comparison
2125 functions that are case-sensitive. Even case-preserving filesystems
2126 do not distinguish case in drive letters. */
2127 p2 = fp + 1;
2129 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2131 *fp += 'a' - 'A';
2132 fp += 2;
2135 while (*fp)
2137 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2138 *fp = path_sep;
2139 fp++;
2143 /* Destructively turn backslashes into slashes. */
2144 void
2145 dostounix_filename (register char *p)
2147 normalize_filename (p, '/');
2150 /* Destructively turn slashes into backslashes. */
2151 void
2152 unixtodos_filename (register char *p)
2154 normalize_filename (p, '\\');
2157 /* Remove all CR's that are followed by a LF.
2158 (From msdos.c...probably should figure out a way to share it,
2159 although this code isn't going to ever change.) */
2160 static int
2161 crlf_to_lf (register int n, register unsigned char *buf)
2163 unsigned char *np = buf;
2164 unsigned char *startp = buf;
2165 unsigned char *endp = buf + n;
2167 if (n == 0)
2168 return n;
2169 while (buf < endp - 1)
2171 if (*buf == 0x0d)
2173 if (*(++buf) != 0x0a)
2174 *np++ = 0x0d;
2176 else
2177 *np++ = *buf++;
2179 if (buf < endp)
2180 *np++ = *buf++;
2181 return np - startp;
2184 /* Parse the root part of file name, if present. Return length and
2185 optionally store pointer to char after root. */
2186 static int
2187 parse_root (const char * name, const char ** pPath)
2189 const char * start = name;
2191 if (name == NULL)
2192 return 0;
2194 /* find the root name of the volume if given */
2195 if (isalpha (name[0]) && name[1] == ':')
2197 /* skip past drive specifier */
2198 name += 2;
2199 if (IS_DIRECTORY_SEP (name[0]))
2200 name++;
2202 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2204 int slashes = 2;
2206 name += 2;
2209 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2210 break;
2211 name++;
2213 while ( *name );
2214 if (IS_DIRECTORY_SEP (name[0]))
2215 name++;
2218 if (pPath)
2219 *pPath = name;
2221 return name - start;
2224 /* Get long base name for name; name is assumed to be absolute. */
2225 static int
2226 get_long_basename (char * name, char * buf, int size)
2228 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2229 char fname_utf8[MAX_UTF8_PATH];
2230 int len = 0;
2231 int cstatus = -1;
2233 /* Must be valid filename, no wild cards or other invalid characters. */
2234 if (strpbrk (name, "*?|<>\""))
2235 return 0;
2237 if (w32_unicode_filenames)
2239 wchar_t fname_utf16[MAX_PATH];
2240 WIN32_FIND_DATAW find_data_wide;
2242 filename_to_utf16 (name, fname_utf16);
2243 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2244 if (dir_handle != INVALID_HANDLE_VALUE)
2245 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2247 else
2249 char fname_ansi[MAX_PATH];
2250 WIN32_FIND_DATAA find_data_ansi;
2252 filename_to_ansi (name, fname_ansi);
2253 /* If the ANSI name includes ? characters, it is not encodable
2254 in the ANSI codepage. In that case, we deliver the question
2255 marks to the caller; calling FindFirstFileA in this case
2256 could return some unrelated file name in the same
2257 directory. */
2258 if (_mbspbrk (fname_ansi, "?"))
2260 /* Find the basename of fname_ansi. */
2261 char *p = strrchr (fname_ansi, '\\');
2263 if (!p)
2264 p = fname_ansi;
2265 else
2266 p++;
2267 cstatus = filename_from_ansi (p, fname_utf8);
2269 else
2271 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2272 if (dir_handle != INVALID_HANDLE_VALUE)
2273 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2277 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2278 memcpy (buf, fname_utf8, len + 1);
2279 else
2280 len = 0;
2282 if (dir_handle != INVALID_HANDLE_VALUE)
2283 FindClose (dir_handle);
2285 return len;
2288 /* Get long name for file, if possible (assumed to be absolute). */
2289 BOOL
2290 w32_get_long_filename (char * name, char * buf, int size)
2292 char * o = buf;
2293 char * p;
2294 const char * q;
2295 char full[ MAX_UTF8_PATH ];
2296 int len;
2298 len = strlen (name);
2299 if (len >= MAX_UTF8_PATH)
2300 return FALSE;
2302 /* Use local copy for destructive modification. */
2303 memcpy (full, name, len+1);
2304 unixtodos_filename (full);
2306 /* Copy root part verbatim. */
2307 len = parse_root (full, (const char **)&p);
2308 memcpy (o, full, len);
2309 o += len;
2310 *o = '\0';
2311 size -= len;
2313 while (p != NULL && *p)
2315 q = p;
2316 p = strchr (q, '\\');
2317 if (p) *p = '\0';
2318 len = get_long_basename (full, o, size);
2319 if (len > 0)
2321 o += len;
2322 size -= len;
2323 if (p != NULL)
2325 *p++ = '\\';
2326 if (size < 2)
2327 return FALSE;
2328 *o++ = '\\';
2329 size--;
2330 *o = '\0';
2333 else
2334 return FALSE;
2337 return TRUE;
2340 unsigned int
2341 w32_get_short_filename (char * name, char * buf, int size)
2343 if (w32_unicode_filenames)
2345 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2346 unsigned int retval;
2348 filename_to_utf16 (name, name_utf16);
2349 retval = GetShortPathNameW (name_utf16, short_name, size);
2350 if (retval && retval < size)
2351 filename_from_utf16 (short_name, buf);
2352 return retval;
2354 else
2356 char name_ansi[MAX_PATH];
2358 filename_to_ansi (name, name_ansi);
2359 return GetShortPathNameA (name_ansi, buf, size);
2363 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2364 MS-Windows ANSI codepage. If FILENAME includes characters not
2365 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2366 if it exists. This is needed because the w32 build wants to
2367 support file names outside of the system locale, but image
2368 libraries typically don't support wide (a.k.a. "Unicode") APIs
2369 required for that. */
2371 Lisp_Object
2372 ansi_encode_filename (Lisp_Object filename)
2374 Lisp_Object encoded_filename;
2375 char fname[MAX_PATH];
2377 filename_to_ansi (SSDATA (filename), fname);
2378 if (_mbspbrk (fname, "?"))
2380 char shortname[MAX_PATH];
2382 if (w32_get_short_filename (SDATA (filename), shortname, MAX_PATH))
2384 dostounix_filename (shortname);
2385 encoded_filename = build_string (shortname);
2388 else
2389 encoded_filename = build_unibyte_string (fname);
2390 return encoded_filename;
2393 static int
2394 is_unc_volume (const char *filename)
2396 const char *ptr = filename;
2398 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2399 return 0;
2401 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2402 return 0;
2404 return 1;
2407 /* Emulate the Posix unsetenv. */
2409 unsetenv (const char *name)
2411 char *var;
2412 size_t name_len;
2413 int retval;
2415 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2417 errno = EINVAL;
2418 return -1;
2420 name_len = strlen (name);
2421 /* MS docs says an environment variable cannot be longer than 32K. */
2422 if (name_len > 32767)
2424 errno = ENOMEM;
2425 return 0;
2427 /* It is safe to use 'alloca' with 32K size, since the stack is at
2428 least 2MB, and we set it to 8MB in the link command line. */
2429 var = alloca (name_len + 2);
2430 strncpy (var, name, name_len);
2431 var[name_len++] = '=';
2432 var[name_len] = '\0';
2433 return _putenv (var);
2436 /* MS _putenv doesn't support removing a variable when the argument
2437 does not include the '=' character, so we fix that here. */
2439 sys_putenv (char *str)
2441 const char *const name_end = strchr (str, '=');
2443 if (name_end == NULL)
2445 /* Remove the variable from the environment. */
2446 return unsetenv (str);
2449 return _putenv (str);
2452 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2454 LPBYTE
2455 w32_get_resource (char *key, LPDWORD lpdwtype)
2457 LPBYTE lpvalue;
2458 HKEY hrootkey = NULL;
2459 DWORD cbData;
2461 /* Check both the current user and the local machine to see if
2462 we have any resources. */
2464 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2466 lpvalue = NULL;
2468 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2469 && (lpvalue = xmalloc (cbData)) != NULL
2470 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2472 RegCloseKey (hrootkey);
2473 return (lpvalue);
2476 xfree (lpvalue);
2478 RegCloseKey (hrootkey);
2481 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2483 lpvalue = NULL;
2485 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2486 && (lpvalue = xmalloc (cbData)) != NULL
2487 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2489 RegCloseKey (hrootkey);
2490 return (lpvalue);
2493 xfree (lpvalue);
2495 RegCloseKey (hrootkey);
2498 return (NULL);
2501 /* The argv[] array holds ANSI-encoded strings, and so this function
2502 works with ANS_encoded strings. */
2503 void
2504 init_environment (char ** argv)
2506 static const char * const tempdirs[] = {
2507 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2510 int i;
2512 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
2514 /* Implementation note: This function explicitly works with ANSI
2515 file names, not with UTF-8 encoded file names. This is because
2516 this function pushes variables into the Emacs's environment, and
2517 the environment variables are always assumed to be in the
2518 locale-specific encoding. Do NOT call any functions that accept
2519 UTF-8 file names from this function! */
2521 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2522 temporary files and assume "/tmp" if $TMPDIR is unset, which
2523 will break on DOS/Windows. Refuse to work if we cannot find
2524 a directory, not even "c:/", usable for that purpose. */
2525 for (i = 0; i < imax ; i++)
2527 const char *tmp = tempdirs[i];
2529 if (*tmp == '$')
2530 tmp = getenv (tmp + 1);
2531 /* Note that `access' can lie to us if the directory resides on a
2532 read-only filesystem, like CD-ROM or a write-protected floppy.
2533 The only way to be really sure is to actually create a file and
2534 see if it succeeds. But I think that's too much to ask. */
2536 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2537 if (tmp && sys_access (tmp, D_OK) == 0)
2539 char * var = alloca (strlen (tmp) + 8);
2540 sprintf (var, "TMPDIR=%s", tmp);
2541 _putenv (strdup (var));
2542 break;
2545 if (i >= imax)
2546 cmd_error_internal
2547 (Fcons (Qerror,
2548 Fcons (build_string ("no usable temporary directories found!!"),
2549 Qnil)),
2550 "While setting TMPDIR: ");
2552 /* Check for environment variables and use registry settings if they
2553 don't exist. Fallback on default values where applicable. */
2555 int i;
2556 LPBYTE lpval;
2557 DWORD dwType;
2558 char locale_name[32];
2559 char default_home[MAX_PATH];
2560 int appdata = 0;
2562 static const struct env_entry
2564 char * name;
2565 char * def_value;
2566 } dflt_envvars[] =
2568 /* If the default value is NULL, we will use the value from the
2569 outside environment or the Registry, but will not push the
2570 variable into the Emacs environment if it is defined neither
2571 in the Registry nor in the outside environment. */
2572 {"HOME", "C:/"},
2573 {"PRELOAD_WINSOCK", NULL},
2574 {"emacs_dir", "C:/emacs"},
2575 {"EMACSLOADPATH", NULL},
2576 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2577 {"EMACSDATA", NULL},
2578 {"EMACSPATH", NULL},
2579 {"INFOPATH", NULL},
2580 {"EMACSDOC", NULL},
2581 {"TERM", "cmd"},
2582 {"LANG", NULL},
2585 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
2587 /* We need to copy dflt_envvars[] and work on the copy because we
2588 don't want the dumped Emacs to inherit the values of
2589 environment variables we saw during dumping (which could be on
2590 a different system). The defaults above must be left intact. */
2591 struct env_entry env_vars[N_ENV_VARS];
2593 for (i = 0; i < N_ENV_VARS; i++)
2594 env_vars[i] = dflt_envvars[i];
2596 /* For backwards compatibility, check if a .emacs file exists in C:/
2597 If not, then we can try to default to the appdata directory under the
2598 user's profile, which is more likely to be writable. */
2599 if (sys_access ("C:/.emacs", F_OK) != 0)
2601 HRESULT profile_result;
2602 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2603 of Windows 95 and NT4 that have not been updated to include
2604 MSIE 5. */
2605 ShGetFolderPath_fn get_folder_path;
2606 get_folder_path = (ShGetFolderPath_fn)
2607 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2609 if (get_folder_path != NULL)
2611 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2612 0, default_home);
2614 /* If we can't get the appdata dir, revert to old behavior. */
2615 if (profile_result == S_OK)
2617 env_vars[0].def_value = default_home;
2618 appdata = 1;
2623 /* Get default locale info and use it for LANG. */
2624 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2625 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2626 locale_name, sizeof (locale_name)))
2628 for (i = 0; i < N_ENV_VARS; i++)
2630 if (strcmp (env_vars[i].name, "LANG") == 0)
2632 env_vars[i].def_value = locale_name;
2633 break;
2638 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2640 /* Treat emacs_dir specially: set it unconditionally based on our
2641 location. */
2643 char *p;
2644 char modname[MAX_PATH];
2646 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2647 emacs_abort ();
2648 if ((p = _mbsrchr (modname, '\\')) == NULL)
2649 emacs_abort ();
2650 *p = 0;
2652 if ((p = _mbsrchr (modname, '\\'))
2653 /* From bin means installed Emacs, from src means uninstalled. */
2654 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2656 char buf[SET_ENV_BUF_SIZE];
2657 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2659 *p = 0;
2660 for (p = modname; *p; p = CharNext (p))
2661 if (*p == '\\') *p = '/';
2663 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2664 _putenv (strdup (buf));
2665 /* If we are running from the Posix-like build tree, define
2666 SHELL to point to our own cmdproxy. The loop below will
2667 then disregard PATH_EXEC and the default value. */
2668 if (within_build_tree)
2670 _snprintf (buf, sizeof (buf) - 1,
2671 "SHELL=%s/nt/cmdproxy.exe", modname);
2672 _putenv (strdup (buf));
2677 for (i = 0; i < N_ENV_VARS; i++)
2679 if (!getenv (env_vars[i].name))
2681 int dont_free = 0;
2682 char bufc[SET_ENV_BUF_SIZE];
2684 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2685 /* Also ignore empty environment variables. */
2686 || *lpval == 0)
2688 xfree (lpval);
2689 dont_free = 1;
2690 if (strcmp (env_vars[i].name, "SHELL") == 0)
2692 /* Look for cmdproxy.exe in every directory in
2693 PATH_EXEC. FIXME: This does not find cmdproxy
2694 in nt/ when we run uninstalled. */
2695 char fname[MAX_PATH];
2696 const char *pstart = PATH_EXEC, *pend;
2698 do {
2699 pend = _mbschr (pstart, ';');
2700 if (!pend)
2701 pend = pstart + strlen (pstart);
2702 /* Be defensive against series of ;;; characters. */
2703 if (pend > pstart)
2705 strncpy (fname, pstart, pend - pstart);
2706 fname[pend - pstart] = '/';
2707 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2708 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2709 sizeof (bufc));
2710 if (sys_access (bufc, F_OK) == 0)
2712 lpval = bufc;
2713 dwType = REG_SZ;
2714 break;
2717 if (*pend)
2718 pstart = pend + 1;
2719 else
2720 pstart = pend;
2721 if (!*pstart)
2723 /* If not found in any directory, use the
2724 default as the last resort. */
2725 lpval = env_vars[i].def_value;
2726 dwType = REG_EXPAND_SZ;
2728 } while (*pstart);
2730 else
2732 lpval = env_vars[i].def_value;
2733 dwType = REG_EXPAND_SZ;
2735 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2736 Vdelayed_warnings_list
2737 = Fcons (listn (CONSTYPE_HEAP, 2,
2738 intern ("initialization"),
2739 build_string ("Setting HOME to C:\\ by default is deprecated")),
2740 Vdelayed_warnings_list);
2743 if (lpval)
2745 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2747 if (dwType == REG_EXPAND_SZ)
2748 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2749 else if (dwType == REG_SZ)
2750 strcpy (buf1, lpval);
2751 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2753 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2754 buf1);
2755 _putenv (strdup (buf2));
2758 if (!dont_free)
2759 xfree (lpval);
2765 /* Rebuild system configuration to reflect invoking system. */
2766 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2768 /* Another special case: on NT, the PATH variable is actually named
2769 "Path" although cmd.exe (perhaps NT itself) arranges for
2770 environment variable lookup and setting to be case insensitive.
2771 However, Emacs assumes a fully case sensitive environment, so we
2772 need to change "Path" to "PATH" to match the expectations of
2773 various elisp packages. We do this by the sneaky method of
2774 modifying the string in the C runtime environ entry.
2776 The same applies to COMSPEC. */
2778 char ** envp;
2780 for (envp = environ; *envp; envp++)
2781 if (_strnicmp (*envp, "PATH=", 5) == 0)
2782 memcpy (*envp, "PATH=", 5);
2783 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
2784 memcpy (*envp, "COMSPEC=", 8);
2787 /* Remember the initial working directory for getcwd. */
2788 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2789 Does it matter anywhere in Emacs? */
2790 if (w32_unicode_filenames)
2792 wchar_t wstartup_dir[MAX_PATH];
2794 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2795 emacs_abort ();
2796 filename_from_utf16 (wstartup_dir, startup_dir);
2798 else
2800 char astartup_dir[MAX_PATH];
2802 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2803 emacs_abort ();
2804 filename_from_ansi (astartup_dir, startup_dir);
2808 static char modname[MAX_PATH];
2810 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2811 emacs_abort ();
2812 argv[0] = modname;
2815 /* Determine if there is a middle mouse button, to allow parse_button
2816 to decide whether right mouse events should be mouse-2 or
2817 mouse-3. */
2818 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2820 init_user_info ();
2823 /* Called from expand-file-name when default-directory is not a string. */
2825 char *
2826 emacs_root_dir (void)
2828 static char root_dir[MAX_UTF8_PATH];
2829 const char *p;
2831 p = getenv ("emacs_dir");
2832 if (p == NULL)
2833 emacs_abort ();
2834 filename_from_ansi (p, root_dir);
2835 root_dir[parse_root (root_dir, NULL)] = '\0';
2836 dostounix_filename (root_dir);
2837 return root_dir;
2840 #include <sys/timeb.h>
2842 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2844 gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
2846 struct _timeb tb;
2847 _ftime (&tb);
2849 tv->tv_sec = tb.time;
2850 tv->tv_usec = tb.millitm * 1000L;
2851 /* Implementation note: _ftime sometimes doesn't update the dstflag
2852 according to the new timezone when the system timezone is
2853 changed. We could fix that by using GetSystemTime and
2854 GetTimeZoneInformation, but that doesn't seem necessary, since
2855 Emacs always calls gettimeofday with the 2nd argument NULL (see
2856 current_emacs_time). */
2857 if (tz)
2859 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2860 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2862 return 0;
2865 /* Emulate fdutimens. */
2867 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2868 TIMESPEC[0] and TIMESPEC[1], respectively.
2869 FD must be either negative -- in which case it is ignored --
2870 or a file descriptor that is open on FILE.
2871 If FD is nonnegative, then FILE can be NULL, which means
2872 use just futimes instead of utimes.
2873 If TIMESPEC is null, FAIL.
2874 Return 0 on success, -1 (setting errno) on failure. */
2877 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2879 if (!timespec)
2881 errno = ENOSYS;
2882 return -1;
2884 if (fd < 0 && !file)
2886 errno = EBADF;
2887 return -1;
2889 /* _futime's prototype defines 2nd arg as having the type 'struct
2890 _utimbuf', while utime needs to accept 'struct utimbuf' for
2891 compatibility with Posix. So we need to use 2 different (but
2892 equivalent) types to avoid compiler warnings, sigh. */
2893 if (fd >= 0)
2895 struct _utimbuf _ut;
2897 _ut.actime = timespec[0].tv_sec;
2898 _ut.modtime = timespec[1].tv_sec;
2899 return _futime (fd, &_ut);
2901 else
2903 struct utimbuf ut;
2905 ut.actime = timespec[0].tv_sec;
2906 ut.modtime = timespec[1].tv_sec;
2907 /* Call 'utime', which is implemented below, not the MS library
2908 function, which fails on directories. */
2909 return utime (file, &ut);
2914 /* ------------------------------------------------------------------------- */
2915 /* IO support and wrapper functions for the Windows API. */
2916 /* ------------------------------------------------------------------------- */
2918 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2919 on network directories, so we handle that case here.
2920 (Ulrich Leodolter, 1/11/95). */
2921 char *
2922 sys_ctime (const time_t *t)
2924 char *str = (char *) ctime (t);
2925 return (str ? str : "Sun Jan 01 00:00:00 1970");
2928 /* Emulate sleep...we could have done this with a define, but that
2929 would necessitate including windows.h in the files that used it.
2930 This is much easier. */
2931 void
2932 sys_sleep (int seconds)
2934 Sleep (seconds * 1000);
2937 /* Internal MSVC functions for low-level descriptor munging */
2938 extern int __cdecl _set_osfhnd (int fd, long h);
2939 extern int __cdecl _free_osfhnd (int fd);
2941 /* parallel array of private info on file handles */
2942 filedesc fd_info [ MAXDESC ];
2944 typedef struct volume_info_data {
2945 struct volume_info_data * next;
2947 /* time when info was obtained */
2948 DWORD timestamp;
2950 /* actual volume info */
2951 char * root_dir;
2952 DWORD serialnum;
2953 DWORD maxcomp;
2954 DWORD flags;
2955 char * name;
2956 char * type;
2957 } volume_info_data;
2959 /* Global referenced by various functions. */
2960 static volume_info_data volume_info;
2962 /* Vector to indicate which drives are local and fixed (for which cached
2963 data never expires). */
2964 static BOOL fixed_drives[26];
2966 /* Consider cached volume information to be stale if older than 10s,
2967 at least for non-local drives. Info for fixed drives is never stale. */
2968 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2969 #define VOLINFO_STILL_VALID( root_dir, info ) \
2970 ( ( isalpha (root_dir[0]) && \
2971 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2972 || GetTickCount () - info->timestamp < 10000 )
2974 /* Cache support functions. */
2976 /* Simple linked list with linear search is sufficient. */
2977 static volume_info_data *volume_cache = NULL;
2979 static volume_info_data *
2980 lookup_volume_info (char * root_dir)
2982 volume_info_data * info;
2984 for (info = volume_cache; info; info = info->next)
2985 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2986 break;
2987 return info;
2990 static void
2991 add_volume_info (char * root_dir, volume_info_data * info)
2993 info->root_dir = xstrdup (root_dir);
2994 unixtodos_filename (info->root_dir);
2995 info->next = volume_cache;
2996 volume_cache = info;
3000 /* Wrapper for GetVolumeInformation, which uses caching to avoid
3001 performance penalty (~2ms on 486 for local drives, 7.5ms for local
3002 cdrom drive, ~5-10ms or more for remote drives on LAN). */
3003 static volume_info_data *
3004 GetCachedVolumeInformation (char * root_dir)
3006 volume_info_data * info;
3007 char default_root[ MAX_UTF8_PATH ];
3008 char name[MAX_PATH+1];
3009 char type[MAX_PATH+1];
3011 /* NULL for root_dir means use root from current directory. */
3012 if (root_dir == NULL)
3014 if (w32_unicode_filenames)
3016 wchar_t curdirw[MAX_PATH];
3018 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
3019 return NULL;
3020 filename_from_utf16 (curdirw, default_root);
3022 else
3024 char curdira[MAX_PATH];
3026 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
3027 return NULL;
3028 filename_from_ansi (curdira, default_root);
3030 parse_root (default_root, (const char **)&root_dir);
3031 *root_dir = 0;
3032 root_dir = default_root;
3035 /* Local fixed drives can be cached permanently. Removable drives
3036 cannot be cached permanently, since the volume name and serial
3037 number (if nothing else) can change. Remote drives should be
3038 treated as if they are removable, since there is no sure way to
3039 tell whether they are or not. Also, the UNC association of drive
3040 letters mapped to remote volumes can be changed at any time (even
3041 by other processes) without notice.
3043 As a compromise, so we can benefit from caching info for remote
3044 volumes, we use a simple expiry mechanism to invalidate cache
3045 entries that are more than ten seconds old. */
3047 #if 0
3048 /* No point doing this, because WNetGetConnection is even slower than
3049 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
3050 GetDriveType is about the only call of this type which does not
3051 involve network access, and so is extremely quick). */
3053 /* Map drive letter to UNC if remote. */
3054 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
3056 char remote_name[ 256 ];
3057 char drive[3] = { root_dir[0], ':' };
3059 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
3060 == NO_ERROR)
3061 /* do something */ ;
3063 #endif
3065 info = lookup_volume_info (root_dir);
3067 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
3069 DWORD serialnum;
3070 DWORD maxcomp;
3071 DWORD flags;
3073 /* Info is not cached, or is stale. */
3074 if (w32_unicode_filenames)
3076 wchar_t root_w[MAX_PATH];
3077 wchar_t name_w[MAX_PATH+1];
3078 wchar_t type_w[MAX_PATH+1];
3080 filename_to_utf16 (root_dir, root_w);
3081 if (!GetVolumeInformationW (root_w,
3082 name_w, sizeof (name_w),
3083 &serialnum,
3084 &maxcomp,
3085 &flags,
3086 type_w, sizeof (type_w)))
3087 return NULL;
3088 /* Hmm... not really 100% correct, as these 2 are not file
3089 names... */
3090 filename_from_utf16 (name_w, name);
3091 filename_from_utf16 (type_w, type);
3093 else
3095 char root_a[MAX_PATH];
3096 char name_a[MAX_PATH+1];
3097 char type_a[MAX_PATH+1];
3099 filename_to_ansi (root_dir, root_a);
3100 if (!GetVolumeInformationA (root_a,
3101 name_a, sizeof (name_a),
3102 &serialnum,
3103 &maxcomp,
3104 &flags,
3105 type_a, sizeof (type_a)))
3106 return NULL;
3107 filename_from_ansi (name_a, name);
3108 filename_from_ansi (type_a, type);
3111 /* Cache the volume information for future use, overwriting existing
3112 entry if present. */
3113 if (info == NULL)
3115 info = xmalloc (sizeof (volume_info_data));
3116 add_volume_info (root_dir, info);
3118 else
3120 xfree (info->name);
3121 xfree (info->type);
3124 info->name = xstrdup (name);
3125 unixtodos_filename (info->name);
3126 info->serialnum = serialnum;
3127 info->maxcomp = maxcomp;
3128 info->flags = flags;
3129 info->type = xstrdup (type);
3130 info->timestamp = GetTickCount ();
3133 return info;
3136 /* Get information on the volume where NAME is held; set path pointer to
3137 start of pathname in NAME (past UNC header\volume header if present),
3138 if pPath is non-NULL.
3140 Note: if NAME includes symlinks, the information is for the volume
3141 of the symlink, not of its target. That's because, even though
3142 GetVolumeInformation returns information about the symlink target
3143 of its argument, we only pass the root directory to
3144 GetVolumeInformation, not the full NAME. */
3145 static int
3146 get_volume_info (const char * name, const char ** pPath)
3148 char temp[MAX_UTF8_PATH];
3149 char *rootname = NULL; /* default to current volume */
3150 volume_info_data * info;
3151 int root_len = parse_root (name, pPath);
3153 if (name == NULL)
3154 return FALSE;
3156 /* Copy the root name of the volume, if given. */
3157 if (root_len)
3159 strncpy (temp, name, root_len);
3160 temp[root_len] = '\0';
3161 unixtodos_filename (temp);
3162 rootname = temp;
3165 info = GetCachedVolumeInformation (rootname);
3166 if (info != NULL)
3168 /* Set global referenced by other functions. */
3169 volume_info = *info;
3170 return TRUE;
3172 return FALSE;
3175 /* Determine if volume is FAT format (ie. only supports short 8.3
3176 names); also set path pointer to start of pathname in name, if
3177 pPath is non-NULL. */
3178 static int
3179 is_fat_volume (const char * name, const char ** pPath)
3181 if (get_volume_info (name, pPath))
3182 return (volume_info.maxcomp == 12);
3183 return FALSE;
3186 /* Convert all slashes in a filename to backslashes, and map filename
3187 to a valid 8.3 name if necessary. The result is a pointer to a
3188 static buffer, so CAVEAT EMPTOR! */
3189 const char *
3190 map_w32_filename (const char * name, const char ** pPath)
3192 static char shortname[MAX_UTF8_PATH];
3193 char * str = shortname;
3194 char c;
3195 char * path;
3196 const char * save_name = name;
3198 if (strlen (name) >= sizeof (shortname))
3200 /* Return a filename which will cause callers to fail. */
3201 strcpy (shortname, "?");
3202 return shortname;
3205 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3207 register int left = 8; /* maximum number of chars in part */
3208 register int extn = 0; /* extension added? */
3209 register int dots = 2; /* maximum number of dots allowed */
3211 while (name < path)
3212 *str++ = *name++; /* skip past UNC header */
3214 while ((c = *name++))
3216 switch ( c )
3218 case ':':
3219 case '\\':
3220 case '/':
3221 *str++ = (c == ':' ? ':' : '\\');
3222 extn = 0; /* reset extension flags */
3223 dots = 2; /* max 2 dots */
3224 left = 8; /* max length 8 for main part */
3225 break;
3226 case '.':
3227 if ( dots )
3229 /* Convert path components of the form .xxx to _xxx,
3230 but leave . and .. as they are. This allows .emacs
3231 to be read as _emacs, for example. */
3233 if (! *name ||
3234 *name == '.' ||
3235 IS_DIRECTORY_SEP (*name))
3237 *str++ = '.';
3238 dots--;
3240 else
3242 *str++ = '_';
3243 left--;
3244 dots = 0;
3247 else if ( !extn )
3249 *str++ = '.';
3250 extn = 1; /* we've got an extension */
3251 left = 3; /* 3 chars in extension */
3253 else
3255 /* any embedded dots after the first are converted to _ */
3256 *str++ = '_';
3258 break;
3259 case '~':
3260 case '#': /* don't lose these, they're important */
3261 if ( ! left )
3262 str[-1] = c; /* replace last character of part */
3263 /* FALLTHRU */
3264 default:
3265 if ( left && 'A' <= c && c <= 'Z' )
3267 *str++ = tolower (c); /* map to lower case (looks nicer) */
3268 left--;
3269 dots = 0; /* started a path component */
3271 break;
3274 *str = '\0';
3276 else
3278 strcpy (shortname, name);
3279 unixtodos_filename (shortname);
3282 if (pPath)
3283 *pPath = shortname + (path - save_name);
3285 return shortname;
3288 static int
3289 is_exec (const char * name)
3291 char * p = strrchr (name, '.');
3292 return
3293 (p != NULL
3294 && (xstrcasecmp (p, ".exe") == 0 ||
3295 xstrcasecmp (p, ".com") == 0 ||
3296 xstrcasecmp (p, ".bat") == 0 ||
3297 xstrcasecmp (p, ".cmd") == 0));
3300 /* Emulate the Unix directory procedures opendir, closedir, and
3301 readdir. We rename them to sys_* names because some versions of
3302 MinGW startup code call opendir and readdir to glob wildcards, and
3303 the code that calls them doesn't grok UTF-8 encoded file names we
3304 produce in dirent->d_name[]. */
3306 struct dirent dir_static; /* simulated directory contents */
3307 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3308 static int dir_is_fat;
3309 static char dir_pathname[MAX_UTF8_PATH];
3310 static WIN32_FIND_DATAW dir_find_data_w;
3311 static WIN32_FIND_DATAA dir_find_data_a;
3312 #define DIR_FIND_DATA_W 1
3313 #define DIR_FIND_DATA_A 2
3314 static int last_dir_find_data = -1;
3316 /* Support shares on a network resource as subdirectories of a read-only
3317 root directory. */
3318 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3319 static HANDLE open_unc_volume (const char *);
3320 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3321 static void close_unc_volume (HANDLE);
3323 DIR *
3324 sys_opendir (const char *filename)
3326 DIR *dirp;
3328 /* Opening is done by FindFirstFile. However, a read is inherent to
3329 this operation, so we defer the open until read time. */
3331 if (dir_find_handle != INVALID_HANDLE_VALUE)
3332 return NULL;
3333 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3334 return NULL;
3336 /* Note: We don't support traversal of UNC volumes via symlinks.
3337 Doing so would mean punishing 99.99% of use cases by resolving
3338 all the possible symlinks in FILENAME, recursively. */
3339 if (is_unc_volume (filename))
3341 wnet_enum_handle = open_unc_volume (filename);
3342 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3343 return NULL;
3346 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3347 return NULL;
3349 dirp->dd_fd = 0;
3350 dirp->dd_loc = 0;
3351 dirp->dd_size = 0;
3353 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3354 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3355 /* Note: We don't support symlinks to file names on FAT volumes.
3356 Doing so would mean punishing 99.99% of use cases by resolving
3357 all the possible symlinks in FILENAME, recursively. */
3358 dir_is_fat = is_fat_volume (filename, NULL);
3360 return dirp;
3363 void
3364 sys_closedir (DIR *dirp)
3366 /* If we have a find-handle open, close it. */
3367 if (dir_find_handle != INVALID_HANDLE_VALUE)
3369 FindClose (dir_find_handle);
3370 dir_find_handle = INVALID_HANDLE_VALUE;
3372 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3374 close_unc_volume (wnet_enum_handle);
3375 wnet_enum_handle = INVALID_HANDLE_VALUE;
3377 xfree ((char *) dirp);
3380 struct dirent *
3381 sys_readdir (DIR *dirp)
3383 int downcase = !NILP (Vw32_downcase_file_names);
3385 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3387 if (!read_unc_volume (wnet_enum_handle,
3388 dir_find_data_w.cFileName,
3389 dir_find_data_a.cFileName,
3390 MAX_PATH))
3391 return NULL;
3393 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3394 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3396 char filename[MAX_UTF8_PATH + 2];
3397 int ln;
3399 strcpy (filename, dir_pathname);
3400 ln = strlen (filename) - 1;
3401 if (!IS_DIRECTORY_SEP (filename[ln]))
3402 strcat (filename, "\\");
3403 strcat (filename, "*");
3405 /* Note: No need to resolve symlinks in FILENAME, because
3406 FindFirst opens the directory that is the target of a
3407 symlink. */
3408 if (w32_unicode_filenames)
3410 wchar_t fnw[MAX_PATH];
3412 filename_to_utf16 (filename, fnw);
3413 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3415 else
3417 char fna[MAX_PATH];
3419 filename_to_ansi (filename, fna);
3420 /* If FILENAME is not representable by the current ANSI
3421 codepage, we don't want FindFirstFileA to interpret the
3422 '?' characters as a wildcard. */
3423 if (_mbspbrk (fna, "?"))
3424 dir_find_handle = INVALID_HANDLE_VALUE;
3425 else
3426 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3429 if (dir_find_handle == INVALID_HANDLE_VALUE)
3430 return NULL;
3432 else if (w32_unicode_filenames)
3434 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3435 return NULL;
3437 else
3439 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3440 return NULL;
3443 /* Emacs never uses this value, so don't bother making it match
3444 value returned by stat(). */
3445 dir_static.d_ino = 1;
3447 if (w32_unicode_filenames)
3449 if (downcase || dir_is_fat)
3451 wchar_t tem[MAX_PATH];
3453 wcscpy (tem, dir_find_data_w.cFileName);
3454 CharLowerW (tem);
3455 filename_from_utf16 (tem, dir_static.d_name);
3457 else
3458 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3459 last_dir_find_data = DIR_FIND_DATA_W;
3461 else
3463 char tem[MAX_PATH];
3465 /* If the file name in cFileName[] includes `?' characters, it
3466 means the original file name used characters that cannot be
3467 represented by the current ANSI codepage. To avoid total
3468 lossage, retrieve the short 8+3 alias of the long file
3469 name. */
3470 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3472 strcpy (tem, dir_find_data_a.cAlternateFileName);
3473 /* 8+3 aliases are returned in all caps, which could break
3474 various alists that look at filenames' extensions. */
3475 downcase = 1;
3477 else if (downcase || dir_is_fat)
3478 strcpy (tem, dir_find_data_a.cFileName);
3479 else
3480 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3481 if (downcase || dir_is_fat)
3483 _mbslwr (tem);
3484 filename_from_ansi (tem, dir_static.d_name);
3486 last_dir_find_data = DIR_FIND_DATA_A;
3489 dir_static.d_namlen = strlen (dir_static.d_name);
3490 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3491 dir_static.d_namlen - dir_static.d_namlen % 4;
3493 return &dir_static;
3496 static HANDLE
3497 open_unc_volume (const char *path)
3499 const char *fn = map_w32_filename (path, NULL);
3500 DWORD result;
3501 HANDLE henum;
3503 if (w32_unicode_filenames)
3505 NETRESOURCEW nrw;
3506 wchar_t fnw[MAX_PATH];
3508 nrw.dwScope = RESOURCE_GLOBALNET;
3509 nrw.dwType = RESOURCETYPE_DISK;
3510 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3511 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3512 nrw.lpLocalName = NULL;
3513 filename_to_utf16 (fn, fnw);
3514 nrw.lpRemoteName = fnw;
3515 nrw.lpComment = NULL;
3516 nrw.lpProvider = NULL;
3518 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3519 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3521 else
3523 NETRESOURCEA nra;
3524 char fna[MAX_PATH];
3526 nra.dwScope = RESOURCE_GLOBALNET;
3527 nra.dwType = RESOURCETYPE_DISK;
3528 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3529 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3530 nra.lpLocalName = NULL;
3531 filename_to_ansi (fn, fna);
3532 nra.lpRemoteName = fna;
3533 nra.lpComment = NULL;
3534 nra.lpProvider = NULL;
3536 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3537 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3539 if (result == NO_ERROR)
3540 return henum;
3541 else
3542 return INVALID_HANDLE_VALUE;
3545 static void *
3546 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3548 DWORD count;
3549 int result;
3550 char *buffer;
3551 DWORD bufsize = 512;
3552 void *retval;
3554 count = 1;
3555 if (w32_unicode_filenames)
3557 wchar_t *ptrw;
3559 bufsize *= 2;
3560 buffer = alloca (bufsize);
3561 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3562 if (result != NO_ERROR)
3563 return NULL;
3564 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3565 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3566 ptrw += 2;
3567 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3568 ptrw++;
3569 wcsncpy (fname_w, ptrw, size);
3570 retval = fname_w;
3572 else
3574 int dbcs_p = max_filename_mbslen () > 1;
3575 char *ptra;
3577 buffer = alloca (bufsize);
3578 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3579 if (result != NO_ERROR)
3580 return NULL;
3581 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3582 ptra += 2;
3583 if (!dbcs_p)
3584 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3585 else
3587 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3588 ptra = CharNextExA (file_name_codepage, ptra, 0);
3590 ptra++;
3591 strncpy (fname_a, ptra, size);
3592 retval = fname_a;
3595 return retval;
3598 static void
3599 close_unc_volume (HANDLE henum)
3601 if (henum != INVALID_HANDLE_VALUE)
3602 WNetCloseEnum (henum);
3605 static DWORD
3606 unc_volume_file_attributes (const char *path)
3608 HANDLE henum;
3609 DWORD attrs;
3611 henum = open_unc_volume (path);
3612 if (henum == INVALID_HANDLE_VALUE)
3613 return -1;
3615 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3617 close_unc_volume (henum);
3619 return attrs;
3622 /* Ensure a network connection is authenticated. */
3623 static void
3624 logon_network_drive (const char *path)
3626 char share[MAX_UTF8_PATH];
3627 int n_slashes;
3628 char drive[4];
3629 UINT drvtype;
3630 char *p;
3631 DWORD val;
3633 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3634 drvtype = DRIVE_REMOTE;
3635 else if (path[0] == '\0' || path[1] != ':')
3636 drvtype = GetDriveType (NULL);
3637 else
3639 drive[0] = path[0];
3640 drive[1] = ':';
3641 drive[2] = '\\';
3642 drive[3] = '\0';
3643 drvtype = GetDriveType (drive);
3646 /* Only logon to networked drives. */
3647 if (drvtype != DRIVE_REMOTE)
3648 return;
3650 n_slashes = 2;
3651 strncpy (share, path, MAX_UTF8_PATH);
3652 /* Truncate to just server and share name. */
3653 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3655 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3657 *p = '\0';
3658 break;
3662 if (w32_unicode_filenames)
3664 NETRESOURCEW resourcew;
3665 wchar_t share_w[MAX_PATH];
3667 resourcew.dwScope = RESOURCE_GLOBALNET;
3668 resourcew.dwType = RESOURCETYPE_DISK;
3669 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3670 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3671 resourcew.lpLocalName = NULL;
3672 filename_to_utf16 (share, share_w);
3673 resourcew.lpRemoteName = share_w;
3674 resourcew.lpProvider = NULL;
3676 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3678 else
3680 NETRESOURCEA resourcea;
3681 char share_a[MAX_PATH];
3683 resourcea.dwScope = RESOURCE_GLOBALNET;
3684 resourcea.dwType = RESOURCETYPE_DISK;
3685 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3686 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3687 resourcea.lpLocalName = NULL;
3688 filename_to_ansi (share, share_a);
3689 resourcea.lpRemoteName = share_a;
3690 resourcea.lpProvider = NULL;
3692 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3695 switch (val)
3697 case NO_ERROR:
3698 case ERROR_ALREADY_ASSIGNED:
3699 break;
3700 case ERROR_ACCESS_DENIED:
3701 case ERROR_LOGON_FAILURE:
3702 errno = EACCES;
3703 break;
3704 case ERROR_BUSY:
3705 errno = EAGAIN;
3706 break;
3707 case ERROR_BAD_NET_NAME:
3708 case ERROR_NO_NET_OR_BAD_PATH:
3709 case ERROR_NO_NETWORK:
3710 case ERROR_CANCELLED:
3711 default:
3712 errno = ENOENT;
3713 break;
3717 /* Emulate faccessat(2). */
3719 faccessat (int dirfd, const char * path, int mode, int flags)
3721 DWORD attributes;
3723 if (dirfd != AT_FDCWD
3724 && !(IS_DIRECTORY_SEP (path[0])
3725 || IS_DEVICE_SEP (path[1])))
3727 errno = EBADF;
3728 return -1;
3731 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3732 newer versions blow up when passed D_OK. */
3733 path = map_w32_filename (path, NULL);
3734 /* If the last element of PATH is a symlink, we need to resolve it
3735 to get the attributes of its target file. Note: any symlinks in
3736 PATH elements other than the last one are transparently resolved
3737 by GetFileAttributes below. */
3738 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3739 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3740 path = chase_symlinks (path);
3742 if (w32_unicode_filenames)
3744 wchar_t path_w[MAX_PATH];
3746 filename_to_utf16 (path, path_w);
3747 attributes = GetFileAttributesW (path_w);
3749 else
3751 char path_a[MAX_PATH];
3753 filename_to_ansi (path, path_a);
3754 attributes = GetFileAttributesA (path_a);
3757 if (attributes == -1)
3759 DWORD w32err = GetLastError ();
3761 switch (w32err)
3763 case ERROR_INVALID_NAME:
3764 case ERROR_BAD_PATHNAME:
3765 if (is_unc_volume (path))
3767 attributes = unc_volume_file_attributes (path);
3768 if (attributes == -1)
3770 errno = EACCES;
3771 return -1;
3773 break;
3775 /* FALLTHROUGH */
3776 case ERROR_FILE_NOT_FOUND:
3777 case ERROR_BAD_NETPATH:
3778 errno = ENOENT;
3779 break;
3780 default:
3781 errno = EACCES;
3782 break;
3784 return -1;
3786 if ((mode & X_OK) != 0
3787 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3789 errno = EACCES;
3790 return -1;
3792 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3794 errno = EACCES;
3795 return -1;
3797 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3799 errno = EACCES;
3800 return -1;
3802 return 0;
3805 /* A version of 'access' to be used locally with file names in
3806 locale-specific encoding. Does not resolve symlinks and does not
3807 support file names on FAT12 and FAT16 volumes, but that's OK, since
3808 we only invoke this function for files inside the Emacs source or
3809 installation tree, on directories (so any symlinks should have the
3810 directory bit set), and on short file names such as "C:/.emacs". */
3811 static int
3812 sys_access (const char *fname, int mode)
3814 char fname_copy[MAX_PATH], *p;
3815 DWORD attributes;
3817 strcpy (fname_copy, fname);
3818 /* Do the equivalent of unixtodos_filename. */
3819 for (p = fname_copy; *p; p = CharNext (p))
3820 if (*p == '/')
3821 *p = '\\';
3823 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
3825 DWORD w32err = GetLastError ();
3827 switch (w32err)
3829 case ERROR_INVALID_NAME:
3830 case ERROR_BAD_PATHNAME:
3831 case ERROR_FILE_NOT_FOUND:
3832 case ERROR_BAD_NETPATH:
3833 errno = ENOENT;
3834 break;
3835 default:
3836 errno = EACCES;
3837 break;
3839 return -1;
3841 if ((mode & X_OK) != 0
3842 && !(is_exec (fname_copy)
3843 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3845 errno = EACCES;
3846 return -1;
3848 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3850 errno = EACCES;
3851 return -1;
3853 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3855 errno = EACCES;
3856 return -1;
3858 return 0;
3861 /* Shadow some MSVC runtime functions to map requests for long filenames
3862 to reasonable short names if necessary. This was originally added to
3863 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3864 long file names. */
3867 sys_chdir (const char * path)
3869 path = map_w32_filename (path, NULL);
3870 if (w32_unicode_filenames)
3872 wchar_t newdir_w[MAX_PATH];
3874 if (filename_to_utf16 (path, newdir_w) == 0)
3875 return _wchdir (newdir_w);
3876 return -1;
3878 else
3880 char newdir_a[MAX_PATH];
3882 if (filename_to_ansi (path, newdir_a) == 0)
3883 return _chdir (newdir_a);
3884 return -1;
3889 sys_chmod (const char * path, int mode)
3891 path = chase_symlinks (map_w32_filename (path, NULL));
3892 if (w32_unicode_filenames)
3894 wchar_t path_w[MAX_PATH];
3896 filename_to_utf16 (path, path_w);
3897 return _wchmod (path_w, mode);
3899 else
3901 char path_a[MAX_PATH];
3903 filename_to_ansi (path, path_a);
3904 return _chmod (path_a, mode);
3909 sys_creat (const char * path, int mode)
3911 path = map_w32_filename (path, NULL);
3912 if (w32_unicode_filenames)
3914 wchar_t path_w[MAX_PATH];
3916 filename_to_utf16 (path, path_w);
3917 return _wcreat (path_w, mode);
3919 else
3921 char path_a[MAX_PATH];
3923 filename_to_ansi (path, path_a);
3924 return _creat (path_a, mode);
3928 FILE *
3929 sys_fopen (const char * path, const char * mode)
3931 int fd;
3932 int oflag;
3933 const char * mode_save = mode;
3935 /* Force all file handles to be non-inheritable. This is necessary to
3936 ensure child processes don't unwittingly inherit handles that might
3937 prevent future file access. */
3939 if (mode[0] == 'r')
3940 oflag = O_RDONLY;
3941 else if (mode[0] == 'w' || mode[0] == 'a')
3942 oflag = O_WRONLY | O_CREAT | O_TRUNC;
3943 else
3944 return NULL;
3946 /* Only do simplistic option parsing. */
3947 while (*++mode)
3948 if (mode[0] == '+')
3950 oflag &= ~(O_RDONLY | O_WRONLY);
3951 oflag |= O_RDWR;
3953 else if (mode[0] == 'b')
3955 oflag &= ~O_TEXT;
3956 oflag |= O_BINARY;
3958 else if (mode[0] == 't')
3960 oflag &= ~O_BINARY;
3961 oflag |= O_TEXT;
3963 else break;
3965 path = map_w32_filename (path, NULL);
3966 if (w32_unicode_filenames)
3968 wchar_t path_w[MAX_PATH];
3970 filename_to_utf16 (path, path_w);
3971 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
3973 else
3975 char path_a[MAX_PATH];
3977 filename_to_ansi (path, path_a);
3978 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
3980 if (fd < 0)
3981 return NULL;
3983 return _fdopen (fd, mode_save);
3986 /* This only works on NTFS volumes, but is useful to have. */
3988 sys_link (const char * old, const char * new)
3990 HANDLE fileh;
3991 int result = -1;
3992 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
3993 wchar_t oldname_w[MAX_PATH];
3994 char oldname_a[MAX_PATH];
3996 if (old == NULL || new == NULL)
3998 errno = ENOENT;
3999 return -1;
4002 strcpy (oldname, map_w32_filename (old, NULL));
4003 strcpy (newname, map_w32_filename (new, NULL));
4005 if (w32_unicode_filenames)
4007 filename_to_utf16 (oldname, oldname_w);
4008 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
4009 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4011 else
4013 filename_to_ansi (oldname, oldname_a);
4014 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
4015 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4017 if (fileh != INVALID_HANDLE_VALUE)
4019 int wlen;
4021 /* Confusingly, the "alternate" stream name field does not apply
4022 when restoring a hard link, and instead contains the actual
4023 stream data for the link (ie. the name of the link to create).
4024 The WIN32_STREAM_ID structure before the cStreamName field is
4025 the stream header, which is then immediately followed by the
4026 stream data. */
4028 struct {
4029 WIN32_STREAM_ID wid;
4030 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
4031 } data;
4033 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
4034 indicates that flag is unsupported for CP_UTF8, and OTOH says
4035 it is the default anyway. */
4036 wlen = MultiByteToWideChar (CP_UTF8, 0, newname, -1,
4037 data.wid.cStreamName, MAX_PATH);
4038 if (wlen > 0)
4040 LPVOID context = NULL;
4041 DWORD wbytes = 0;
4043 data.wid.dwStreamId = BACKUP_LINK;
4044 data.wid.dwStreamAttributes = 0;
4045 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
4046 data.wid.Size.HighPart = 0;
4047 data.wid.dwStreamNameSize = 0;
4049 if (BackupWrite (fileh, (LPBYTE)&data,
4050 offsetof (WIN32_STREAM_ID, cStreamName)
4051 + data.wid.Size.LowPart,
4052 &wbytes, FALSE, FALSE, &context)
4053 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
4055 /* succeeded */
4056 result = 0;
4058 else
4060 DWORD err = GetLastError ();
4061 DWORD attributes;
4063 switch (err)
4065 case ERROR_ACCESS_DENIED:
4066 /* This is what happens when OLDNAME is a directory,
4067 since Windows doesn't support hard links to
4068 directories. Posix says to set errno to EPERM in
4069 that case. */
4070 if (w32_unicode_filenames)
4071 attributes = GetFileAttributesW (oldname_w);
4072 else
4073 attributes = GetFileAttributesA (oldname_a);
4074 if (attributes != -1
4075 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
4076 errno = EPERM;
4077 else if (attributes == -1
4078 && is_unc_volume (oldname)
4079 && unc_volume_file_attributes (oldname) != -1)
4080 errno = EPERM;
4081 else
4082 errno = EACCES;
4083 break;
4084 case ERROR_TOO_MANY_LINKS:
4085 errno = EMLINK;
4086 break;
4087 case ERROR_NOT_SAME_DEVICE:
4088 errno = EXDEV;
4089 break;
4090 default:
4091 errno = EINVAL;
4092 break;
4097 CloseHandle (fileh);
4099 else
4100 errno = ENOENT;
4102 return result;
4106 sys_mkdir (const char * path)
4108 path = map_w32_filename (path, NULL);
4110 if (w32_unicode_filenames)
4112 wchar_t path_w[MAX_PATH];
4114 filename_to_utf16 (path, path_w);
4115 return _wmkdir (path_w);
4117 else
4119 char path_a[MAX_PATH];
4121 filename_to_ansi (path, path_a);
4122 return _mkdir (path_a);
4127 sys_open (const char * path, int oflag, int mode)
4129 const char* mpath = map_w32_filename (path, NULL);
4130 int res = -1;
4132 if (w32_unicode_filenames)
4134 wchar_t mpath_w[MAX_PATH];
4136 filename_to_utf16 (mpath, mpath_w);
4137 /* If possible, try to open file without _O_CREAT, to be able to
4138 write to existing hidden and system files. Force all file
4139 handles to be non-inheritable. */
4140 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4141 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4142 if (res < 0)
4143 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4145 else
4147 char mpath_a[MAX_PATH];
4149 filename_to_ansi (mpath, mpath_a);
4150 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4151 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4152 if (res < 0)
4153 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4156 return res;
4159 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
4160 when using mktemp.
4162 Standard algorithm for generating a temporary file name seems to be
4163 use pid or tid with a letter on the front (in place of the 6 X's)
4164 and cycle through the letters to find a unique name. We extend
4165 that to allow any reasonable character as the first of the 6 X's,
4166 so that the number of simultaneously used temporary files will be
4167 greater. */
4170 mkostemp (char * template, int flags)
4172 char * p;
4173 int i, fd = -1;
4174 unsigned uid = GetCurrentThreadId ();
4175 int save_errno = errno;
4176 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
4178 errno = EINVAL;
4179 if (template == NULL)
4180 return -1;
4182 p = template + strlen (template);
4183 i = 5;
4184 /* replace up to the last 5 X's with uid in decimal */
4185 while (--p >= template && p[0] == 'X' && --i >= 0)
4187 p[0] = '0' + uid % 10;
4188 uid /= 10;
4191 if (i < 0 && p[0] == 'X')
4193 i = 0;
4196 p[0] = first_char[i];
4197 if ((fd = sys_open (template,
4198 flags | _O_CREAT | _O_EXCL | _O_RDWR,
4199 S_IRUSR | S_IWUSR)) >= 0
4200 || errno != EEXIST)
4202 if (fd >= 0)
4203 errno = save_errno;
4204 return fd;
4207 while (++i < sizeof (first_char));
4210 /* Template is badly formed or else we can't generate a unique name. */
4211 return -1;
4215 fchmod (int fd, mode_t mode)
4217 return 0;
4221 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4223 BOOL result;
4224 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4225 int newname_dev;
4226 int oldname_dev;
4227 bool have_temp_a = false;
4229 /* MoveFile on Windows 95 doesn't correctly change the short file name
4230 alias in a number of circumstances (it is not easy to predict when
4231 just by looking at oldname and newname, unfortunately). In these
4232 cases, renaming through a temporary name avoids the problem.
4234 A second problem on Windows 95 is that renaming through a temp name when
4235 newname is uppercase fails (the final long name ends up in
4236 lowercase, although the short alias might be uppercase) UNLESS the
4237 long temp name is not 8.3.
4239 So, on Windows 95 we always rename through a temp name, and we make sure
4240 the temp name has a long extension to ensure correct renaming. */
4242 strcpy (temp, map_w32_filename (oldname, NULL));
4244 /* volume_info is set indirectly by map_w32_filename. */
4245 oldname_dev = volume_info.serialnum;
4247 if (os_subtype == OS_9X)
4249 char * o;
4250 char * p;
4251 int i = 0;
4252 char oldname_a[MAX_PATH];
4254 oldname = map_w32_filename (oldname, NULL);
4255 filename_to_ansi (oldname, oldname_a);
4256 filename_to_ansi (temp, temp_a);
4257 if ((o = strrchr (oldname_a, '\\')))
4258 o++;
4259 else
4260 o = (char *) oldname_a;
4262 if ((p = strrchr (temp_a, '\\')))
4263 p++;
4264 else
4265 p = temp_a;
4269 /* Force temp name to require a manufactured 8.3 alias - this
4270 seems to make the second rename work properly. */
4271 sprintf (p, "_.%s.%u", o, i);
4272 i++;
4273 result = rename (oldname_a, temp_a);
4275 /* This loop must surely terminate! */
4276 while (result < 0 && errno == EEXIST);
4277 if (result < 0)
4278 return -1;
4279 have_temp_a = true;
4282 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4283 (at least if it is a file; don't do this for directories).
4285 Since we mustn't do this if we are just changing the case of the
4286 file name (we would end up deleting the file we are trying to
4287 rename!), we let rename detect if the destination file already
4288 exists - that way we avoid the possible pitfalls of trying to
4289 determine ourselves whether two names really refer to the same
4290 file, which is not always possible in the general case. (Consider
4291 all the permutations of shared or subst'd drives, etc.) */
4293 newname = map_w32_filename (newname, NULL);
4295 /* volume_info is set indirectly by map_w32_filename. */
4296 newname_dev = volume_info.serialnum;
4298 if (w32_unicode_filenames)
4300 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4302 filename_to_utf16 (temp, temp_w);
4303 filename_to_utf16 (newname, newname_w);
4304 result = _wrename (temp_w, newname_w);
4305 if (result < 0 && force)
4307 DWORD w32err = GetLastError ();
4309 if (errno == EACCES
4310 && newname_dev != oldname_dev)
4312 /* The implementation of `rename' on Windows does not return
4313 errno = EXDEV when you are moving a directory to a
4314 different storage device (ex. logical disk). It returns
4315 EACCES instead. So here we handle such situations and
4316 return EXDEV. */
4317 DWORD attributes;
4319 if ((attributes = GetFileAttributesW (temp_w)) != -1
4320 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4321 errno = EXDEV;
4323 else if (errno == EEXIST)
4325 if (_wchmod (newname_w, 0666) != 0)
4326 return result;
4327 if (_wunlink (newname_w) != 0)
4328 return result;
4329 result = _wrename (temp_w, newname_w);
4331 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4332 && is_symlink (temp))
4334 /* This is Windows prohibiting the user from creating a
4335 symlink in another place, since that requires
4336 privileges. */
4337 errno = EPERM;
4341 else
4343 char newname_a[MAX_PATH];
4345 if (!have_temp_a)
4346 filename_to_ansi (temp, temp_a);
4347 filename_to_ansi (newname, newname_a);
4348 result = rename (temp_a, newname_a);
4349 if (result < 0 && force)
4351 DWORD w32err = GetLastError ();
4353 if (errno == EACCES
4354 && newname_dev != oldname_dev)
4356 DWORD attributes;
4358 if ((attributes = GetFileAttributesA (temp_a)) != -1
4359 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4360 errno = EXDEV;
4362 else if (errno == EEXIST)
4364 if (_chmod (newname_a, 0666) != 0)
4365 return result;
4366 if (_unlink (newname_a) != 0)
4367 return result;
4368 result = rename (temp_a, newname_a);
4370 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4371 && is_symlink (temp))
4372 errno = EPERM;
4376 return result;
4380 sys_rename (char const *old, char const *new)
4382 return sys_rename_replace (old, new, TRUE);
4386 sys_rmdir (const char * path)
4388 path = map_w32_filename (path, NULL);
4390 if (w32_unicode_filenames)
4392 wchar_t path_w[MAX_PATH];
4394 filename_to_utf16 (path, path_w);
4395 return _wrmdir (path_w);
4397 else
4399 char path_a[MAX_PATH];
4401 filename_to_ansi (path, path_a);
4402 return _rmdir (path_a);
4407 sys_unlink (const char * path)
4409 path = map_w32_filename (path, NULL);
4411 if (w32_unicode_filenames)
4413 wchar_t path_w[MAX_PATH];
4415 filename_to_utf16 (path, path_w);
4416 /* On Unix, unlink works without write permission. */
4417 _wchmod (path_w, 0666);
4418 return _wunlink (path_w);
4420 else
4422 char path_a[MAX_PATH];
4424 filename_to_ansi (path, path_a);
4425 _chmod (path_a, 0666);
4426 return _unlink (path_a);
4430 static FILETIME utc_base_ft;
4431 static ULONGLONG utc_base; /* In 100ns units */
4432 static int init = 0;
4434 #define FILETIME_TO_U64(result, ft) \
4435 do { \
4436 ULARGE_INTEGER uiTemp; \
4437 uiTemp.LowPart = (ft).dwLowDateTime; \
4438 uiTemp.HighPart = (ft).dwHighDateTime; \
4439 result = uiTemp.QuadPart; \
4440 } while (0)
4442 static void
4443 initialize_utc_base (void)
4445 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4446 SYSTEMTIME st;
4448 st.wYear = 1970;
4449 st.wMonth = 1;
4450 st.wDay = 1;
4451 st.wHour = 0;
4452 st.wMinute = 0;
4453 st.wSecond = 0;
4454 st.wMilliseconds = 0;
4456 SystemTimeToFileTime (&st, &utc_base_ft);
4457 FILETIME_TO_U64 (utc_base, utc_base_ft);
4460 static time_t
4461 convert_time (FILETIME ft)
4463 ULONGLONG tmp;
4465 if (!init)
4467 initialize_utc_base ();
4468 init = 1;
4471 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4472 return 0;
4474 FILETIME_TO_U64 (tmp, ft);
4475 return (time_t) ((tmp - utc_base) / 10000000L);
4478 static void
4479 convert_from_time_t (time_t time, FILETIME * pft)
4481 ULARGE_INTEGER tmp;
4483 if (!init)
4485 initialize_utc_base ();
4486 init = 1;
4489 /* time in 100ns units since 1-Jan-1601 */
4490 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4491 pft->dwHighDateTime = tmp.HighPart;
4492 pft->dwLowDateTime = tmp.LowPart;
4495 static PSECURITY_DESCRIPTOR
4496 get_file_security_desc_by_handle (HANDLE h)
4498 PSECURITY_DESCRIPTOR psd = NULL;
4499 DWORD err;
4500 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4501 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4503 err = get_security_info (h, SE_FILE_OBJECT, si,
4504 NULL, NULL, NULL, NULL, &psd);
4505 if (err != ERROR_SUCCESS)
4506 return NULL;
4508 return psd;
4511 static PSECURITY_DESCRIPTOR
4512 get_file_security_desc_by_name (const char *fname)
4514 PSECURITY_DESCRIPTOR psd = NULL;
4515 DWORD sd_len, err;
4516 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4517 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4519 if (!get_file_security (fname, si, psd, 0, &sd_len))
4521 err = GetLastError ();
4522 if (err != ERROR_INSUFFICIENT_BUFFER)
4523 return NULL;
4526 psd = xmalloc (sd_len);
4527 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4529 xfree (psd);
4530 return NULL;
4533 return psd;
4536 static DWORD
4537 get_rid (PSID sid)
4539 unsigned n_subauthorities;
4541 /* Use the last sub-authority value of the RID, the relative
4542 portion of the SID, as user/group ID. */
4543 n_subauthorities = *get_sid_sub_authority_count (sid);
4544 if (n_subauthorities < 1)
4545 return 0; /* the "World" RID */
4546 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4549 /* Caching SID and account values for faster lokup. */
4551 struct w32_id {
4552 unsigned rid;
4553 struct w32_id *next;
4554 char name[GNLEN+1];
4555 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4558 static struct w32_id *w32_idlist;
4560 static int
4561 w32_cached_id (PSID sid, unsigned *id, char *name)
4563 struct w32_id *tail, *found;
4565 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4567 if (equal_sid ((PSID)tail->sid, sid))
4569 found = tail;
4570 break;
4573 if (found)
4575 *id = found->rid;
4576 strcpy (name, found->name);
4577 return 1;
4579 else
4580 return 0;
4583 static void
4584 w32_add_to_cache (PSID sid, unsigned id, char *name)
4586 DWORD sid_len;
4587 struct w32_id *new_entry;
4589 /* We don't want to leave behind stale cache from when Emacs was
4590 dumped. */
4591 if (initialized)
4593 sid_len = get_length_sid (sid);
4594 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4595 if (new_entry)
4597 new_entry->rid = id;
4598 strcpy (new_entry->name, name);
4599 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4600 new_entry->next = w32_idlist;
4601 w32_idlist = new_entry;
4606 #define UID 1
4607 #define GID 2
4609 static int
4610 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4612 PSID sid = NULL;
4613 BOOL dflt;
4614 SID_NAME_USE ignore;
4615 char name[UNLEN+1];
4616 DWORD name_len = sizeof (name);
4617 char domain[1024];
4618 DWORD domain_len = sizeof (domain);
4619 int use_dflt = 0;
4620 int result;
4622 if (what == UID)
4623 result = get_security_descriptor_owner (psd, &sid, &dflt);
4624 else if (what == GID)
4625 result = get_security_descriptor_group (psd, &sid, &dflt);
4626 else
4627 result = 0;
4629 if (!result || !is_valid_sid (sid))
4630 use_dflt = 1;
4631 else if (!w32_cached_id (sid, id, nm))
4633 if (!lookup_account_sid (NULL, sid, name, &name_len,
4634 domain, &domain_len, &ignore)
4635 || name_len > UNLEN+1)
4636 use_dflt = 1;
4637 else
4639 *id = get_rid (sid);
4640 strcpy (nm, name);
4641 w32_add_to_cache (sid, *id, name);
4644 return use_dflt;
4647 static void
4648 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4650 int dflt_usr = 0, dflt_grp = 0;
4652 if (!psd)
4654 dflt_usr = 1;
4655 dflt_grp = 1;
4657 else
4659 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4660 dflt_usr = 1;
4661 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4662 dflt_grp = 1;
4664 /* Consider files to belong to current user/group, if we cannot get
4665 more accurate information. */
4666 if (dflt_usr)
4668 st->st_uid = dflt_passwd.pw_uid;
4669 strcpy (st->st_uname, dflt_passwd.pw_name);
4671 if (dflt_grp)
4673 st->st_gid = dflt_passwd.pw_gid;
4674 strcpy (st->st_gname, dflt_group.gr_name);
4678 /* Return non-zero if NAME is a potentially slow filesystem. */
4680 is_slow_fs (const char *name)
4682 char drive_root[4];
4683 UINT devtype;
4685 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4686 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4687 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4688 devtype = GetDriveType (NULL); /* use root of current drive */
4689 else
4691 /* GetDriveType needs the root directory of the drive. */
4692 strncpy (drive_root, name, 2);
4693 drive_root[2] = '\\';
4694 drive_root[3] = '\0';
4695 devtype = GetDriveType (drive_root);
4697 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4700 /* If this is non-zero, the caller wants accurate information about
4701 file's owner and group, which could be expensive to get. dired.c
4702 uses this flag when needed for the job at hand. */
4703 int w32_stat_get_owner_group;
4705 /* MSVC stat function can't cope with UNC names and has other bugs, so
4706 replace it with our own. This also allows us to calculate consistent
4707 inode values and owner/group without hacks in the main Emacs code,
4708 and support file names encoded in UTF-8. */
4710 static int
4711 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4713 char *name, *save_name, *r;
4714 WIN32_FIND_DATAW wfd_w;
4715 WIN32_FIND_DATAA wfd_a;
4716 HANDLE fh;
4717 unsigned __int64 fake_inode = 0;
4718 int permission;
4719 int len;
4720 int rootdir = FALSE;
4721 PSECURITY_DESCRIPTOR psd = NULL;
4722 int is_a_symlink = 0;
4723 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4724 DWORD access_rights = 0;
4725 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4726 FILETIME ctime, atime, wtime;
4727 wchar_t name_w[MAX_PATH];
4728 char name_a[MAX_PATH];
4730 if (path == NULL || buf == NULL)
4732 errno = EFAULT;
4733 return -1;
4736 save_name = name = (char *) map_w32_filename (path, &path);
4737 /* Must be valid filename, no wild cards or other invalid
4738 characters. */
4739 if (strpbrk (name, "*?|<>\""))
4741 errno = ENOENT;
4742 return -1;
4745 /* Remove trailing directory separator, unless name is the root
4746 directory of a drive or UNC volume in which case ensure there
4747 is a trailing separator. */
4748 len = strlen (name);
4749 name = strcpy (alloca (len + 2), name);
4751 /* Avoid a somewhat costly call to is_symlink if the filesystem
4752 doesn't support symlinks. */
4753 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4754 is_a_symlink = is_symlink (name);
4756 /* Plan A: Open the file and get all the necessary information via
4757 the resulting handle. This solves several issues in one blow:
4759 . retrieves attributes for the target of a symlink, if needed
4760 . gets attributes of root directories and symlinks pointing to
4761 root directories, thus avoiding the need for special-casing
4762 these and detecting them by examining the file-name format
4763 . retrieves more accurate attributes (e.g., non-zero size for
4764 some directories, esp. directories that are junction points)
4765 . correctly resolves "c:/..", "/.." and similar file names
4766 . avoids run-time penalties for 99% of use cases
4768 Plan A is always tried first, unless the user asked not to (but
4769 if the file is a symlink and we need to follow links, we try Plan
4770 A even if the user asked not to).
4772 If Plan A fails, we go to Plan B (below), where various
4773 potentially expensive techniques must be used to handle "special"
4774 files such as UNC volumes etc. */
4775 if (!(NILP (Vw32_get_true_file_attributes)
4776 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
4777 /* Following symlinks requires getting the info by handle. */
4778 || (is_a_symlink && follow_symlinks))
4780 BY_HANDLE_FILE_INFORMATION info;
4782 if (is_a_symlink && !follow_symlinks)
4783 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
4784 /* READ_CONTROL access rights are required to get security info
4785 by handle. But if the OS doesn't support security in the
4786 first place, we don't need to try. */
4787 if (is_windows_9x () != TRUE)
4788 access_rights |= READ_CONTROL;
4790 if (w32_unicode_filenames)
4792 filename_to_utf16 (name, name_w);
4793 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
4794 file_flags, NULL);
4795 /* If CreateFile fails with READ_CONTROL, try again with
4796 zero as access rights. */
4797 if (fh == INVALID_HANDLE_VALUE && access_rights)
4798 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
4799 file_flags, NULL);
4801 else
4803 filename_to_ansi (name, name_a);
4804 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
4805 file_flags, NULL);
4806 if (fh == INVALID_HANDLE_VALUE && access_rights)
4807 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
4808 file_flags, NULL);
4810 if (fh == INVALID_HANDLE_VALUE)
4811 goto no_true_file_attributes;
4813 /* This is more accurate in terms of getting the correct number
4814 of links, but is quite slow (it is noticeable when Emacs is
4815 making a list of file name completions). */
4816 if (GetFileInformationByHandle (fh, &info))
4818 nlinks = info.nNumberOfLinks;
4819 /* Might as well use file index to fake inode values, but this
4820 is not guaranteed to be unique unless we keep a handle open
4821 all the time (even then there are situations where it is
4822 not unique). Reputedly, there are at most 48 bits of info
4823 (on NTFS, presumably less on FAT). */
4824 fake_inode = info.nFileIndexHigh;
4825 fake_inode <<= 32;
4826 fake_inode += info.nFileIndexLow;
4827 serialnum = info.dwVolumeSerialNumber;
4828 fs_high = info.nFileSizeHigh;
4829 fs_low = info.nFileSizeLow;
4830 ctime = info.ftCreationTime;
4831 atime = info.ftLastAccessTime;
4832 wtime = info.ftLastWriteTime;
4833 fattrs = info.dwFileAttributes;
4835 else
4837 /* We don't go to Plan B here, because it's not clear that
4838 it's a good idea. The only known use case where
4839 CreateFile succeeds, but GetFileInformationByHandle fails
4840 (with ERROR_INVALID_FUNCTION) is for character devices
4841 such as NUL, PRN, etc. For these, switching to Plan B is
4842 a net loss, because we lose the character device
4843 attribute returned by GetFileType below (FindFirstFile
4844 doesn't set that bit in the attributes), and the other
4845 fields don't make sense for character devices anyway.
4846 Emacs doesn't really care for non-file entities in the
4847 context of l?stat, so neither do we. */
4849 /* w32err is assigned so one could put a breakpoint here and
4850 examine its value, when GetFileInformationByHandle
4851 fails. */
4852 DWORD w32err = GetLastError ();
4854 switch (w32err)
4856 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
4857 errno = ENOENT;
4858 return -1;
4862 /* Test for a symlink before testing for a directory, since
4863 symlinks to directories have the directory bit set, but we
4864 don't want them to appear as directories. */
4865 if (is_a_symlink && !follow_symlinks)
4866 buf->st_mode = S_IFLNK;
4867 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4868 buf->st_mode = S_IFDIR;
4869 else
4871 DWORD ftype = GetFileType (fh);
4873 switch (ftype)
4875 case FILE_TYPE_DISK:
4876 buf->st_mode = S_IFREG;
4877 break;
4878 case FILE_TYPE_PIPE:
4879 buf->st_mode = S_IFIFO;
4880 break;
4881 case FILE_TYPE_CHAR:
4882 case FILE_TYPE_UNKNOWN:
4883 default:
4884 buf->st_mode = S_IFCHR;
4887 /* We produce the fallback owner and group data, based on the
4888 current user that runs Emacs, in the following cases:
4890 . caller didn't request owner and group info
4891 . this is Windows 9X
4892 . getting security by handle failed, and we need to produce
4893 information for the target of a symlink (this is better
4894 than producing a potentially misleading info about the
4895 symlink itself)
4897 If getting security by handle fails, and we don't need to
4898 resolve symlinks, we try getting security by name. */
4899 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4900 get_file_owner_and_group (NULL, buf);
4901 else
4903 psd = get_file_security_desc_by_handle (fh);
4904 if (psd)
4906 get_file_owner_and_group (psd, buf);
4907 LocalFree (psd);
4909 else if (!(is_a_symlink && follow_symlinks))
4911 psd = get_file_security_desc_by_name (name);
4912 get_file_owner_and_group (psd, buf);
4913 xfree (psd);
4915 else
4916 get_file_owner_and_group (NULL, buf);
4918 CloseHandle (fh);
4920 else
4922 no_true_file_attributes:
4923 /* Plan B: Either getting a handle on the file failed, or the
4924 caller explicitly asked us to not bother making this
4925 information more accurate.
4927 Implementation note: In Plan B, we never bother to resolve
4928 symlinks, even if we got here because we tried Plan A and
4929 failed. That's because, even if the caller asked for extra
4930 precision by setting Vw32_get_true_file_attributes to t,
4931 resolving symlinks requires acquiring a file handle to the
4932 symlink, which we already know will fail. And if the user
4933 did not ask for extra precision, resolving symlinks will fly
4934 in the face of that request, since the user then wants the
4935 lightweight version of the code. */
4936 rootdir = (path >= save_name + len - 1
4937 && (IS_DIRECTORY_SEP (*path) || *path == 0));
4939 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4940 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
4941 if (IS_DIRECTORY_SEP (r[0])
4942 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
4943 r[1] = r[2] = '\0';
4945 /* Note: If NAME is a symlink to the root of a UNC volume
4946 (i.e. "\\SERVER"), we will not detect that here, and we will
4947 return data about the symlink as result of FindFirst below.
4948 This is unfortunate, but that marginal use case does not
4949 justify a call to chase_symlinks which would impose a penalty
4950 on all the other use cases. (We get here for symlinks to
4951 roots of UNC volumes because CreateFile above fails for them,
4952 unlike with symlinks to root directories X:\ of drives.) */
4953 if (is_unc_volume (name))
4955 fattrs = unc_volume_file_attributes (name);
4956 if (fattrs == -1)
4957 return -1;
4959 ctime = atime = wtime = utc_base_ft;
4961 else if (rootdir)
4963 if (!IS_DIRECTORY_SEP (name[len-1]))
4964 strcat (name, "\\");
4965 if (GetDriveType (name) < 2)
4967 errno = ENOENT;
4968 return -1;
4971 fattrs = FILE_ATTRIBUTE_DIRECTORY;
4972 ctime = atime = wtime = utc_base_ft;
4974 else
4976 int have_wfd = -1;
4978 if (IS_DIRECTORY_SEP (name[len-1]))
4979 name[len - 1] = 0;
4981 /* (This is hacky, but helps when doing file completions on
4982 network drives.) Optimize by using information available from
4983 active readdir if possible. */
4984 len = strlen (dir_pathname);
4985 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
4986 len--;
4987 if (dir_find_handle != INVALID_HANDLE_VALUE
4988 && last_dir_find_data != -1
4989 && !(is_a_symlink && follow_symlinks)
4990 /* The 2 file-name comparisons below support only ASCII
4991 characters, and will lose (compare not equal) when
4992 the file names include non-ASCII characters that are
4993 the same but for the case. However, doing this
4994 properly involves: (a) converting both file names to
4995 UTF-16, (b) lower-casing both names using CharLowerW,
4996 and (c) comparing the results; this would be quite a
4997 bit slower, whereas Plan B is for users who want
4998 lightweight albeit inaccurate version of 'stat'. */
4999 && c_strncasecmp (save_name, dir_pathname, len) == 0
5000 && IS_DIRECTORY_SEP (name[len])
5001 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
5003 have_wfd = last_dir_find_data;
5004 /* This was the last entry returned by readdir. */
5005 if (last_dir_find_data == DIR_FIND_DATA_W)
5006 wfd_w = dir_find_data_w;
5007 else
5008 wfd_a = dir_find_data_a;
5010 else
5012 logon_network_drive (name);
5014 if (w32_unicode_filenames)
5016 filename_to_utf16 (name, name_w);
5017 fh = FindFirstFileW (name_w, &wfd_w);
5018 have_wfd = DIR_FIND_DATA_W;
5020 else
5022 filename_to_ansi (name, name_a);
5023 /* If NAME includes characters not representable by
5024 the current ANSI codepage, filename_to_ansi
5025 usually replaces them with a '?'. We don't want
5026 to let FindFirstFileA interpret those as wildcards,
5027 and "succeed", returning us data from some random
5028 file in the same directory. */
5029 if (_mbspbrk (name_a, "?"))
5030 fh = INVALID_HANDLE_VALUE;
5031 else
5032 fh = FindFirstFileA (name_a, &wfd_a);
5033 have_wfd = DIR_FIND_DATA_A;
5035 if (fh == INVALID_HANDLE_VALUE)
5037 errno = ENOENT;
5038 return -1;
5040 FindClose (fh);
5042 /* Note: if NAME is a symlink, the information we get from
5043 FindFirstFile is for the symlink, not its target. */
5044 if (have_wfd == DIR_FIND_DATA_W)
5046 fattrs = wfd_w.dwFileAttributes;
5047 ctime = wfd_w.ftCreationTime;
5048 atime = wfd_w.ftLastAccessTime;
5049 wtime = wfd_w.ftLastWriteTime;
5050 fs_high = wfd_w.nFileSizeHigh;
5051 fs_low = wfd_w.nFileSizeLow;
5053 else
5055 fattrs = wfd_a.dwFileAttributes;
5056 ctime = wfd_a.ftCreationTime;
5057 atime = wfd_a.ftLastAccessTime;
5058 wtime = wfd_a.ftLastWriteTime;
5059 fs_high = wfd_a.nFileSizeHigh;
5060 fs_low = wfd_a.nFileSizeLow;
5062 fake_inode = 0;
5063 nlinks = 1;
5064 serialnum = volume_info.serialnum;
5066 if (is_a_symlink && !follow_symlinks)
5067 buf->st_mode = S_IFLNK;
5068 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5069 buf->st_mode = S_IFDIR;
5070 else
5071 buf->st_mode = S_IFREG;
5073 get_file_owner_and_group (NULL, buf);
5076 buf->st_ino = fake_inode;
5078 buf->st_dev = serialnum;
5079 buf->st_rdev = serialnum;
5081 buf->st_size = fs_high;
5082 buf->st_size <<= 32;
5083 buf->st_size += fs_low;
5084 buf->st_nlink = nlinks;
5086 /* Convert timestamps to Unix format. */
5087 buf->st_mtime = convert_time (wtime);
5088 buf->st_atime = convert_time (atime);
5089 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5090 buf->st_ctime = convert_time (ctime);
5091 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5093 /* determine rwx permissions */
5094 if (is_a_symlink && !follow_symlinks)
5095 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5096 else
5098 if (fattrs & FILE_ATTRIBUTE_READONLY)
5099 permission = S_IREAD;
5100 else
5101 permission = S_IREAD | S_IWRITE;
5103 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5104 permission |= S_IEXEC;
5105 else if (is_exec (name))
5106 permission |= S_IEXEC;
5109 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5111 return 0;
5115 stat (const char * path, struct stat * buf)
5117 return stat_worker (path, buf, 1);
5121 lstat (const char * path, struct stat * buf)
5123 return stat_worker (path, buf, 0);
5127 fstatat (int fd, char const *name, struct stat *st, int flags)
5129 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5130 This is good enough for the current usage in Emacs, but is fragile.
5132 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5133 Gnulib does this and can serve as a model. */
5134 char fullname[MAX_UTF8_PATH];
5136 if (fd != AT_FDCWD)
5138 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5139 < 0)
5141 errno = ENAMETOOLONG;
5142 return -1;
5144 name = fullname;
5147 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5150 /* Provide fstat and utime as well as stat for consistent handling of
5151 file timestamps. */
5153 fstat (int desc, struct stat * buf)
5155 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5156 BY_HANDLE_FILE_INFORMATION info;
5157 unsigned __int64 fake_inode;
5158 int permission;
5160 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5162 case FILE_TYPE_DISK:
5163 buf->st_mode = S_IFREG;
5164 if (!GetFileInformationByHandle (fh, &info))
5166 errno = EACCES;
5167 return -1;
5169 break;
5170 case FILE_TYPE_PIPE:
5171 buf->st_mode = S_IFIFO;
5172 goto non_disk;
5173 case FILE_TYPE_CHAR:
5174 case FILE_TYPE_UNKNOWN:
5175 default:
5176 buf->st_mode = S_IFCHR;
5177 non_disk:
5178 memset (&info, 0, sizeof (info));
5179 info.dwFileAttributes = 0;
5180 info.ftCreationTime = utc_base_ft;
5181 info.ftLastAccessTime = utc_base_ft;
5182 info.ftLastWriteTime = utc_base_ft;
5185 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5186 buf->st_mode = S_IFDIR;
5188 buf->st_nlink = info.nNumberOfLinks;
5189 /* Might as well use file index to fake inode values, but this
5190 is not guaranteed to be unique unless we keep a handle open
5191 all the time (even then there are situations where it is
5192 not unique). Reputedly, there are at most 48 bits of info
5193 (on NTFS, presumably less on FAT). */
5194 fake_inode = info.nFileIndexHigh;
5195 fake_inode <<= 32;
5196 fake_inode += info.nFileIndexLow;
5198 /* MSVC defines _ino_t to be short; other libc's might not. */
5199 if (sizeof (buf->st_ino) == 2)
5200 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5201 else
5202 buf->st_ino = fake_inode;
5204 /* If the caller so requested, get the true file owner and group.
5205 Otherwise, consider the file to belong to the current user. */
5206 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5207 get_file_owner_and_group (NULL, buf);
5208 else
5210 PSECURITY_DESCRIPTOR psd = NULL;
5212 psd = get_file_security_desc_by_handle (fh);
5213 if (psd)
5215 get_file_owner_and_group (psd, buf);
5216 LocalFree (psd);
5218 else
5219 get_file_owner_and_group (NULL, buf);
5222 buf->st_dev = info.dwVolumeSerialNumber;
5223 buf->st_rdev = info.dwVolumeSerialNumber;
5225 buf->st_size = info.nFileSizeHigh;
5226 buf->st_size <<= 32;
5227 buf->st_size += info.nFileSizeLow;
5229 /* Convert timestamps to Unix format. */
5230 buf->st_mtime = convert_time (info.ftLastWriteTime);
5231 buf->st_atime = convert_time (info.ftLastAccessTime);
5232 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5233 buf->st_ctime = convert_time (info.ftCreationTime);
5234 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5236 /* determine rwx permissions */
5237 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5238 permission = S_IREAD;
5239 else
5240 permission = S_IREAD | S_IWRITE;
5242 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5243 permission |= S_IEXEC;
5244 else
5246 #if 0 /* no way of knowing the filename */
5247 char * p = strrchr (name, '.');
5248 if (p != NULL &&
5249 (xstrcasecmp (p, ".exe") == 0 ||
5250 xstrcasecmp (p, ".com") == 0 ||
5251 xstrcasecmp (p, ".bat") == 0 ||
5252 xstrcasecmp (p, ".cmd") == 0))
5253 permission |= S_IEXEC;
5254 #endif
5257 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5259 return 0;
5262 /* A version of 'utime' which handles directories as well as
5263 files. */
5266 utime (const char *name, struct utimbuf *times)
5268 struct utimbuf deftime;
5269 HANDLE fh;
5270 FILETIME mtime;
5271 FILETIME atime;
5273 if (times == NULL)
5275 deftime.modtime = deftime.actime = time (NULL);
5276 times = &deftime;
5279 if (w32_unicode_filenames)
5281 wchar_t name_utf16[MAX_PATH];
5283 if (filename_to_utf16 (name, name_utf16) != 0)
5284 return -1; /* errno set by filename_to_utf16 */
5286 /* Need write access to set times. */
5287 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5288 /* If NAME specifies a directory, FILE_SHARE_DELETE
5289 allows other processes to delete files inside it,
5290 while we have the directory open. */
5291 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5292 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5294 else
5296 char name_ansi[MAX_PATH];
5298 if (filename_to_ansi (name, name_ansi) != 0)
5299 return -1; /* errno set by filename_to_ansi */
5301 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5302 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5303 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5305 if (fh != INVALID_HANDLE_VALUE)
5307 convert_from_time_t (times->actime, &atime);
5308 convert_from_time_t (times->modtime, &mtime);
5309 if (!SetFileTime (fh, NULL, &atime, &mtime))
5311 CloseHandle (fh);
5312 errno = EACCES;
5313 return -1;
5315 CloseHandle (fh);
5317 else
5319 DWORD err = GetLastError ();
5321 switch (err)
5323 case ERROR_FILE_NOT_FOUND:
5324 case ERROR_PATH_NOT_FOUND:
5325 case ERROR_INVALID_DRIVE:
5326 case ERROR_BAD_NETPATH:
5327 case ERROR_DEV_NOT_EXIST:
5328 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5329 file name includes ?s, i.e. translation to ANSI failed. */
5330 case ERROR_INVALID_NAME:
5331 errno = ENOENT;
5332 break;
5333 case ERROR_TOO_MANY_OPEN_FILES:
5334 errno = ENFILE;
5335 break;
5336 case ERROR_ACCESS_DENIED:
5337 case ERROR_SHARING_VIOLATION:
5338 errno = EACCES;
5339 break;
5340 default:
5341 errno = EINVAL;
5342 break;
5344 return -1;
5346 return 0;
5349 /* Emacs expects us to support the traditional octal form of the mode
5350 bits, which is not what msvcrt.dll wants. */
5352 #define WRITE_USER 00200
5355 sys_umask (int mode)
5357 static int current_mask;
5358 int retval, arg = 0;
5360 /* The only bit we really support is the write bit. Files are
5361 always readable on MS-Windows, and the execute bit does not exist
5362 at all. */
5363 /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
5364 to prevent access by other users on NTFS. */
5365 if ((mode & WRITE_USER) != 0)
5366 arg |= S_IWRITE;
5368 retval = _umask (arg);
5369 /* Merge into the return value the bits they've set the last time,
5370 which msvcrt.dll ignores and never returns. Emacs insists on its
5371 notion of mask being identical to what we return. */
5372 retval |= (current_mask & ~WRITE_USER);
5373 current_mask = mode;
5375 return retval;
5379 /* Symlink-related functions. */
5380 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5381 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5382 #endif
5385 symlink (char const *filename, char const *linkname)
5387 char linkfn[MAX_UTF8_PATH], *tgtfn;
5388 DWORD flags = 0;
5389 int dir_access, filename_ends_in_slash;
5391 /* Diagnostics follows Posix as much as possible. */
5392 if (filename == NULL || linkname == NULL)
5394 errno = EFAULT;
5395 return -1;
5397 if (!*filename)
5399 errno = ENOENT;
5400 return -1;
5402 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5404 errno = ENAMETOOLONG;
5405 return -1;
5408 strcpy (linkfn, map_w32_filename (linkname, NULL));
5409 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5411 errno = EPERM;
5412 return -1;
5415 /* Note: since empty FILENAME was already rejected, we can safely
5416 refer to FILENAME[1]. */
5417 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5419 /* Non-absolute FILENAME is understood as being relative to
5420 LINKNAME's directory. We need to prepend that directory to
5421 FILENAME to get correct results from faccessat below, since
5422 otherwise it will interpret FILENAME relative to the
5423 directory where the Emacs process runs. Note that
5424 make-symbolic-link always makes sure LINKNAME is a fully
5425 expanded file name. */
5426 char tem[MAX_UTF8_PATH];
5427 char *p = linkfn + strlen (linkfn);
5429 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5430 p--;
5431 if (p > linkfn)
5432 strncpy (tem, linkfn, p - linkfn);
5433 tem[p - linkfn] = '\0';
5434 strcat (tem, filename);
5435 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5437 else
5438 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5440 /* Since Windows distinguishes between symlinks to directories and
5441 to files, we provide a kludgy feature: if FILENAME doesn't
5442 exist, but ends in a slash, we create a symlink to directory. If
5443 FILENAME exists and is a directory, we always create a symlink to
5444 directory. */
5445 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5446 if (dir_access == 0 || filename_ends_in_slash)
5447 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5449 tgtfn = (char *)map_w32_filename (filename, NULL);
5450 if (filename_ends_in_slash)
5451 tgtfn[strlen (tgtfn) - 1] = '\0';
5453 errno = 0;
5454 if (!create_symbolic_link (linkfn, tgtfn, flags))
5456 /* ENOSYS is set by create_symbolic_link, when it detects that
5457 the OS doesn't support the CreateSymbolicLink API. */
5458 if (errno != ENOSYS)
5460 DWORD w32err = GetLastError ();
5462 switch (w32err)
5464 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5465 TGTFN point to the same file name, go figure. */
5466 case ERROR_SUCCESS:
5467 case ERROR_FILE_EXISTS:
5468 errno = EEXIST;
5469 break;
5470 case ERROR_ACCESS_DENIED:
5471 errno = EACCES;
5472 break;
5473 case ERROR_FILE_NOT_FOUND:
5474 case ERROR_PATH_NOT_FOUND:
5475 case ERROR_BAD_NETPATH:
5476 case ERROR_INVALID_REPARSE_DATA:
5477 errno = ENOENT;
5478 break;
5479 case ERROR_DIRECTORY:
5480 errno = EISDIR;
5481 break;
5482 case ERROR_PRIVILEGE_NOT_HELD:
5483 case ERROR_NOT_ALL_ASSIGNED:
5484 errno = EPERM;
5485 break;
5486 case ERROR_DISK_FULL:
5487 errno = ENOSPC;
5488 break;
5489 default:
5490 errno = EINVAL;
5491 break;
5494 return -1;
5496 return 0;
5499 /* A quick inexpensive test of whether FILENAME identifies a file that
5500 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5501 must already be in the normalized form returned by
5502 map_w32_filename.
5504 Note: for repeated operations on many files, it is best to test
5505 whether the underlying volume actually supports symlinks, by
5506 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5507 avoid the call to this function if it doesn't. That's because the
5508 call to GetFileAttributes takes a non-negligible time, especially
5509 on non-local or removable filesystems. See stat_worker for an
5510 example of how to do that. */
5511 static int
5512 is_symlink (const char *filename)
5514 DWORD attrs;
5515 wchar_t filename_w[MAX_PATH];
5516 char filename_a[MAX_PATH];
5517 WIN32_FIND_DATAW wfdw;
5518 WIN32_FIND_DATAA wfda;
5519 HANDLE fh;
5520 int attrs_mean_symlink;
5522 if (w32_unicode_filenames)
5524 filename_to_utf16 (filename, filename_w);
5525 attrs = GetFileAttributesW (filename_w);
5527 else
5529 filename_to_ansi (filename, filename_a);
5530 attrs = GetFileAttributesA (filename_a);
5532 if (attrs == -1)
5534 DWORD w32err = GetLastError ();
5536 switch (w32err)
5538 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5539 break;
5540 case ERROR_ACCESS_DENIED:
5541 errno = EACCES;
5542 break;
5543 case ERROR_FILE_NOT_FOUND:
5544 case ERROR_PATH_NOT_FOUND:
5545 default:
5546 errno = ENOENT;
5547 break;
5549 return 0;
5551 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5552 return 0;
5553 logon_network_drive (filename);
5554 if (w32_unicode_filenames)
5556 fh = FindFirstFileW (filename_w, &wfdw);
5557 attrs_mean_symlink =
5558 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5559 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5561 else if (_mbspbrk (filename_a, "?"))
5563 /* filename_to_ansi failed to convert the file name. */
5564 errno = ENOENT;
5565 return 0;
5567 else
5569 fh = FindFirstFileA (filename_a, &wfda);
5570 attrs_mean_symlink =
5571 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5572 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5574 if (fh == INVALID_HANDLE_VALUE)
5575 return 0;
5576 FindClose (fh);
5577 return attrs_mean_symlink;
5580 /* If NAME identifies a symbolic link, copy into BUF the file name of
5581 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5582 null-terminate the target name, even if it fits. Return the number
5583 of bytes copied, or -1 if NAME is not a symlink or any error was
5584 encountered while resolving it. The file name copied into BUF is
5585 encoded in the current ANSI codepage. */
5586 ssize_t
5587 readlink (const char *name, char *buf, size_t buf_size)
5589 const char *path;
5590 TOKEN_PRIVILEGES privs;
5591 int restore_privs = 0;
5592 HANDLE sh;
5593 ssize_t retval;
5594 char resolved[MAX_UTF8_PATH];
5596 if (name == NULL)
5598 errno = EFAULT;
5599 return -1;
5601 if (!*name)
5603 errno = ENOENT;
5604 return -1;
5607 path = map_w32_filename (name, NULL);
5609 if (strlen (path) > MAX_UTF8_PATH)
5611 errno = ENAMETOOLONG;
5612 return -1;
5615 errno = 0;
5616 if (is_windows_9x () == TRUE
5617 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5618 || !is_symlink (path))
5620 if (!errno)
5621 errno = EINVAL; /* not a symlink */
5622 return -1;
5625 /* Done with simple tests, now we're in for some _real_ work. */
5626 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5627 restore_privs = 1;
5628 /* Implementation note: From here and onward, don't return early,
5629 since that will fail to restore the original set of privileges of
5630 the calling thread. */
5632 retval = -1; /* not too optimistic, are we? */
5634 /* Note: In the next call to CreateFile, we use zero as the 2nd
5635 argument because, when the symlink is a hidden/system file,
5636 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5637 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5638 and directory symlinks. */
5639 if (w32_unicode_filenames)
5641 wchar_t path_w[MAX_PATH];
5643 filename_to_utf16 (path, path_w);
5644 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5645 FILE_FLAG_OPEN_REPARSE_POINT
5646 | FILE_FLAG_BACKUP_SEMANTICS,
5647 NULL);
5649 else
5651 char path_a[MAX_PATH];
5653 filename_to_ansi (path, path_a);
5654 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5655 FILE_FLAG_OPEN_REPARSE_POINT
5656 | FILE_FLAG_BACKUP_SEMANTICS,
5657 NULL);
5659 if (sh != INVALID_HANDLE_VALUE)
5661 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5662 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5663 DWORD retbytes;
5665 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5666 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5667 &retbytes, NULL))
5668 errno = EIO;
5669 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5670 errno = EINVAL;
5671 else
5673 /* Copy the link target name, in wide characters, from
5674 reparse_data, then convert it to multibyte encoding in
5675 the current locale's codepage. */
5676 WCHAR *lwname;
5677 size_t lname_size;
5678 USHORT lwname_len =
5679 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5680 WCHAR *lwname_src =
5681 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5682 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5683 size_t size_to_copy = buf_size;
5685 /* According to MSDN, PrintNameLength does not include the
5686 terminating null character. */
5687 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5688 memcpy (lwname, lwname_src, lwname_len);
5689 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5690 filename_from_utf16 (lwname, resolved);
5691 dostounix_filename (resolved);
5692 lname_size = strlen (resolved) + 1;
5693 if (lname_size <= buf_size)
5694 size_to_copy = lname_size;
5695 strncpy (buf, resolved, size_to_copy);
5696 /* Success! */
5697 retval = size_to_copy;
5699 CloseHandle (sh);
5701 else
5703 /* CreateFile failed. */
5704 DWORD w32err2 = GetLastError ();
5706 switch (w32err2)
5708 case ERROR_FILE_NOT_FOUND:
5709 case ERROR_PATH_NOT_FOUND:
5710 errno = ENOENT;
5711 break;
5712 case ERROR_ACCESS_DENIED:
5713 case ERROR_TOO_MANY_OPEN_FILES:
5714 errno = EACCES;
5715 break;
5716 default:
5717 errno = EPERM;
5718 break;
5721 if (restore_privs)
5723 restore_privilege (&privs);
5724 revert_to_self ();
5727 return retval;
5730 ssize_t
5731 readlinkat (int fd, char const *name, char *buffer,
5732 size_t buffer_size)
5734 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5735 as in fstatat. FIXME: Add proper support for readlinkat. */
5736 char fullname[MAX_UTF8_PATH];
5738 if (fd != AT_FDCWD)
5740 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5741 < 0)
5743 errno = ENAMETOOLONG;
5744 return -1;
5746 name = fullname;
5749 return readlink (name, buffer, buffer_size);
5752 /* If FILE is a symlink, return its target (stored in a static
5753 buffer); otherwise return FILE.
5755 This function repeatedly resolves symlinks in the last component of
5756 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5757 until it arrives at a file whose last component is not a symlink,
5758 or some error occurs. It returns the target of the last
5759 successfully resolved symlink in the chain. If it succeeds to
5760 resolve even a single symlink, the value returned is an absolute
5761 file name with backslashes (result of GetFullPathName). By
5762 contrast, if the original FILE is returned, it is unaltered.
5764 Note: This function can set errno even if it succeeds.
5766 Implementation note: we only resolve the last portion ("basename")
5767 of the argument FILE and of each following file in the chain,
5768 disregarding any possible symlinks in its leading directories.
5769 This is because Windows system calls and library functions
5770 transparently resolve symlinks in leading directories and return
5771 correct information, as long as the basename is not a symlink. */
5772 static char *
5773 chase_symlinks (const char *file)
5775 static char target[MAX_UTF8_PATH];
5776 char link[MAX_UTF8_PATH];
5777 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
5778 char target_a[MAX_PATH], link_a[MAX_PATH];
5779 ssize_t res, link_len;
5780 int loop_count = 0;
5782 if (is_windows_9x () == TRUE || !is_symlink (file))
5783 return (char *)file;
5785 if (w32_unicode_filenames)
5787 wchar_t file_w[MAX_PATH];
5789 filename_to_utf16 (file, file_w);
5790 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
5791 return (char *)file;
5792 filename_from_utf16 (link_w, link);
5794 else
5796 char file_a[MAX_PATH];
5798 filename_to_ansi (file, file_a);
5799 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
5800 return (char *)file;
5801 filename_from_ansi (link_a, link);
5803 link_len = strlen (link);
5805 target[0] = '\0';
5806 do {
5808 /* Remove trailing slashes, as we want to resolve the last
5809 non-trivial part of the link name. */
5810 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
5811 link[link_len--] = '\0';
5813 res = readlink (link, target, MAX_UTF8_PATH);
5814 if (res > 0)
5816 target[res] = '\0';
5817 if (!(IS_DEVICE_SEP (target[1])
5818 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
5820 /* Target is relative. Append it to the directory part of
5821 the symlink, then copy the result back to target. */
5822 char *p = link + link_len;
5824 while (p > link && !IS_ANY_SEP (p[-1]))
5825 p--;
5826 strcpy (p, target);
5827 strcpy (target, link);
5829 /* Resolve any "." and ".." to get a fully-qualified file name
5830 in link[] again. */
5831 if (w32_unicode_filenames)
5833 filename_to_utf16 (target, target_w);
5834 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
5835 if (link_len > 0)
5836 filename_from_utf16 (link_w, link);
5838 else
5840 filename_to_ansi (target, target_a);
5841 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
5842 if (link_len > 0)
5843 filename_from_ansi (link_a, link);
5845 link_len = strlen (link);
5847 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
5849 if (loop_count > 100)
5850 errno = ELOOP;
5852 if (target[0] == '\0') /* not a single call to readlink succeeded */
5853 return (char *)file;
5854 return target;
5858 /* Posix ACL emulation. */
5861 acl_valid (acl_t acl)
5863 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
5866 char *
5867 acl_to_text (acl_t acl, ssize_t *size)
5869 LPTSTR str_acl;
5870 SECURITY_INFORMATION flags =
5871 OWNER_SECURITY_INFORMATION |
5872 GROUP_SECURITY_INFORMATION |
5873 DACL_SECURITY_INFORMATION;
5874 char *retval = NULL;
5875 ULONG local_size;
5876 int e = errno;
5878 errno = 0;
5880 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
5882 errno = e;
5883 /* We don't want to mix heaps, so we duplicate the string in our
5884 heap and free the one allocated by the API. */
5885 retval = xstrdup (str_acl);
5886 if (size)
5887 *size = local_size;
5888 LocalFree (str_acl);
5890 else if (errno != ENOTSUP)
5891 errno = EINVAL;
5893 return retval;
5896 acl_t
5897 acl_from_text (const char *acl_str)
5899 PSECURITY_DESCRIPTOR psd, retval = NULL;
5900 ULONG sd_size;
5901 int e = errno;
5903 errno = 0;
5905 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
5907 errno = e;
5908 retval = xmalloc (sd_size);
5909 memcpy (retval, psd, sd_size);
5910 LocalFree (psd);
5912 else if (errno != ENOTSUP)
5913 errno = EINVAL;
5915 return retval;
5919 acl_free (void *ptr)
5921 xfree (ptr);
5922 return 0;
5925 acl_t
5926 acl_get_file (const char *fname, acl_type_t type)
5928 PSECURITY_DESCRIPTOR psd = NULL;
5929 const char *filename;
5931 if (type == ACL_TYPE_ACCESS)
5933 DWORD sd_len, err;
5934 SECURITY_INFORMATION si =
5935 OWNER_SECURITY_INFORMATION |
5936 GROUP_SECURITY_INFORMATION |
5937 DACL_SECURITY_INFORMATION ;
5938 int e = errno;
5940 filename = map_w32_filename (fname, NULL);
5941 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5942 fname = chase_symlinks (filename);
5943 else
5944 fname = filename;
5946 errno = 0;
5947 if (!get_file_security (fname, si, psd, 0, &sd_len)
5948 && errno != ENOTSUP)
5950 err = GetLastError ();
5951 if (err == ERROR_INSUFFICIENT_BUFFER)
5953 psd = xmalloc (sd_len);
5954 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
5956 xfree (psd);
5957 errno = EIO;
5958 psd = NULL;
5961 else if (err == ERROR_FILE_NOT_FOUND
5962 || err == ERROR_PATH_NOT_FOUND
5963 /* ERROR_INVALID_NAME is what we get if
5964 w32-unicode-filenames is nil and the file cannot
5965 be encoded in the current ANSI codepage. */
5966 || err == ERROR_INVALID_NAME)
5967 errno = ENOENT;
5968 else
5969 errno = EIO;
5971 else if (!errno)
5972 errno = e;
5974 else if (type != ACL_TYPE_DEFAULT)
5975 errno = EINVAL;
5977 return psd;
5981 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
5983 TOKEN_PRIVILEGES old1, old2;
5984 DWORD err;
5985 int st = 0, retval = -1;
5986 SECURITY_INFORMATION flags = 0;
5987 PSID psidOwner, psidGroup;
5988 PACL pacl;
5989 BOOL dflt;
5990 BOOL dacl_present;
5991 int e;
5992 const char *filename;
5994 if (acl_valid (acl) != 0
5995 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
5997 errno = EINVAL;
5998 return -1;
6001 if (type == ACL_TYPE_DEFAULT)
6003 errno = ENOSYS;
6004 return -1;
6007 filename = map_w32_filename (fname, NULL);
6008 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6009 fname = chase_symlinks (filename);
6010 else
6011 fname = filename;
6013 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
6014 &dflt)
6015 && psidOwner)
6016 flags |= OWNER_SECURITY_INFORMATION;
6017 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
6018 &dflt)
6019 && psidGroup)
6020 flags |= GROUP_SECURITY_INFORMATION;
6021 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
6022 &pacl, &dflt)
6023 && dacl_present)
6024 flags |= DACL_SECURITY_INFORMATION;
6025 if (!flags)
6026 return 0;
6028 /* According to KB-245153, setting the owner will succeed if either:
6029 (1) the caller is the user who will be the new owner, and has the
6030 SE_TAKE_OWNERSHIP privilege, or
6031 (2) the caller has the SE_RESTORE privilege, in which case she can
6032 set any valid user or group as the owner
6034 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
6035 privileges, and disregard any failures in obtaining them. If
6036 these privileges cannot be obtained, and do not already exist in
6037 the calling thread's security token, this function could fail
6038 with EPERM. */
6039 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
6040 st++;
6041 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
6042 st++;
6044 e = errno;
6045 errno = 0;
6046 /* SetFileSecurity is deprecated by MS, and sometimes fails when
6047 DACL inheritance is involved, but it seems to preserve ownership
6048 better than SetNamedSecurityInfo, which is important e.g., in
6049 copy-file. */
6050 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
6052 err = GetLastError ();
6054 if (errno != ENOTSUP)
6055 err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
6056 psidOwner, psidGroup, pacl, NULL);
6058 else
6059 err = ERROR_SUCCESS;
6060 if (err != ERROR_SUCCESS)
6062 if (errno == ENOTSUP)
6064 else if (err == ERROR_INVALID_OWNER
6065 || err == ERROR_NOT_ALL_ASSIGNED
6066 || err == ERROR_ACCESS_DENIED)
6068 /* Maybe the requested ACL and the one the file already has
6069 are identical, in which case we can silently ignore the
6070 failure. (And no, Windows doesn't.) */
6071 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
6073 errno = EPERM;
6074 if (current_acl)
6076 char *acl_from = acl_to_text (current_acl, NULL);
6077 char *acl_to = acl_to_text (acl, NULL);
6079 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
6081 retval = 0;
6082 errno = e;
6084 if (acl_from)
6085 acl_free (acl_from);
6086 if (acl_to)
6087 acl_free (acl_to);
6088 acl_free (current_acl);
6091 else if (err == ERROR_FILE_NOT_FOUND
6092 || err == ERROR_PATH_NOT_FOUND
6093 /* ERROR_INVALID_NAME is what we get if
6094 w32-unicode-filenames is nil and the file cannot be
6095 encoded in the current ANSI codepage. */
6096 || err == ERROR_INVALID_NAME)
6097 errno = ENOENT;
6098 else
6099 errno = EACCES;
6101 else
6103 retval = 0;
6104 errno = e;
6107 if (st)
6109 if (st >= 2)
6110 restore_privilege (&old2);
6111 restore_privilege (&old1);
6112 revert_to_self ();
6115 return retval;
6119 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
6120 have a fixed max size for file names, so we don't need the kind of
6121 alloc/malloc/realloc dance the gnulib version does. We also don't
6122 support FD-relative symlinks. */
6123 char *
6124 careadlinkat (int fd, char const *filename,
6125 char *buffer, size_t buffer_size,
6126 struct allocator const *alloc,
6127 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6129 char linkname[MAX_UTF8_PATH];
6130 ssize_t link_size;
6132 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6134 if (link_size > 0)
6136 char *retval = buffer;
6138 linkname[link_size++] = '\0';
6139 if (link_size > buffer_size)
6140 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6141 if (retval)
6142 memcpy (retval, linkname, link_size);
6144 return retval;
6146 return NULL;
6150 w32_copy_file (const char *from, const char *to,
6151 int keep_time, int preserve_ownership, int copy_acls)
6153 acl_t acl = NULL;
6154 BOOL copy_result;
6155 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6156 char from_a[MAX_PATH], to_a[MAX_PATH];
6158 /* We ignore preserve_ownership for now. */
6159 preserve_ownership = preserve_ownership;
6161 if (copy_acls)
6163 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6164 if (acl == NULL && acl_errno_valid (errno))
6165 return -2;
6167 if (w32_unicode_filenames)
6169 filename_to_utf16 (from, from_w);
6170 filename_to_utf16 (to, to_w);
6171 copy_result = CopyFileW (from_w, to_w, FALSE);
6173 else
6175 filename_to_ansi (from, from_a);
6176 filename_to_ansi (to, to_a);
6177 copy_result = CopyFileA (from_a, to_a, FALSE);
6179 if (!copy_result)
6181 /* CopyFile doesn't set errno when it fails. By far the most
6182 "popular" reason is that the target is read-only. */
6183 DWORD err = GetLastError ();
6185 switch (err)
6187 case ERROR_FILE_NOT_FOUND:
6188 errno = ENOENT;
6189 break;
6190 case ERROR_ACCESS_DENIED:
6191 errno = EACCES;
6192 break;
6193 case ERROR_ENCRYPTION_FAILED:
6194 errno = EIO;
6195 break;
6196 default:
6197 errno = EPERM;
6198 break;
6201 if (acl)
6202 acl_free (acl);
6203 return -1;
6205 /* CopyFile retains the timestamp by default. However, see
6206 "Community Additions" for CopyFile: it sounds like that is not
6207 entirely true. Testing on Windows XP confirms that modified time
6208 is copied, but creation and last-access times are not.
6209 FIXME? */
6210 else if (!keep_time)
6212 struct timespec now;
6213 DWORD attributes;
6215 if (w32_unicode_filenames)
6217 /* Ensure file is writable while its times are set. */
6218 attributes = GetFileAttributesW (to_w);
6219 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6220 now = current_timespec ();
6221 if (set_file_times (-1, to, now, now))
6223 /* Restore original attributes. */
6224 SetFileAttributesW (to_w, attributes);
6225 if (acl)
6226 acl_free (acl);
6227 return -3;
6229 /* Restore original attributes. */
6230 SetFileAttributesW (to_w, attributes);
6232 else
6234 attributes = GetFileAttributesA (to_a);
6235 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6236 now = current_timespec ();
6237 if (set_file_times (-1, to, now, now))
6239 SetFileAttributesA (to_a, attributes);
6240 if (acl)
6241 acl_free (acl);
6242 return -3;
6244 SetFileAttributesA (to_a, attributes);
6247 if (acl != NULL)
6249 bool fail =
6250 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6251 acl_free (acl);
6252 if (fail && acl_errno_valid (errno))
6253 return -4;
6256 return 0;
6260 /* Support for browsing other processes and their attributes. See
6261 process.c for the Lisp bindings. */
6263 /* Helper wrapper functions. */
6265 static HANDLE WINAPI
6266 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6268 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6270 if (g_b_init_create_toolhelp32_snapshot == 0)
6272 g_b_init_create_toolhelp32_snapshot = 1;
6273 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6274 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6275 "CreateToolhelp32Snapshot");
6277 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6279 return INVALID_HANDLE_VALUE;
6281 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6284 static BOOL WINAPI
6285 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6287 static Process32First_Proc s_pfn_Process32_First = NULL;
6289 if (g_b_init_process32_first == 0)
6291 g_b_init_process32_first = 1;
6292 s_pfn_Process32_First = (Process32First_Proc)
6293 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6294 "Process32First");
6296 if (s_pfn_Process32_First == NULL)
6298 return FALSE;
6300 return (s_pfn_Process32_First (hSnapshot, lppe));
6303 static BOOL WINAPI
6304 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6306 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6308 if (g_b_init_process32_next == 0)
6310 g_b_init_process32_next = 1;
6311 s_pfn_Process32_Next = (Process32Next_Proc)
6312 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6313 "Process32Next");
6315 if (s_pfn_Process32_Next == NULL)
6317 return FALSE;
6319 return (s_pfn_Process32_Next (hSnapshot, lppe));
6322 static BOOL WINAPI
6323 open_thread_token (HANDLE ThreadHandle,
6324 DWORD DesiredAccess,
6325 BOOL OpenAsSelf,
6326 PHANDLE TokenHandle)
6328 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6329 HMODULE hm_advapi32 = NULL;
6330 if (is_windows_9x () == TRUE)
6332 SetLastError (ERROR_NOT_SUPPORTED);
6333 return FALSE;
6335 if (g_b_init_open_thread_token == 0)
6337 g_b_init_open_thread_token = 1;
6338 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6339 s_pfn_Open_Thread_Token =
6340 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6342 if (s_pfn_Open_Thread_Token == NULL)
6344 SetLastError (ERROR_NOT_SUPPORTED);
6345 return FALSE;
6347 return (
6348 s_pfn_Open_Thread_Token (
6349 ThreadHandle,
6350 DesiredAccess,
6351 OpenAsSelf,
6352 TokenHandle)
6356 static BOOL WINAPI
6357 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6359 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6360 HMODULE hm_advapi32 = NULL;
6361 if (is_windows_9x () == TRUE)
6363 return FALSE;
6365 if (g_b_init_impersonate_self == 0)
6367 g_b_init_impersonate_self = 1;
6368 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6369 s_pfn_Impersonate_Self =
6370 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6372 if (s_pfn_Impersonate_Self == NULL)
6374 return FALSE;
6376 return s_pfn_Impersonate_Self (ImpersonationLevel);
6379 static BOOL WINAPI
6380 revert_to_self (void)
6382 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6383 HMODULE hm_advapi32 = NULL;
6384 if (is_windows_9x () == TRUE)
6386 return FALSE;
6388 if (g_b_init_revert_to_self == 0)
6390 g_b_init_revert_to_self = 1;
6391 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6392 s_pfn_Revert_To_Self =
6393 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6395 if (s_pfn_Revert_To_Self == NULL)
6397 return FALSE;
6399 return s_pfn_Revert_To_Self ();
6402 static BOOL WINAPI
6403 get_process_memory_info (HANDLE h_proc,
6404 PPROCESS_MEMORY_COUNTERS mem_counters,
6405 DWORD bufsize)
6407 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6408 HMODULE hm_psapi = NULL;
6409 if (is_windows_9x () == TRUE)
6411 return FALSE;
6413 if (g_b_init_get_process_memory_info == 0)
6415 g_b_init_get_process_memory_info = 1;
6416 hm_psapi = LoadLibrary ("Psapi.dll");
6417 if (hm_psapi)
6418 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6419 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6421 if (s_pfn_Get_Process_Memory_Info == NULL)
6423 return FALSE;
6425 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6428 static BOOL WINAPI
6429 get_process_working_set_size (HANDLE h_proc,
6430 PSIZE_T minrss,
6431 PSIZE_T maxrss)
6433 static GetProcessWorkingSetSize_Proc
6434 s_pfn_Get_Process_Working_Set_Size = NULL;
6436 if (is_windows_9x () == TRUE)
6438 return FALSE;
6440 if (g_b_init_get_process_working_set_size == 0)
6442 g_b_init_get_process_working_set_size = 1;
6443 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6444 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6445 "GetProcessWorkingSetSize");
6447 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6449 return FALSE;
6451 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6454 static BOOL WINAPI
6455 global_memory_status (MEMORYSTATUS *buf)
6457 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6459 if (is_windows_9x () == TRUE)
6461 return FALSE;
6463 if (g_b_init_global_memory_status == 0)
6465 g_b_init_global_memory_status = 1;
6466 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6467 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6468 "GlobalMemoryStatus");
6470 if (s_pfn_Global_Memory_Status == NULL)
6472 return FALSE;
6474 return s_pfn_Global_Memory_Status (buf);
6477 static BOOL WINAPI
6478 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6480 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6482 if (is_windows_9x () == TRUE)
6484 return FALSE;
6486 if (g_b_init_global_memory_status_ex == 0)
6488 g_b_init_global_memory_status_ex = 1;
6489 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6490 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6491 "GlobalMemoryStatusEx");
6493 if (s_pfn_Global_Memory_Status_Ex == NULL)
6495 return FALSE;
6497 return s_pfn_Global_Memory_Status_Ex (buf);
6500 Lisp_Object
6501 list_system_processes (void)
6503 struct gcpro gcpro1;
6504 Lisp_Object proclist = Qnil;
6505 HANDLE h_snapshot;
6507 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6509 if (h_snapshot != INVALID_HANDLE_VALUE)
6511 PROCESSENTRY32 proc_entry;
6512 DWORD proc_id;
6513 BOOL res;
6515 GCPRO1 (proclist);
6517 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6518 for (res = process32_first (h_snapshot, &proc_entry); res;
6519 res = process32_next (h_snapshot, &proc_entry))
6521 proc_id = proc_entry.th32ProcessID;
6522 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6525 CloseHandle (h_snapshot);
6526 UNGCPRO;
6527 proclist = Fnreverse (proclist);
6530 return proclist;
6533 static int
6534 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6536 TOKEN_PRIVILEGES priv;
6537 DWORD priv_size = sizeof (priv);
6538 DWORD opriv_size = sizeof (*old_priv);
6539 HANDLE h_token = NULL;
6540 HANDLE h_thread = GetCurrentThread ();
6541 int ret_val = 0;
6542 BOOL res;
6544 res = open_thread_token (h_thread,
6545 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6546 FALSE, &h_token);
6547 if (!res && GetLastError () == ERROR_NO_TOKEN)
6549 if (impersonate_self (SecurityImpersonation))
6550 res = open_thread_token (h_thread,
6551 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6552 FALSE, &h_token);
6554 if (res)
6556 priv.PrivilegeCount = 1;
6557 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6558 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6559 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6560 old_priv, &opriv_size)
6561 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6562 ret_val = 1;
6564 if (h_token)
6565 CloseHandle (h_token);
6567 return ret_val;
6570 static int
6571 restore_privilege (TOKEN_PRIVILEGES *priv)
6573 DWORD priv_size = sizeof (*priv);
6574 HANDLE h_token = NULL;
6575 int ret_val = 0;
6577 if (open_thread_token (GetCurrentThread (),
6578 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6579 FALSE, &h_token))
6581 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6582 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6583 ret_val = 1;
6585 if (h_token)
6586 CloseHandle (h_token);
6588 return ret_val;
6591 static Lisp_Object
6592 ltime (ULONGLONG time_100ns)
6594 ULONGLONG time_sec = time_100ns / 10000000;
6595 int subsec = time_100ns % 10000000;
6596 return list4i (time_sec >> 16, time_sec & 0xffff,
6597 subsec / 10, subsec % 10 * 100000);
6600 #define U64_TO_LISP_TIME(time) ltime (time)
6602 static int
6603 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6604 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6605 double *pcpu)
6607 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6608 ULONGLONG tem1, tem2, tem3, tem;
6610 if (!h_proc
6611 || !get_process_times_fn
6612 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6613 &ft_kernel, &ft_user))
6614 return 0;
6616 GetSystemTimeAsFileTime (&ft_current);
6618 FILETIME_TO_U64 (tem1, ft_kernel);
6619 *stime = U64_TO_LISP_TIME (tem1);
6621 FILETIME_TO_U64 (tem2, ft_user);
6622 *utime = U64_TO_LISP_TIME (tem2);
6624 tem3 = tem1 + tem2;
6625 *ttime = U64_TO_LISP_TIME (tem3);
6627 FILETIME_TO_U64 (tem, ft_creation);
6628 /* Process no 4 (System) returns zero creation time. */
6629 if (tem)
6630 tem -= utc_base;
6631 *ctime = U64_TO_LISP_TIME (tem);
6633 if (tem)
6635 FILETIME_TO_U64 (tem3, ft_current);
6636 tem = (tem3 - utc_base) - tem;
6638 *etime = U64_TO_LISP_TIME (tem);
6640 if (tem)
6642 *pcpu = 100.0 * (tem1 + tem2) / tem;
6643 if (*pcpu > 100)
6644 *pcpu = 100.0;
6646 else
6647 *pcpu = 0;
6649 return 1;
6652 Lisp_Object
6653 system_process_attributes (Lisp_Object pid)
6655 struct gcpro gcpro1, gcpro2, gcpro3;
6656 Lisp_Object attrs = Qnil;
6657 Lisp_Object cmd_str, decoded_cmd, tem;
6658 HANDLE h_snapshot, h_proc;
6659 DWORD proc_id;
6660 int found_proc = 0;
6661 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
6662 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
6663 DWORD glength = sizeof (gname);
6664 HANDLE token = NULL;
6665 SID_NAME_USE user_type;
6666 unsigned char *buf = NULL;
6667 DWORD blen = 0;
6668 TOKEN_USER user_token;
6669 TOKEN_PRIMARY_GROUP group_token;
6670 unsigned euid;
6671 unsigned egid;
6672 PROCESS_MEMORY_COUNTERS mem;
6673 PROCESS_MEMORY_COUNTERS_EX mem_ex;
6674 SIZE_T minrss, maxrss;
6675 MEMORYSTATUS memst;
6676 MEMORY_STATUS_EX memstex;
6677 double totphys = 0.0;
6678 Lisp_Object ctime, stime, utime, etime, ttime;
6679 double pcpu;
6680 BOOL result = FALSE;
6682 CHECK_NUMBER_OR_FLOAT (pid);
6683 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
6685 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6687 GCPRO3 (attrs, decoded_cmd, tem);
6689 if (h_snapshot != INVALID_HANDLE_VALUE)
6691 PROCESSENTRY32 pe;
6692 BOOL res;
6694 pe.dwSize = sizeof (PROCESSENTRY32);
6695 for (res = process32_first (h_snapshot, &pe); res;
6696 res = process32_next (h_snapshot, &pe))
6698 if (proc_id == pe.th32ProcessID)
6700 if (proc_id == 0)
6701 decoded_cmd = build_string ("Idle");
6702 else
6704 /* Decode the command name from locale-specific
6705 encoding. */
6706 cmd_str = build_unibyte_string (pe.szExeFile);
6708 decoded_cmd =
6709 code_convert_string_norecord (cmd_str,
6710 Vlocale_coding_system, 0);
6712 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
6713 attrs = Fcons (Fcons (Qppid,
6714 make_fixnum_or_float (pe.th32ParentProcessID)),
6715 attrs);
6716 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
6717 attrs);
6718 attrs = Fcons (Fcons (Qthcount,
6719 make_fixnum_or_float (pe.cntThreads)),
6720 attrs);
6721 found_proc = 1;
6722 break;
6726 CloseHandle (h_snapshot);
6729 if (!found_proc)
6731 UNGCPRO;
6732 return Qnil;
6735 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6736 FALSE, proc_id);
6737 /* If we were denied a handle to the process, try again after
6738 enabling the SeDebugPrivilege in our process. */
6739 if (!h_proc)
6741 TOKEN_PRIVILEGES priv_current;
6743 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
6745 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6746 FALSE, proc_id);
6747 restore_privilege (&priv_current);
6748 revert_to_self ();
6751 if (h_proc)
6753 result = open_process_token (h_proc, TOKEN_QUERY, &token);
6754 if (result)
6756 result = get_token_information (token, TokenUser, NULL, 0, &blen);
6757 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6759 buf = xmalloc (blen);
6760 result = get_token_information (token, TokenUser,
6761 (LPVOID)buf, blen, &needed);
6762 if (result)
6764 memcpy (&user_token, buf, sizeof (user_token));
6765 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
6767 euid = get_rid (user_token.User.Sid);
6768 result = lookup_account_sid (NULL, user_token.User.Sid,
6769 uname, &ulength,
6770 domain, &dlength,
6771 &user_type);
6772 if (result)
6773 w32_add_to_cache (user_token.User.Sid, euid, uname);
6774 else
6776 strcpy (uname, "unknown");
6777 result = TRUE;
6780 ulength = strlen (uname);
6784 if (result)
6786 /* Determine a reasonable euid and gid values. */
6787 if (xstrcasecmp ("administrator", uname) == 0)
6789 euid = 500; /* well-known Administrator uid */
6790 egid = 513; /* well-known None gid */
6792 else
6794 /* Get group id and name. */
6795 result = get_token_information (token, TokenPrimaryGroup,
6796 (LPVOID)buf, blen, &needed);
6797 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6799 buf = xrealloc (buf, blen = needed);
6800 result = get_token_information (token, TokenPrimaryGroup,
6801 (LPVOID)buf, blen, &needed);
6803 if (result)
6805 memcpy (&group_token, buf, sizeof (group_token));
6806 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
6808 egid = get_rid (group_token.PrimaryGroup);
6809 dlength = sizeof (domain);
6810 result =
6811 lookup_account_sid (NULL, group_token.PrimaryGroup,
6812 gname, &glength, NULL, &dlength,
6813 &user_type);
6814 if (result)
6815 w32_add_to_cache (group_token.PrimaryGroup,
6816 egid, gname);
6817 else
6819 strcpy (gname, "None");
6820 result = TRUE;
6823 glength = strlen (gname);
6827 xfree (buf);
6829 if (!result)
6831 if (!is_windows_9x ())
6833 /* We couldn't open the process token, presumably because of
6834 insufficient access rights. Assume this process is run
6835 by the system. */
6836 strcpy (uname, "SYSTEM");
6837 strcpy (gname, "None");
6838 euid = 18; /* SYSTEM */
6839 egid = 513; /* None */
6840 glength = strlen (gname);
6841 ulength = strlen (uname);
6843 /* If we are running under Windows 9X, where security calls are
6844 not supported, we assume all processes are run by the current
6845 user. */
6846 else if (GetUserName (uname, &ulength))
6848 if (xstrcasecmp ("administrator", uname) == 0)
6849 euid = 0;
6850 else
6851 euid = 123;
6852 egid = euid;
6853 strcpy (gname, "None");
6854 glength = strlen (gname);
6855 ulength = strlen (uname);
6857 else
6859 euid = 123;
6860 egid = 123;
6861 strcpy (uname, "administrator");
6862 ulength = strlen (uname);
6863 strcpy (gname, "None");
6864 glength = strlen (gname);
6866 if (token)
6867 CloseHandle (token);
6870 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
6871 tem = make_unibyte_string (uname, ulength);
6872 attrs = Fcons (Fcons (Quser,
6873 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6874 attrs);
6875 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
6876 tem = make_unibyte_string (gname, glength);
6877 attrs = Fcons (Fcons (Qgroup,
6878 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6879 attrs);
6881 if (global_memory_status_ex (&memstex))
6882 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
6883 totphys = memstex.ullTotalPhys / 1024.0;
6884 #else
6885 /* Visual Studio 6 cannot convert an unsigned __int64 type to
6886 double, so we need to do this for it... */
6888 DWORD tot_hi = memstex.ullTotalPhys >> 32;
6889 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
6890 DWORD tot_lo = memstex.ullTotalPhys % 1024;
6892 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
6894 #endif /* __GNUC__ || _MSC_VER >= 1300 */
6895 else if (global_memory_status (&memst))
6896 totphys = memst.dwTotalPhys / 1024.0;
6898 if (h_proc
6899 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
6900 sizeof (mem_ex)))
6902 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6904 attrs = Fcons (Fcons (Qmajflt,
6905 make_fixnum_or_float (mem_ex.PageFaultCount)),
6906 attrs);
6907 attrs = Fcons (Fcons (Qvsize,
6908 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
6909 attrs);
6910 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6911 if (totphys)
6912 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6914 else if (h_proc
6915 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
6917 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6919 attrs = Fcons (Fcons (Qmajflt,
6920 make_fixnum_or_float (mem.PageFaultCount)),
6921 attrs);
6922 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6923 if (totphys)
6924 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6926 else if (h_proc
6927 && get_process_working_set_size (h_proc, &minrss, &maxrss))
6929 DWORD rss = maxrss / 1024;
6931 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
6932 if (totphys)
6933 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6936 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
6938 attrs = Fcons (Fcons (Qutime, utime), attrs);
6939 attrs = Fcons (Fcons (Qstime, stime), attrs);
6940 attrs = Fcons (Fcons (Qtime, ttime), attrs);
6941 attrs = Fcons (Fcons (Qstart, ctime), attrs);
6942 attrs = Fcons (Fcons (Qetime, etime), attrs);
6943 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
6946 /* FIXME: Retrieve command line by walking the PEB of the process. */
6948 if (h_proc)
6949 CloseHandle (h_proc);
6950 UNGCPRO;
6951 return attrs;
6955 /* Wrappers for winsock functions to map between our file descriptors
6956 and winsock's handles; also set h_errno for convenience.
6958 To allow Emacs to run on systems which don't have winsock support
6959 installed, we dynamically link to winsock on startup if present, and
6960 otherwise provide the minimum necessary functionality
6961 (eg. gethostname). */
6963 /* function pointers for relevant socket functions */
6964 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
6965 void (PASCAL *pfn_WSASetLastError) (int iError);
6966 int (PASCAL *pfn_WSAGetLastError) (void);
6967 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
6968 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
6969 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
6970 int (PASCAL *pfn_socket) (int af, int type, int protocol);
6971 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
6972 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
6973 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
6974 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
6975 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
6976 int (PASCAL *pfn_closesocket) (SOCKET s);
6977 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
6978 int (PASCAL *pfn_WSACleanup) (void);
6980 u_short (PASCAL *pfn_htons) (u_short hostshort);
6981 u_short (PASCAL *pfn_ntohs) (u_short netshort);
6982 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
6983 int (PASCAL *pfn_gethostname) (char * name, int namelen);
6984 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
6985 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
6986 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
6987 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
6988 const char * optval, int optlen);
6989 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
6990 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
6991 int * namelen);
6992 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
6993 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
6994 struct sockaddr * from, int * fromlen);
6995 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
6996 const struct sockaddr * to, int tolen);
6998 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6999 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7000 #ifndef HANDLE_FLAG_INHERIT
7001 #define HANDLE_FLAG_INHERIT 1
7002 #endif
7004 HANDLE winsock_lib;
7005 static int winsock_inuse;
7007 BOOL
7008 term_winsock (void)
7010 if (winsock_lib != NULL && winsock_inuse == 0)
7012 release_listen_threads ();
7013 /* Not sure what would cause WSAENETDOWN, or even if it can happen
7014 after WSAStartup returns successfully, but it seems reasonable
7015 to allow unloading winsock anyway in that case. */
7016 if (pfn_WSACleanup () == 0 ||
7017 pfn_WSAGetLastError () == WSAENETDOWN)
7019 if (FreeLibrary (winsock_lib))
7020 winsock_lib = NULL;
7021 return TRUE;
7024 return FALSE;
7027 BOOL
7028 init_winsock (int load_now)
7030 WSADATA winsockData;
7032 if (winsock_lib != NULL)
7033 return TRUE;
7035 pfn_SetHandleInformation
7036 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
7037 "SetHandleInformation");
7039 winsock_lib = LoadLibrary ("Ws2_32.dll");
7041 if (winsock_lib != NULL)
7043 /* dynamically link to socket functions */
7045 #define LOAD_PROC(fn) \
7046 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
7047 goto fail;
7049 LOAD_PROC (WSAStartup);
7050 LOAD_PROC (WSASetLastError);
7051 LOAD_PROC (WSAGetLastError);
7052 LOAD_PROC (WSAEventSelect);
7053 LOAD_PROC (WSACreateEvent);
7054 LOAD_PROC (WSACloseEvent);
7055 LOAD_PROC (socket);
7056 LOAD_PROC (bind);
7057 LOAD_PROC (connect);
7058 LOAD_PROC (ioctlsocket);
7059 LOAD_PROC (recv);
7060 LOAD_PROC (send);
7061 LOAD_PROC (closesocket);
7062 LOAD_PROC (shutdown);
7063 LOAD_PROC (htons);
7064 LOAD_PROC (ntohs);
7065 LOAD_PROC (inet_addr);
7066 LOAD_PROC (gethostname);
7067 LOAD_PROC (gethostbyname);
7068 LOAD_PROC (getservbyname);
7069 LOAD_PROC (getpeername);
7070 LOAD_PROC (WSACleanup);
7071 LOAD_PROC (setsockopt);
7072 LOAD_PROC (listen);
7073 LOAD_PROC (getsockname);
7074 LOAD_PROC (accept);
7075 LOAD_PROC (recvfrom);
7076 LOAD_PROC (sendto);
7077 #undef LOAD_PROC
7079 /* specify version 1.1 of winsock */
7080 if (pfn_WSAStartup (0x101, &winsockData) == 0)
7082 if (winsockData.wVersion != 0x101)
7083 goto fail;
7085 if (!load_now)
7087 /* Report that winsock exists and is usable, but leave
7088 socket functions disabled. I am assuming that calling
7089 WSAStartup does not require any network interaction,
7090 and in particular does not cause or require a dial-up
7091 connection to be established. */
7093 pfn_WSACleanup ();
7094 FreeLibrary (winsock_lib);
7095 winsock_lib = NULL;
7097 winsock_inuse = 0;
7098 return TRUE;
7101 fail:
7102 FreeLibrary (winsock_lib);
7103 winsock_lib = NULL;
7106 return FALSE;
7110 int h_errno = 0;
7112 /* Function to map winsock error codes to errno codes for those errno
7113 code defined in errno.h (errno values not defined by errno.h are
7114 already in nt/inc/sys/socket.h). */
7115 static void
7116 set_errno (void)
7118 int wsa_err;
7120 h_errno = 0;
7121 if (winsock_lib == NULL)
7122 wsa_err = EINVAL;
7123 else
7124 wsa_err = pfn_WSAGetLastError ();
7126 switch (wsa_err)
7128 case WSAEACCES: errno = EACCES; break;
7129 case WSAEBADF: errno = EBADF; break;
7130 case WSAEFAULT: errno = EFAULT; break;
7131 case WSAEINTR: errno = EINTR; break;
7132 case WSAEINVAL: errno = EINVAL; break;
7133 case WSAEMFILE: errno = EMFILE; break;
7134 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7135 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7136 default: errno = wsa_err; break;
7140 static void
7141 check_errno (void)
7143 h_errno = 0;
7144 if (winsock_lib != NULL)
7145 pfn_WSASetLastError (0);
7148 /* Extend strerror to handle the winsock-specific error codes. */
7149 struct {
7150 int errnum;
7151 char * msg;
7152 } _wsa_errlist[] = {
7153 {WSAEINTR , "Interrupted function call"},
7154 {WSAEBADF , "Bad file descriptor"},
7155 {WSAEACCES , "Permission denied"},
7156 {WSAEFAULT , "Bad address"},
7157 {WSAEINVAL , "Invalid argument"},
7158 {WSAEMFILE , "Too many open files"},
7160 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7161 {WSAEINPROGRESS , "Operation now in progress"},
7162 {WSAEALREADY , "Operation already in progress"},
7163 {WSAENOTSOCK , "Socket operation on non-socket"},
7164 {WSAEDESTADDRREQ , "Destination address required"},
7165 {WSAEMSGSIZE , "Message too long"},
7166 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7167 {WSAENOPROTOOPT , "Bad protocol option"},
7168 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7169 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7170 {WSAEOPNOTSUPP , "Operation not supported"},
7171 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7172 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7173 {WSAEADDRINUSE , "Address already in use"},
7174 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7175 {WSAENETDOWN , "Network is down"},
7176 {WSAENETUNREACH , "Network is unreachable"},
7177 {WSAENETRESET , "Network dropped connection on reset"},
7178 {WSAECONNABORTED , "Software caused connection abort"},
7179 {WSAECONNRESET , "Connection reset by peer"},
7180 {WSAENOBUFS , "No buffer space available"},
7181 {WSAEISCONN , "Socket is already connected"},
7182 {WSAENOTCONN , "Socket is not connected"},
7183 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7184 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7185 {WSAETIMEDOUT , "Connection timed out"},
7186 {WSAECONNREFUSED , "Connection refused"},
7187 {WSAELOOP , "Network loop"}, /* not sure */
7188 {WSAENAMETOOLONG , "Name is too long"},
7189 {WSAEHOSTDOWN , "Host is down"},
7190 {WSAEHOSTUNREACH , "No route to host"},
7191 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7192 {WSAEPROCLIM , "Too many processes"},
7193 {WSAEUSERS , "Too many users"}, /* not sure */
7194 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7195 {WSAESTALE , "Data is stale"}, /* not sure */
7196 {WSAEREMOTE , "Remote error"}, /* not sure */
7198 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7199 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7200 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7201 {WSAEDISCON , "Graceful shutdown in progress"},
7202 #ifdef WSAENOMORE
7203 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7204 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7205 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7206 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7207 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7208 {WSASYSCALLFAILURE , "System call failure"},
7209 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7210 {WSATYPE_NOT_FOUND , "Class type not found"},
7211 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7212 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7213 {WSAEREFUSED , "Operation refused"}, /* not sure */
7214 #endif
7216 {WSAHOST_NOT_FOUND , "Host not found"},
7217 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7218 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7219 {WSANO_DATA , "Valid name, no data record of requested type"},
7221 {-1, NULL}
7224 char *
7225 sys_strerror (int error_no)
7227 int i;
7228 static char unknown_msg[40];
7230 if (error_no >= 0 && error_no < sys_nerr)
7231 return sys_errlist[error_no];
7233 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7234 if (_wsa_errlist[i].errnum == error_no)
7235 return _wsa_errlist[i].msg;
7237 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7238 return unknown_msg;
7241 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7242 but I believe the method of keeping the socket handle separate (and
7243 insuring it is not inheritable) is the correct one. */
7245 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7247 static int socket_to_fd (SOCKET s);
7250 sys_socket (int af, int type, int protocol)
7252 SOCKET s;
7254 if (winsock_lib == NULL)
7256 errno = ENETDOWN;
7257 return INVALID_SOCKET;
7260 check_errno ();
7262 /* call the real socket function */
7263 s = pfn_socket (af, type, protocol);
7265 if (s != INVALID_SOCKET)
7266 return socket_to_fd (s);
7268 set_errno ();
7269 return -1;
7272 /* Convert a SOCKET to a file descriptor. */
7273 static int
7274 socket_to_fd (SOCKET s)
7276 int fd;
7277 child_process * cp;
7279 /* Although under NT 3.5 _open_osfhandle will accept a socket
7280 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7281 that does not work under NT 3.1. However, we can get the same
7282 effect by using a backdoor function to replace an existing
7283 descriptor handle with the one we want. */
7285 /* allocate a file descriptor (with appropriate flags) */
7286 fd = _open ("NUL:", _O_RDWR);
7287 if (fd >= 0)
7289 /* Make a non-inheritable copy of the socket handle. Note
7290 that it is possible that sockets aren't actually kernel
7291 handles, which appears to be the case on Windows 9x when
7292 the MS Proxy winsock client is installed. */
7294 /* Apparently there is a bug in NT 3.51 with some service
7295 packs, which prevents using DuplicateHandle to make a
7296 socket handle non-inheritable (causes WSACleanup to
7297 hang). The work-around is to use SetHandleInformation
7298 instead if it is available and implemented. */
7299 if (pfn_SetHandleInformation)
7301 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7303 else
7305 HANDLE parent = GetCurrentProcess ();
7306 HANDLE new_s = INVALID_HANDLE_VALUE;
7308 if (DuplicateHandle (parent,
7309 (HANDLE) s,
7310 parent,
7311 &new_s,
7313 FALSE,
7314 DUPLICATE_SAME_ACCESS))
7316 /* It is possible that DuplicateHandle succeeds even
7317 though the socket wasn't really a kernel handle,
7318 because a real handle has the same value. So
7319 test whether the new handle really is a socket. */
7320 long nonblocking = 0;
7321 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7323 pfn_closesocket (s);
7324 s = (SOCKET) new_s;
7326 else
7328 CloseHandle (new_s);
7333 eassert (fd < MAXDESC);
7334 fd_info[fd].hnd = (HANDLE) s;
7336 /* set our own internal flags */
7337 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7339 cp = new_child ();
7340 if (cp)
7342 cp->fd = fd;
7343 cp->status = STATUS_READ_ACKNOWLEDGED;
7345 /* attach child_process to fd_info */
7346 if (fd_info[ fd ].cp != NULL)
7348 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7349 emacs_abort ();
7352 fd_info[ fd ].cp = cp;
7354 /* success! */
7355 winsock_inuse++; /* count open sockets */
7356 return fd;
7359 /* clean up */
7360 _close (fd);
7362 else
7363 pfn_closesocket (s);
7364 errno = EMFILE;
7365 return -1;
7369 sys_bind (int s, const struct sockaddr * addr, int namelen)
7371 if (winsock_lib == NULL)
7373 errno = ENOTSOCK;
7374 return SOCKET_ERROR;
7377 check_errno ();
7378 if (fd_info[s].flags & FILE_SOCKET)
7380 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7381 if (rc == SOCKET_ERROR)
7382 set_errno ();
7383 return rc;
7385 errno = ENOTSOCK;
7386 return SOCKET_ERROR;
7390 sys_connect (int s, const struct sockaddr * name, int namelen)
7392 if (winsock_lib == NULL)
7394 errno = ENOTSOCK;
7395 return SOCKET_ERROR;
7398 check_errno ();
7399 if (fd_info[s].flags & FILE_SOCKET)
7401 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7402 if (rc == SOCKET_ERROR)
7403 set_errno ();
7404 return rc;
7406 errno = ENOTSOCK;
7407 return SOCKET_ERROR;
7410 u_short
7411 sys_htons (u_short hostshort)
7413 return (winsock_lib != NULL) ?
7414 pfn_htons (hostshort) : hostshort;
7417 u_short
7418 sys_ntohs (u_short netshort)
7420 return (winsock_lib != NULL) ?
7421 pfn_ntohs (netshort) : netshort;
7424 unsigned long
7425 sys_inet_addr (const char * cp)
7427 return (winsock_lib != NULL) ?
7428 pfn_inet_addr (cp) : INADDR_NONE;
7432 sys_gethostname (char * name, int namelen)
7434 if (winsock_lib != NULL)
7436 int retval;
7438 check_errno ();
7439 retval = pfn_gethostname (name, namelen);
7440 if (retval == SOCKET_ERROR)
7441 set_errno ();
7442 return retval;
7445 if (namelen > MAX_COMPUTERNAME_LENGTH)
7446 return !GetComputerName (name, (DWORD *)&namelen);
7448 errno = EFAULT;
7449 return SOCKET_ERROR;
7452 struct hostent *
7453 sys_gethostbyname (const char * name)
7455 struct hostent * host;
7456 int h_err = h_errno;
7458 if (winsock_lib == NULL)
7460 h_errno = NO_RECOVERY;
7461 errno = ENETDOWN;
7462 return NULL;
7465 check_errno ();
7466 host = pfn_gethostbyname (name);
7467 if (!host)
7469 set_errno ();
7470 h_errno = errno;
7472 else
7473 h_errno = h_err;
7474 return host;
7477 struct servent *
7478 sys_getservbyname (const char * name, const char * proto)
7480 struct servent * serv;
7482 if (winsock_lib == NULL)
7484 errno = ENETDOWN;
7485 return NULL;
7488 check_errno ();
7489 serv = pfn_getservbyname (name, proto);
7490 if (!serv)
7491 set_errno ();
7492 return serv;
7496 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7498 if (winsock_lib == NULL)
7500 errno = ENETDOWN;
7501 return SOCKET_ERROR;
7504 check_errno ();
7505 if (fd_info[s].flags & FILE_SOCKET)
7507 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7508 if (rc == SOCKET_ERROR)
7509 set_errno ();
7510 return rc;
7512 errno = ENOTSOCK;
7513 return SOCKET_ERROR;
7517 sys_shutdown (int s, int how)
7519 if (winsock_lib == NULL)
7521 errno = ENETDOWN;
7522 return SOCKET_ERROR;
7525 check_errno ();
7526 if (fd_info[s].flags & FILE_SOCKET)
7528 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
7529 if (rc == SOCKET_ERROR)
7530 set_errno ();
7531 return rc;
7533 errno = ENOTSOCK;
7534 return SOCKET_ERROR;
7538 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
7540 if (winsock_lib == NULL)
7542 errno = ENETDOWN;
7543 return SOCKET_ERROR;
7546 check_errno ();
7547 if (fd_info[s].flags & FILE_SOCKET)
7549 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
7550 (const char *)optval, optlen);
7551 if (rc == SOCKET_ERROR)
7552 set_errno ();
7553 return rc;
7555 errno = ENOTSOCK;
7556 return SOCKET_ERROR;
7560 sys_listen (int s, int backlog)
7562 if (winsock_lib == NULL)
7564 errno = ENETDOWN;
7565 return SOCKET_ERROR;
7568 check_errno ();
7569 if (fd_info[s].flags & FILE_SOCKET)
7571 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
7572 if (rc == SOCKET_ERROR)
7573 set_errno ();
7574 else
7575 fd_info[s].flags |= FILE_LISTEN;
7576 return rc;
7578 errno = ENOTSOCK;
7579 return SOCKET_ERROR;
7583 sys_getsockname (int s, struct sockaddr * name, int * namelen)
7585 if (winsock_lib == NULL)
7587 errno = ENETDOWN;
7588 return SOCKET_ERROR;
7591 check_errno ();
7592 if (fd_info[s].flags & FILE_SOCKET)
7594 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
7595 if (rc == SOCKET_ERROR)
7596 set_errno ();
7597 return rc;
7599 errno = ENOTSOCK;
7600 return SOCKET_ERROR;
7604 sys_accept (int s, struct sockaddr * addr, int * addrlen)
7606 if (winsock_lib == NULL)
7608 errno = ENETDOWN;
7609 return -1;
7612 check_errno ();
7613 if (fd_info[s].flags & FILE_LISTEN)
7615 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
7616 int fd = -1;
7617 if (t == INVALID_SOCKET)
7618 set_errno ();
7619 else
7620 fd = socket_to_fd (t);
7622 if (fd >= 0)
7624 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
7625 ResetEvent (fd_info[s].cp->char_avail);
7627 return fd;
7629 errno = ENOTSOCK;
7630 return -1;
7634 sys_recvfrom (int s, char * buf, int len, int flags,
7635 struct sockaddr * from, int * fromlen)
7637 if (winsock_lib == NULL)
7639 errno = ENETDOWN;
7640 return SOCKET_ERROR;
7643 check_errno ();
7644 if (fd_info[s].flags & FILE_SOCKET)
7646 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
7647 if (rc == SOCKET_ERROR)
7648 set_errno ();
7649 return rc;
7651 errno = ENOTSOCK;
7652 return SOCKET_ERROR;
7656 sys_sendto (int s, const char * buf, int len, int flags,
7657 const struct sockaddr * to, int tolen)
7659 if (winsock_lib == NULL)
7661 errno = ENETDOWN;
7662 return SOCKET_ERROR;
7665 check_errno ();
7666 if (fd_info[s].flags & FILE_SOCKET)
7668 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
7669 if (rc == SOCKET_ERROR)
7670 set_errno ();
7671 return rc;
7673 errno = ENOTSOCK;
7674 return SOCKET_ERROR;
7677 /* Windows does not have an fcntl function. Provide an implementation
7678 good enough for Emacs. */
7680 fcntl (int s, int cmd, int options)
7682 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
7683 invoked in a context where fd1 is closed and all descriptors less
7684 than fd1 are open, so sys_dup is an adequate implementation. */
7685 if (cmd == F_DUPFD_CLOEXEC)
7686 return sys_dup (s);
7688 if (winsock_lib == NULL)
7690 errno = ENETDOWN;
7691 return -1;
7694 check_errno ();
7695 if (fd_info[s].flags & FILE_SOCKET)
7697 if (cmd == F_SETFL && options == O_NONBLOCK)
7699 unsigned long nblock = 1;
7700 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
7701 if (rc == SOCKET_ERROR)
7702 set_errno ();
7703 /* Keep track of the fact that we set this to non-blocking. */
7704 fd_info[s].flags |= FILE_NDELAY;
7705 return rc;
7707 else
7709 errno = EINVAL;
7710 return SOCKET_ERROR;
7713 errno = ENOTSOCK;
7714 return SOCKET_ERROR;
7718 /* Shadow main io functions: we need to handle pipes and sockets more
7719 intelligently, and implement non-blocking mode as well. */
7722 sys_close (int fd)
7724 int rc;
7726 if (fd < 0)
7728 errno = EBADF;
7729 return -1;
7732 if (fd < MAXDESC && fd_info[fd].cp)
7734 child_process * cp = fd_info[fd].cp;
7736 fd_info[fd].cp = NULL;
7738 if (CHILD_ACTIVE (cp))
7740 /* if last descriptor to active child_process then cleanup */
7741 int i;
7742 for (i = 0; i < MAXDESC; i++)
7744 if (i == fd)
7745 continue;
7746 if (fd_info[i].cp == cp)
7747 break;
7749 if (i == MAXDESC)
7751 if (fd_info[fd].flags & FILE_SOCKET)
7753 if (winsock_lib == NULL) emacs_abort ();
7755 pfn_shutdown (SOCK_HANDLE (fd), 2);
7756 rc = pfn_closesocket (SOCK_HANDLE (fd));
7758 winsock_inuse--; /* count open sockets */
7760 /* If the process handle is NULL, it's either a socket
7761 or serial connection, or a subprocess that was
7762 already reaped by reap_subprocess, but whose
7763 resources were not yet freed, because its output was
7764 not fully read yet by the time it was reaped. (This
7765 usually happens with async subprocesses whose output
7766 is being read by Emacs.) Otherwise, this process was
7767 not reaped yet, so we set its FD to a negative value
7768 to make sure sys_select will eventually get to
7769 calling the SIGCHLD handler for it, which will then
7770 invoke waitpid and reap_subprocess. */
7771 if (cp->procinfo.hProcess == NULL)
7772 delete_child (cp);
7773 else
7774 cp->fd = -1;
7779 if (fd >= 0 && fd < MAXDESC)
7780 fd_info[fd].flags = 0;
7782 /* Note that sockets do not need special treatment here (at least on
7783 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
7784 closesocket is equivalent to CloseHandle, which is to be expected
7785 because socket handles are fully fledged kernel handles. */
7786 rc = _close (fd);
7788 return rc;
7792 sys_dup (int fd)
7794 int new_fd;
7796 new_fd = _dup (fd);
7797 if (new_fd >= 0 && new_fd < MAXDESC)
7799 /* duplicate our internal info as well */
7800 fd_info[new_fd] = fd_info[fd];
7802 return new_fd;
7806 sys_dup2 (int src, int dst)
7808 int rc;
7810 if (dst < 0 || dst >= MAXDESC)
7812 errno = EBADF;
7813 return -1;
7816 /* make sure we close the destination first if it's a pipe or socket */
7817 if (src != dst && fd_info[dst].flags != 0)
7818 sys_close (dst);
7820 rc = _dup2 (src, dst);
7821 if (rc == 0)
7823 /* duplicate our internal info as well */
7824 fd_info[dst] = fd_info[src];
7826 return rc;
7830 pipe2 (int * phandles, int pipe2_flags)
7832 int rc;
7833 unsigned flags;
7835 eassert (pipe2_flags == O_CLOEXEC);
7837 /* make pipe handles non-inheritable; when we spawn a child, we
7838 replace the relevant handle with an inheritable one. Also put
7839 pipes into binary mode; we will do text mode translation ourselves
7840 if required. */
7841 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
7843 if (rc == 0)
7845 /* Protect against overflow, since Windows can open more handles than
7846 our fd_info array has room for. */
7847 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
7849 _close (phandles[0]);
7850 _close (phandles[1]);
7851 errno = EMFILE;
7852 rc = -1;
7854 else
7856 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
7857 fd_info[phandles[0]].flags = flags;
7859 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
7860 fd_info[phandles[1]].flags = flags;
7864 return rc;
7867 /* Function to do blocking read of one byte, needed to implement
7868 select. It is only allowed on communication ports, sockets, or
7869 pipes. */
7871 _sys_read_ahead (int fd)
7873 child_process * cp;
7874 int rc;
7876 if (fd < 0 || fd >= MAXDESC)
7877 return STATUS_READ_ERROR;
7879 cp = fd_info[fd].cp;
7881 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7882 return STATUS_READ_ERROR;
7884 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
7885 || (fd_info[fd].flags & FILE_READ) == 0)
7887 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
7888 emacs_abort ();
7891 cp->status = STATUS_READ_IN_PROGRESS;
7893 if (fd_info[fd].flags & FILE_PIPE)
7895 rc = _read (fd, &cp->chr, sizeof (char));
7897 /* Give subprocess time to buffer some more output for us before
7898 reporting that input is available; we need this because Windows 95
7899 connects DOS programs to pipes by making the pipe appear to be
7900 the normal console stdout - as a result most DOS programs will
7901 write to stdout without buffering, ie. one character at a
7902 time. Even some W32 programs do this - "dir" in a command
7903 shell on NT is very slow if we don't do this. */
7904 if (rc > 0)
7906 int wait = w32_pipe_read_delay;
7908 if (wait > 0)
7909 Sleep (wait);
7910 else if (wait < 0)
7911 while (++wait <= 0)
7912 /* Yield remainder of our time slice, effectively giving a
7913 temporary priority boost to the child process. */
7914 Sleep (0);
7917 else if (fd_info[fd].flags & FILE_SERIAL)
7919 HANDLE hnd = fd_info[fd].hnd;
7920 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7921 COMMTIMEOUTS ct;
7923 /* Configure timeouts for blocking read. */
7924 if (!GetCommTimeouts (hnd, &ct))
7926 cp->status = STATUS_READ_ERROR;
7927 return STATUS_READ_ERROR;
7929 ct.ReadIntervalTimeout = 0;
7930 ct.ReadTotalTimeoutMultiplier = 0;
7931 ct.ReadTotalTimeoutConstant = 0;
7932 if (!SetCommTimeouts (hnd, &ct))
7934 cp->status = STATUS_READ_ERROR;
7935 return STATUS_READ_ERROR;
7938 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
7940 if (GetLastError () != ERROR_IO_PENDING)
7942 cp->status = STATUS_READ_ERROR;
7943 return STATUS_READ_ERROR;
7945 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
7947 cp->status = STATUS_READ_ERROR;
7948 return STATUS_READ_ERROR;
7952 else if (fd_info[fd].flags & FILE_SOCKET)
7954 unsigned long nblock = 0;
7955 /* We always want this to block, so temporarily disable NDELAY. */
7956 if (fd_info[fd].flags & FILE_NDELAY)
7957 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7959 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
7961 if (fd_info[fd].flags & FILE_NDELAY)
7963 nblock = 1;
7964 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7968 if (rc == sizeof (char))
7969 cp->status = STATUS_READ_SUCCEEDED;
7970 else
7971 cp->status = STATUS_READ_FAILED;
7973 return cp->status;
7977 _sys_wait_accept (int fd)
7979 HANDLE hEv;
7980 child_process * cp;
7981 int rc;
7983 if (fd < 0 || fd >= MAXDESC)
7984 return STATUS_READ_ERROR;
7986 cp = fd_info[fd].cp;
7988 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7989 return STATUS_READ_ERROR;
7991 cp->status = STATUS_READ_FAILED;
7993 hEv = pfn_WSACreateEvent ();
7994 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
7995 if (rc != SOCKET_ERROR)
7997 do {
7998 rc = WaitForSingleObject (hEv, 500);
7999 Sleep (5);
8000 } while (rc == WAIT_TIMEOUT
8001 && cp->status != STATUS_READ_ERROR
8002 && cp->char_avail);
8003 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8004 if (rc == WAIT_OBJECT_0)
8005 cp->status = STATUS_READ_SUCCEEDED;
8007 pfn_WSACloseEvent (hEv);
8009 return cp->status;
8013 sys_read (int fd, char * buffer, unsigned int count)
8015 int nchars;
8016 int to_read;
8017 DWORD waiting;
8018 char * orig_buffer = buffer;
8020 if (fd < 0)
8022 errno = EBADF;
8023 return -1;
8026 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8028 child_process *cp = fd_info[fd].cp;
8030 if ((fd_info[fd].flags & FILE_READ) == 0)
8032 errno = EBADF;
8033 return -1;
8036 nchars = 0;
8038 /* re-read CR carried over from last read */
8039 if (fd_info[fd].flags & FILE_LAST_CR)
8041 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
8042 *buffer++ = 0x0d;
8043 count--;
8044 nchars++;
8045 fd_info[fd].flags &= ~FILE_LAST_CR;
8048 /* presence of a child_process structure means we are operating in
8049 non-blocking mode - otherwise we just call _read directly.
8050 Note that the child_process structure might be missing because
8051 reap_subprocess has been called; in this case the pipe is
8052 already broken, so calling _read on it is okay. */
8053 if (cp)
8055 int current_status = cp->status;
8057 switch (current_status)
8059 case STATUS_READ_FAILED:
8060 case STATUS_READ_ERROR:
8061 /* report normal EOF if nothing in buffer */
8062 if (nchars <= 0)
8063 fd_info[fd].flags |= FILE_AT_EOF;
8064 return nchars;
8066 case STATUS_READ_READY:
8067 case STATUS_READ_IN_PROGRESS:
8068 DebPrint (("sys_read called when read is in progress\n"));
8069 errno = EWOULDBLOCK;
8070 return -1;
8072 case STATUS_READ_SUCCEEDED:
8073 /* consume read-ahead char */
8074 *buffer++ = cp->chr;
8075 count--;
8076 nchars++;
8077 cp->status = STATUS_READ_ACKNOWLEDGED;
8078 ResetEvent (cp->char_avail);
8080 case STATUS_READ_ACKNOWLEDGED:
8081 break;
8083 default:
8084 DebPrint (("sys_read: bad status %d\n", current_status));
8085 errno = EBADF;
8086 return -1;
8089 if (fd_info[fd].flags & FILE_PIPE)
8091 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
8092 to_read = min (waiting, (DWORD) count);
8094 if (to_read > 0)
8095 nchars += _read (fd, buffer, to_read);
8097 else if (fd_info[fd].flags & FILE_SERIAL)
8099 HANDLE hnd = fd_info[fd].hnd;
8100 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8101 int rc = 0;
8102 COMMTIMEOUTS ct;
8104 if (count > 0)
8106 /* Configure timeouts for non-blocking read. */
8107 if (!GetCommTimeouts (hnd, &ct))
8109 errno = EIO;
8110 return -1;
8112 ct.ReadIntervalTimeout = MAXDWORD;
8113 ct.ReadTotalTimeoutMultiplier = 0;
8114 ct.ReadTotalTimeoutConstant = 0;
8115 if (!SetCommTimeouts (hnd, &ct))
8117 errno = EIO;
8118 return -1;
8121 if (!ResetEvent (ovl->hEvent))
8123 errno = EIO;
8124 return -1;
8126 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8128 if (GetLastError () != ERROR_IO_PENDING)
8130 errno = EIO;
8131 return -1;
8133 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8135 errno = EIO;
8136 return -1;
8139 nchars += rc;
8142 else /* FILE_SOCKET */
8144 if (winsock_lib == NULL) emacs_abort ();
8146 /* do the equivalent of a non-blocking read */
8147 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8148 if (waiting == 0 && nchars == 0)
8150 errno = EWOULDBLOCK;
8151 return -1;
8154 if (waiting)
8156 /* always use binary mode for sockets */
8157 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8158 if (res == SOCKET_ERROR)
8160 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8161 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8162 set_errno ();
8163 return -1;
8165 nchars += res;
8169 else
8171 int nread = _read (fd, buffer, count);
8172 if (nread >= 0)
8173 nchars += nread;
8174 else if (nchars == 0)
8175 nchars = nread;
8178 if (nchars <= 0)
8179 fd_info[fd].flags |= FILE_AT_EOF;
8180 /* Perform text mode translation if required. */
8181 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8183 nchars = crlf_to_lf (nchars, orig_buffer);
8184 /* If buffer contains only CR, return that. To be absolutely
8185 sure we should attempt to read the next char, but in
8186 practice a CR to be followed by LF would not appear by
8187 itself in the buffer. */
8188 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8190 fd_info[fd].flags |= FILE_LAST_CR;
8191 nchars--;
8195 else
8196 nchars = _read (fd, buffer, count);
8198 return nchars;
8201 /* From w32xfns.c */
8202 extern HANDLE interrupt_handle;
8204 /* For now, don't bother with a non-blocking mode */
8206 sys_write (int fd, const void * buffer, unsigned int count)
8208 int nchars;
8210 if (fd < 0)
8212 errno = EBADF;
8213 return -1;
8216 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8218 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8220 errno = EBADF;
8221 return -1;
8224 /* Perform text mode translation if required. */
8225 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8227 char * tmpbuf = alloca (count * 2);
8228 unsigned char * src = (void *)buffer;
8229 unsigned char * dst = tmpbuf;
8230 int nbytes = count;
8232 while (1)
8234 unsigned char *next;
8235 /* copy next line or remaining bytes */
8236 next = _memccpy (dst, src, '\n', nbytes);
8237 if (next)
8239 /* copied one line ending with '\n' */
8240 int copied = next - dst;
8241 nbytes -= copied;
8242 src += copied;
8243 /* insert '\r' before '\n' */
8244 next[-1] = '\r';
8245 next[0] = '\n';
8246 dst = next + 1;
8247 count++;
8249 else
8250 /* copied remaining partial line -> now finished */
8251 break;
8253 buffer = tmpbuf;
8257 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8259 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8260 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8261 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8262 DWORD active = 0;
8264 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8266 if (GetLastError () != ERROR_IO_PENDING)
8268 errno = EIO;
8269 return -1;
8271 if (detect_input_pending ())
8272 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
8273 QS_ALLINPUT);
8274 else
8275 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8276 if (active == WAIT_OBJECT_0)
8277 { /* User pressed C-g, cancel write, then leave. Don't bother
8278 cleaning up as we may only get stuck in buggy drivers. */
8279 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8280 CancelIo (hnd);
8281 errno = EIO;
8282 return -1;
8284 if (active == WAIT_OBJECT_0 + 1
8285 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8287 errno = EIO;
8288 return -1;
8292 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8294 unsigned long nblock = 0;
8295 if (winsock_lib == NULL) emacs_abort ();
8297 /* TODO: implement select() properly so non-blocking I/O works. */
8298 /* For now, make sure the write blocks. */
8299 if (fd_info[fd].flags & FILE_NDELAY)
8300 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8302 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
8304 /* Set the socket back to non-blocking if it was before,
8305 for other operations that support it. */
8306 if (fd_info[fd].flags & FILE_NDELAY)
8308 nblock = 1;
8309 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8312 if (nchars == SOCKET_ERROR)
8314 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
8315 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8316 set_errno ();
8319 else
8321 /* Some networked filesystems don't like too large writes, so
8322 break them into smaller chunks. See the Comments section of
8323 the MSDN documentation of WriteFile for details behind the
8324 choice of the value of CHUNK below. See also the thread
8325 http://thread.gmane.org/gmane.comp.version-control.git/145294
8326 in the git mailing list. */
8327 const unsigned char *p = buffer;
8328 const unsigned chunk = 30 * 1024 * 1024;
8330 nchars = 0;
8331 while (count > 0)
8333 unsigned this_chunk = count < chunk ? count : chunk;
8334 int n = _write (fd, p, this_chunk);
8336 nchars += n;
8337 if (n < 0)
8339 nchars = n;
8340 break;
8342 else if (n < this_chunk)
8343 break;
8344 count -= n;
8345 p += n;
8349 return nchars;
8353 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
8355 extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
8357 /* Return information about network interface IFNAME, or about all
8358 interfaces (if IFNAME is nil). */
8359 static Lisp_Object
8360 network_interface_get_info (Lisp_Object ifname)
8362 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
8363 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
8364 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
8365 Lisp_Object res = Qnil;
8367 if (retval == ERROR_BUFFER_OVERFLOW)
8369 ainfo = xrealloc (ainfo, ainfo_len);
8370 retval = get_adapters_info (ainfo, &ainfo_len);
8373 if (retval == ERROR_SUCCESS)
8375 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
8376 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
8377 int if_num;
8378 struct sockaddr_in sa;
8380 /* For the below, we need some winsock functions, so make sure
8381 the winsock DLL is loaded. If we cannot successfully load
8382 it, they will have no use of the information we provide,
8383 anyway, so punt. */
8384 if (!winsock_lib && !init_winsock (1))
8385 goto done;
8387 for (adapter = ainfo; adapter; adapter = adapter->Next)
8389 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
8390 u_long ip_addr;
8391 /* Present Unix-compatible interface names, instead of the
8392 Windows names, which are really GUIDs not readable by
8393 humans. */
8394 static const char *ifmt[] = {
8395 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
8396 "lo", "ifx%d"
8398 enum {
8399 NONE = -1,
8400 ETHERNET = 0,
8401 TOKENRING = 1,
8402 FDDI = 2,
8403 PPP = 3,
8404 SLIP = 4,
8405 WLAN = 5,
8406 LOOPBACK = 6,
8407 OTHER_IF = 7
8408 } ifmt_idx;
8410 switch (adapter->Type)
8412 case MIB_IF_TYPE_ETHERNET:
8413 /* Windows before Vista reports wireless adapters as
8414 Ethernet. Work around by looking at the Description
8415 string. */
8416 if (strstr (adapter->Description, "Wireless "))
8418 ifmt_idx = WLAN;
8419 if_num = wlan_count++;
8421 else
8423 ifmt_idx = ETHERNET;
8424 if_num = eth_count++;
8426 break;
8427 case MIB_IF_TYPE_TOKENRING:
8428 ifmt_idx = TOKENRING;
8429 if_num = tr_count++;
8430 break;
8431 case MIB_IF_TYPE_FDDI:
8432 ifmt_idx = FDDI;
8433 if_num = fddi_count++;
8434 break;
8435 case MIB_IF_TYPE_PPP:
8436 ifmt_idx = PPP;
8437 if_num = ppp_count++;
8438 break;
8439 case MIB_IF_TYPE_SLIP:
8440 ifmt_idx = SLIP;
8441 if_num = sl_count++;
8442 break;
8443 case IF_TYPE_IEEE80211:
8444 ifmt_idx = WLAN;
8445 if_num = wlan_count++;
8446 break;
8447 case MIB_IF_TYPE_LOOPBACK:
8448 if (lo_count < 0)
8450 ifmt_idx = LOOPBACK;
8451 if_num = lo_count++;
8453 else
8454 ifmt_idx = NONE;
8455 break;
8456 default:
8457 ifmt_idx = OTHER_IF;
8458 if_num = ifx_count++;
8459 break;
8461 if (ifmt_idx == NONE)
8462 continue;
8463 sprintf (namebuf, ifmt[ifmt_idx], if_num);
8465 sa.sin_family = AF_INET;
8466 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
8467 if (ip_addr == INADDR_NONE)
8469 /* Bogus address, skip this interface. */
8470 continue;
8472 sa.sin_addr.s_addr = ip_addr;
8473 sa.sin_port = 0;
8474 if (NILP (ifname))
8475 res = Fcons (Fcons (build_string (namebuf),
8476 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
8477 sizeof (struct sockaddr))),
8478 res);
8479 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
8481 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
8482 register struct Lisp_Vector *p = XVECTOR (hwaddr);
8483 Lisp_Object flags = Qnil;
8484 int n;
8485 u_long net_mask;
8487 /* Flags. We guess most of them by type, since the
8488 Windows flags are different and hard to get by. */
8489 flags = Fcons (intern ("up"), flags);
8490 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
8492 flags = Fcons (intern ("broadcast"), flags);
8493 flags = Fcons (intern ("multicast"), flags);
8495 flags = Fcons (intern ("running"), flags);
8496 if (ifmt_idx == PPP)
8498 flags = Fcons (intern ("pointopoint"), flags);
8499 flags = Fcons (intern ("noarp"), flags);
8501 if (adapter->HaveWins)
8502 flags = Fcons (intern ("WINS"), flags);
8503 if (adapter->DhcpEnabled)
8504 flags = Fcons (intern ("dynamic"), flags);
8506 res = Fcons (flags, res);
8508 /* Hardware address and its family. */
8509 for (n = 0; n < adapter->AddressLength; n++)
8510 p->contents[n] = make_number ((int) adapter->Address[n]);
8511 /* Windows does not support AF_LINK or AF_PACKET family
8512 of addresses. Use an arbitrary family number that is
8513 identical to what GNU/Linux returns. */
8514 res = Fcons (Fcons (make_number (1), hwaddr), res);
8516 /* Network mask. */
8517 sa.sin_family = AF_INET;
8518 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
8519 if (net_mask != INADDR_NONE)
8521 sa.sin_addr.s_addr = net_mask;
8522 sa.sin_port = 0;
8523 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8524 sizeof (struct sockaddr)),
8525 res);
8527 else
8528 res = Fcons (Qnil, res);
8530 sa.sin_family = AF_INET;
8531 if (ip_addr != INADDR_NONE)
8533 /* Broadcast address is only reported by
8534 GetAdaptersAddresses, which is of limited
8535 availability. Generate it on our own. */
8536 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
8538 sa.sin_addr.s_addr = bcast_addr;
8539 sa.sin_port = 0;
8540 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8541 sizeof (struct sockaddr)),
8542 res);
8544 /* IP address. */
8545 sa.sin_addr.s_addr = ip_addr;
8546 sa.sin_port = 0;
8547 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8548 sizeof (struct sockaddr)),
8549 res);
8551 else
8552 res = Fcons (Qnil, Fcons (Qnil, res));
8555 /* GetAdaptersInfo is documented to not report loopback
8556 interfaces, so we generate one out of thin air. */
8557 if (!lo_count)
8559 sa.sin_family = AF_INET;
8560 sa.sin_port = 0;
8561 if (NILP (ifname))
8563 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
8564 res = Fcons (Fcons (build_string ("lo"),
8565 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
8566 sizeof (struct sockaddr))),
8567 res);
8569 else if (strcmp (SSDATA (ifname), "lo") == 0)
8571 res = Fcons (Fcons (intern ("running"),
8572 Fcons (intern ("loopback"),
8573 Fcons (intern ("up"), Qnil))), Qnil);
8574 /* 772 is what 3 different GNU/Linux systems report for
8575 the loopback interface. */
8576 res = Fcons (Fcons (make_number (772),
8577 Fmake_vector (make_number (6),
8578 make_number (0))),
8579 res);
8580 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
8581 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8582 sizeof (struct sockaddr)),
8583 res);
8584 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
8585 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8586 sizeof (struct sockaddr)),
8587 res);
8588 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
8589 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8590 sizeof (struct sockaddr)),
8591 res);
8597 done:
8598 xfree (ainfo);
8599 return res;
8602 Lisp_Object
8603 network_interface_list (void)
8605 return network_interface_get_info (Qnil);
8608 Lisp_Object
8609 network_interface_info (Lisp_Object ifname)
8611 return network_interface_get_info (ifname);
8615 /* The Windows CRT functions are "optimized for speed", so they don't
8616 check for timezone and DST changes if they were last called less
8617 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
8618 all Emacs features that repeatedly call time functions (e.g.,
8619 display-time) are in real danger of missing timezone and DST
8620 changes. Calling tzset before each localtime call fixes that. */
8621 struct tm *
8622 sys_localtime (const time_t *t)
8624 tzset ();
8625 return localtime (t);
8630 /* Try loading LIBRARY_ID from the file(s) specified in
8631 Vdynamic_library_alist. If the library is loaded successfully,
8632 return the handle of the DLL, and record the filename in the
8633 property :loaded-from of LIBRARY_ID. If the library could not be
8634 found, or when it was already loaded (because the handle is not
8635 recorded anywhere, and so is lost after use), return NULL.
8637 We could also save the handle in :loaded-from, but currently
8638 there's no use case for it. */
8639 HMODULE
8640 w32_delayed_load (Lisp_Object library_id)
8642 HMODULE dll_handle = NULL;
8644 CHECK_SYMBOL (library_id);
8646 if (CONSP (Vdynamic_library_alist)
8647 && NILP (Fassq (library_id, Vlibrary_cache)))
8649 Lisp_Object found = Qnil;
8650 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
8652 if (CONSP (dlls))
8653 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
8655 Lisp_Object dll = XCAR (dlls);
8656 char name[MAX_UTF8_PATH];
8657 DWORD res = -1;
8659 CHECK_STRING (dll);
8660 dll = ENCODE_FILE (dll);
8661 if (w32_unicode_filenames)
8663 wchar_t name_w[MAX_PATH];
8665 filename_to_utf16 (SSDATA (dll), name_w);
8666 dll_handle = LoadLibraryW (name_w);
8667 if (dll_handle)
8669 res = GetModuleFileNameW (dll_handle, name_w,
8670 sizeof (name_w));
8671 if (res > 0)
8672 filename_from_utf16 (name_w, name);
8675 else
8677 char name_a[MAX_PATH];
8679 filename_to_ansi (SSDATA (dll), name_a);
8680 dll_handle = LoadLibraryA (name_a);
8681 if (dll_handle)
8683 res = GetModuleFileNameA (dll_handle, name_a,
8684 sizeof (name_a));
8685 if (res > 0)
8686 filename_from_ansi (name_a, name);
8689 if (dll_handle)
8691 ptrdiff_t len = strlen (name);
8692 found = Fcons (dll,
8693 (res > 0)
8694 /* Possibly truncated */
8695 ? make_specified_string (name, -1, len, 1)
8696 : Qnil);
8697 break;
8701 Fput (library_id, QCloaded_from, found);
8704 return dll_handle;
8708 void
8709 check_windows_init_file (void)
8711 /* A common indication that Emacs is not installed properly is when
8712 it cannot find the Windows installation file. If this file does
8713 not exist in the expected place, tell the user. */
8715 if (!noninteractive && !inhibit_window_system
8716 /* Vload_path is not yet initialized when we are loading
8717 loadup.el. */
8718 && NILP (Vpurify_flag))
8720 Lisp_Object init_file;
8721 int fd;
8723 /* Implementation note: this function runs early during Emacs
8724 startup, before startup.el is run. So Vload_path is still in
8725 its initial unibyte form, but it holds UTF-8 encoded file
8726 names, since init_callproc was already called. So we do not
8727 need to ENCODE_FILE here, but we do need to convert the file
8728 names from UTF-8 to ANSI. */
8729 init_file = build_string ("term/w32-win");
8730 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
8731 if (fd < 0)
8733 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
8734 char *init_file_name = SDATA (init_file);
8735 char *load_path = SDATA (load_path_print);
8736 char *buffer = alloca (1024
8737 + strlen (init_file_name)
8738 + strlen (load_path));
8739 char *msg = buffer;
8740 int needed;
8742 sprintf (buffer,
8743 "The Emacs Windows initialization file \"%s.el\" "
8744 "could not be found in your Emacs installation. "
8745 "Emacs checked the following directories for this file:\n"
8746 "\n%s\n\n"
8747 "When Emacs cannot find this file, it usually means that it "
8748 "was not installed properly, or its distribution file was "
8749 "not unpacked properly.\nSee the README.W32 file in the "
8750 "top-level Emacs directory for more information.",
8751 init_file_name, load_path);
8752 needed = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
8753 -1, NULL, 0);
8754 if (needed > 0)
8756 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
8758 MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
8759 msg_w, needed);
8760 needed = WideCharToMultiByte (CP_ACP, 0, msg_w, -1,
8761 NULL, 0, NULL, NULL);
8762 if (needed > 0)
8764 char *msg_a = alloca (needed + 1);
8766 WideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
8767 NULL, NULL);
8768 msg = msg_a;
8771 MessageBox (NULL,
8772 msg,
8773 "Emacs Abort Dialog",
8774 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
8775 /* Use the low-level system abort. */
8776 abort ();
8778 else
8780 _close (fd);
8785 void
8786 term_ntproc (int ignored)
8788 (void)ignored;
8790 term_timers ();
8792 /* shutdown the socket interface if necessary */
8793 term_winsock ();
8795 term_w32select ();
8798 void
8799 init_ntproc (int dumping)
8801 sigset_t initial_mask = 0;
8803 /* Initialize the socket interface now if available and requested by
8804 the user by defining PRELOAD_WINSOCK; otherwise loading will be
8805 delayed until open-network-stream is called (w32-has-winsock can
8806 also be used to dynamically load or reload winsock).
8808 Conveniently, init_environment is called before us, so
8809 PRELOAD_WINSOCK can be set in the registry. */
8811 /* Always initialize this correctly. */
8812 winsock_lib = NULL;
8814 if (getenv ("PRELOAD_WINSOCK") != NULL)
8815 init_winsock (TRUE);
8817 /* Initial preparation for subprocess support: replace our standard
8818 handles with non-inheritable versions. */
8820 HANDLE parent;
8821 HANDLE stdin_save = INVALID_HANDLE_VALUE;
8822 HANDLE stdout_save = INVALID_HANDLE_VALUE;
8823 HANDLE stderr_save = INVALID_HANDLE_VALUE;
8825 parent = GetCurrentProcess ();
8827 /* ignore errors when duplicating and closing; typically the
8828 handles will be invalid when running as a gui program. */
8829 DuplicateHandle (parent,
8830 GetStdHandle (STD_INPUT_HANDLE),
8831 parent,
8832 &stdin_save,
8834 FALSE,
8835 DUPLICATE_SAME_ACCESS);
8837 DuplicateHandle (parent,
8838 GetStdHandle (STD_OUTPUT_HANDLE),
8839 parent,
8840 &stdout_save,
8842 FALSE,
8843 DUPLICATE_SAME_ACCESS);
8845 DuplicateHandle (parent,
8846 GetStdHandle (STD_ERROR_HANDLE),
8847 parent,
8848 &stderr_save,
8850 FALSE,
8851 DUPLICATE_SAME_ACCESS);
8853 fclose (stdin);
8854 fclose (stdout);
8855 fclose (stderr);
8857 if (stdin_save != INVALID_HANDLE_VALUE)
8858 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
8859 else
8860 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
8861 _fdopen (0, "r");
8863 if (stdout_save != INVALID_HANDLE_VALUE)
8864 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
8865 else
8866 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8867 _fdopen (1, "w");
8869 if (stderr_save != INVALID_HANDLE_VALUE)
8870 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
8871 else
8872 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8873 _fdopen (2, "w");
8876 /* unfortunately, atexit depends on implementation of malloc */
8877 /* atexit (term_ntproc); */
8878 if (!dumping)
8880 /* Make sure we start with all signals unblocked. */
8881 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
8882 signal (SIGABRT, term_ntproc);
8884 init_timers ();
8886 /* determine which drives are fixed, for GetCachedVolumeInformation */
8888 /* GetDriveType must have trailing backslash. */
8889 char drive[] = "A:\\";
8891 /* Loop over all possible drive letters */
8892 while (*drive <= 'Z')
8894 /* Record if this drive letter refers to a fixed drive. */
8895 fixed_drives[DRIVE_INDEX (*drive)] =
8896 (GetDriveType (drive) == DRIVE_FIXED);
8898 (*drive)++;
8901 /* Reset the volume info cache. */
8902 volume_cache = NULL;
8907 shutdown_handler ensures that buffers' autosave files are
8908 up to date when the user logs off, or the system shuts down.
8910 static BOOL WINAPI
8911 shutdown_handler (DWORD type)
8913 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
8914 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
8915 || type == CTRL_LOGOFF_EVENT /* User logs off. */
8916 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
8918 /* Shut down cleanly, making sure autosave files are up to date. */
8919 shut_down_emacs (0, Qnil);
8922 /* Allow other handlers to handle this signal. */
8923 return FALSE;
8927 globals_of_w32 is used to initialize those global variables that
8928 must always be initialized on startup even when the global variable
8929 initialized is non zero (see the function main in emacs.c).
8931 void
8932 globals_of_w32 (void)
8934 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
8936 get_process_times_fn = (GetProcessTimes_Proc)
8937 GetProcAddress (kernel32, "GetProcessTimes");
8939 DEFSYM (QCloaded_from, ":loaded-from");
8941 g_b_init_is_windows_9x = 0;
8942 g_b_init_open_process_token = 0;
8943 g_b_init_get_token_information = 0;
8944 g_b_init_lookup_account_sid = 0;
8945 g_b_init_get_sid_sub_authority = 0;
8946 g_b_init_get_sid_sub_authority_count = 0;
8947 g_b_init_get_security_info = 0;
8948 g_b_init_get_file_security_w = 0;
8949 g_b_init_get_file_security_a = 0;
8950 g_b_init_get_security_descriptor_owner = 0;
8951 g_b_init_get_security_descriptor_group = 0;
8952 g_b_init_is_valid_sid = 0;
8953 g_b_init_create_toolhelp32_snapshot = 0;
8954 g_b_init_process32_first = 0;
8955 g_b_init_process32_next = 0;
8956 g_b_init_open_thread_token = 0;
8957 g_b_init_impersonate_self = 0;
8958 g_b_init_revert_to_self = 0;
8959 g_b_init_get_process_memory_info = 0;
8960 g_b_init_get_process_working_set_size = 0;
8961 g_b_init_global_memory_status = 0;
8962 g_b_init_global_memory_status_ex = 0;
8963 g_b_init_equal_sid = 0;
8964 g_b_init_copy_sid = 0;
8965 g_b_init_get_length_sid = 0;
8966 g_b_init_get_native_system_info = 0;
8967 g_b_init_get_system_times = 0;
8968 g_b_init_create_symbolic_link_w = 0;
8969 g_b_init_create_symbolic_link_a = 0;
8970 g_b_init_get_security_descriptor_dacl = 0;
8971 g_b_init_convert_sd_to_sddl = 0;
8972 g_b_init_convert_sddl_to_sd = 0;
8973 g_b_init_is_valid_security_descriptor = 0;
8974 g_b_init_set_file_security_w = 0;
8975 g_b_init_set_file_security_a = 0;
8976 g_b_init_set_named_security_info_w = 0;
8977 g_b_init_set_named_security_info_a = 0;
8978 g_b_init_get_adapters_info = 0;
8979 num_of_processors = 0;
8980 /* The following sets a handler for shutdown notifications for
8981 console apps. This actually applies to Emacs in both console and
8982 GUI modes, since we had to fool windows into thinking emacs is a
8983 console application to get console mode to work. */
8984 SetConsoleCtrlHandler (shutdown_handler, TRUE);
8986 /* "None" is the default group name on standalone workstations. */
8987 strcpy (dflt_group_name, "None");
8989 /* Reset, in case it has some value inherited from dump time. */
8990 w32_stat_get_owner_group = 0;
8992 /* If w32_unicode_filenames is non-zero, we will be using Unicode
8993 (a.k.a. "wide") APIs to invoke functions that accept file
8994 names. */
8995 if (is_windows_9x ())
8996 w32_unicode_filenames = 0;
8997 else
8998 w32_unicode_filenames = 1;
9001 /* For make-serial-process */
9003 serial_open (Lisp_Object port_obj)
9005 char *port = SSDATA (port_obj);
9006 HANDLE hnd;
9007 child_process *cp;
9008 int fd = -1;
9010 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
9011 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
9012 if (hnd == INVALID_HANDLE_VALUE)
9013 error ("Could not open %s", port);
9014 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
9015 if (fd == -1)
9016 error ("Could not open %s", port);
9018 cp = new_child ();
9019 if (!cp)
9020 error ("Could not create child process");
9021 cp->fd = fd;
9022 cp->status = STATUS_READ_ACKNOWLEDGED;
9023 fd_info[ fd ].hnd = hnd;
9024 fd_info[ fd ].flags |=
9025 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
9026 if (fd_info[ fd ].cp != NULL)
9028 error ("fd_info[fd = %d] is already in use", fd);
9030 fd_info[ fd ].cp = cp;
9031 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9032 if (cp->ovl_read.hEvent == NULL)
9033 error ("Could not create read event");
9034 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9035 if (cp->ovl_write.hEvent == NULL)
9036 error ("Could not create write event");
9038 return fd;
9041 /* For serial-process-configure */
9042 void
9043 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
9045 Lisp_Object childp2 = Qnil;
9046 Lisp_Object tem = Qnil;
9047 HANDLE hnd;
9048 DCB dcb;
9049 COMMTIMEOUTS ct;
9050 char summary[4] = "???"; /* This usually becomes "8N1". */
9052 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
9053 error ("Not a serial process");
9054 hnd = fd_info[ p->outfd ].hnd;
9056 childp2 = Fcopy_sequence (p->childp);
9058 /* Initialize timeouts for blocking read and blocking write. */
9059 if (!GetCommTimeouts (hnd, &ct))
9060 error ("GetCommTimeouts() failed");
9061 ct.ReadIntervalTimeout = 0;
9062 ct.ReadTotalTimeoutMultiplier = 0;
9063 ct.ReadTotalTimeoutConstant = 0;
9064 ct.WriteTotalTimeoutMultiplier = 0;
9065 ct.WriteTotalTimeoutConstant = 0;
9066 if (!SetCommTimeouts (hnd, &ct))
9067 error ("SetCommTimeouts() failed");
9068 /* Read port attributes and prepare default configuration. */
9069 memset (&dcb, 0, sizeof (dcb));
9070 dcb.DCBlength = sizeof (DCB);
9071 if (!GetCommState (hnd, &dcb))
9072 error ("GetCommState() failed");
9073 dcb.fBinary = TRUE;
9074 dcb.fNull = FALSE;
9075 dcb.fAbortOnError = FALSE;
9076 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
9077 dcb.ErrorChar = 0;
9078 dcb.EofChar = 0;
9079 dcb.EvtChar = 0;
9081 /* Configure speed. */
9082 if (!NILP (Fplist_member (contact, QCspeed)))
9083 tem = Fplist_get (contact, QCspeed);
9084 else
9085 tem = Fplist_get (p->childp, QCspeed);
9086 CHECK_NUMBER (tem);
9087 dcb.BaudRate = XINT (tem);
9088 childp2 = Fplist_put (childp2, QCspeed, tem);
9090 /* Configure bytesize. */
9091 if (!NILP (Fplist_member (contact, QCbytesize)))
9092 tem = Fplist_get (contact, QCbytesize);
9093 else
9094 tem = Fplist_get (p->childp, QCbytesize);
9095 if (NILP (tem))
9096 tem = make_number (8);
9097 CHECK_NUMBER (tem);
9098 if (XINT (tem) != 7 && XINT (tem) != 8)
9099 error (":bytesize must be nil (8), 7, or 8");
9100 dcb.ByteSize = XINT (tem);
9101 summary[0] = XINT (tem) + '0';
9102 childp2 = Fplist_put (childp2, QCbytesize, tem);
9104 /* Configure parity. */
9105 if (!NILP (Fplist_member (contact, QCparity)))
9106 tem = Fplist_get (contact, QCparity);
9107 else
9108 tem = Fplist_get (p->childp, QCparity);
9109 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
9110 error (":parity must be nil (no parity), `even', or `odd'");
9111 dcb.fParity = FALSE;
9112 dcb.Parity = NOPARITY;
9113 dcb.fErrorChar = FALSE;
9114 if (NILP (tem))
9116 summary[1] = 'N';
9118 else if (EQ (tem, Qeven))
9120 summary[1] = 'E';
9121 dcb.fParity = TRUE;
9122 dcb.Parity = EVENPARITY;
9123 dcb.fErrorChar = TRUE;
9125 else if (EQ (tem, Qodd))
9127 summary[1] = 'O';
9128 dcb.fParity = TRUE;
9129 dcb.Parity = ODDPARITY;
9130 dcb.fErrorChar = TRUE;
9132 childp2 = Fplist_put (childp2, QCparity, tem);
9134 /* Configure stopbits. */
9135 if (!NILP (Fplist_member (contact, QCstopbits)))
9136 tem = Fplist_get (contact, QCstopbits);
9137 else
9138 tem = Fplist_get (p->childp, QCstopbits);
9139 if (NILP (tem))
9140 tem = make_number (1);
9141 CHECK_NUMBER (tem);
9142 if (XINT (tem) != 1 && XINT (tem) != 2)
9143 error (":stopbits must be nil (1 stopbit), 1, or 2");
9144 summary[2] = XINT (tem) + '0';
9145 if (XINT (tem) == 1)
9146 dcb.StopBits = ONESTOPBIT;
9147 else if (XINT (tem) == 2)
9148 dcb.StopBits = TWOSTOPBITS;
9149 childp2 = Fplist_put (childp2, QCstopbits, tem);
9151 /* Configure flowcontrol. */
9152 if (!NILP (Fplist_member (contact, QCflowcontrol)))
9153 tem = Fplist_get (contact, QCflowcontrol);
9154 else
9155 tem = Fplist_get (p->childp, QCflowcontrol);
9156 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
9157 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
9158 dcb.fOutxCtsFlow = FALSE;
9159 dcb.fOutxDsrFlow = FALSE;
9160 dcb.fDtrControl = DTR_CONTROL_DISABLE;
9161 dcb.fDsrSensitivity = FALSE;
9162 dcb.fTXContinueOnXoff = FALSE;
9163 dcb.fOutX = FALSE;
9164 dcb.fInX = FALSE;
9165 dcb.fRtsControl = RTS_CONTROL_DISABLE;
9166 dcb.XonChar = 17; /* Control-Q */
9167 dcb.XoffChar = 19; /* Control-S */
9168 if (NILP (tem))
9170 /* Already configured. */
9172 else if (EQ (tem, Qhw))
9174 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
9175 dcb.fOutxCtsFlow = TRUE;
9177 else if (EQ (tem, Qsw))
9179 dcb.fOutX = TRUE;
9180 dcb.fInX = TRUE;
9182 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
9184 /* Activate configuration. */
9185 if (!SetCommState (hnd, &dcb))
9186 error ("SetCommState() failed");
9188 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
9189 pset_childp (p, childp2);
9192 #ifdef HAVE_GNUTLS
9194 ssize_t
9195 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
9197 int n, err;
9198 SELECT_TYPE fdset;
9199 struct timespec timeout;
9200 struct Lisp_Process *process = (struct Lisp_Process *)p;
9201 int fd = process->infd;
9203 n = sys_read (fd, (char*)buf, sz);
9205 if (n >= 0)
9206 return n;
9208 err = errno;
9210 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9211 if (err == EWOULDBLOCK)
9212 err = EAGAIN;
9214 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
9216 return -1;
9219 ssize_t
9220 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
9222 struct Lisp_Process *process = (struct Lisp_Process *)p;
9223 int fd = process->outfd;
9224 ssize_t n = sys_write (fd, buf, sz);
9226 /* 0 or more bytes written means everything went fine. */
9227 if (n >= 0)
9228 return n;
9230 /* Negative bytes written means we got an error in errno.
9231 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9232 emacs_gnutls_transport_set_errno (process->gnutls_state,
9233 errno == EWOULDBLOCK ? EAGAIN : errno);
9235 return -1;
9237 #endif /* HAVE_GNUTLS */
9239 /* end of w32.c */