* lisp/emacs-lisp/easy-mmode.el (define-minor-mode): Use mode function
[emacs.git] / src / w32.c
blob25549d79d7fea56414a4ffb73eb23be57fcb95a8
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 #ifndef _ANONYMOUS_UNION
77 # define _ANONYMOUS_UNION
78 #endif
79 #ifndef _ANONYMOUS_STRUCT
80 # define _ANONYMOUS_STRUCT
81 #endif
82 #include <windows.h>
83 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
84 use a different name to avoid compilation problems. */
85 typedef struct _MEMORY_STATUS_EX {
86 DWORD dwLength;
87 DWORD dwMemoryLoad;
88 DWORDLONG ullTotalPhys;
89 DWORDLONG ullAvailPhys;
90 DWORDLONG ullTotalPageFile;
91 DWORDLONG ullAvailPageFile;
92 DWORDLONG ullTotalVirtual;
93 DWORDLONG ullAvailVirtual;
94 DWORDLONG ullAvailExtendedVirtual;
95 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
97 /* These are here so that GDB would know about these data types. This
98 allows to attach GDB to Emacs when a fatal exception is triggered
99 and Windows pops up the "application needs to be closed" dialog.
100 At that point, _gnu_exception_handler, the top-level exception
101 handler installed by the MinGW startup code, is somewhere on the
102 call-stack of the main thread, so going to that call frame and
103 looking at the argument to _gnu_exception_handler, which is a
104 PEXCEPTION_POINTERS pointer, can reveal the exception code
105 (excptr->ExceptionRecord->ExceptionCode) and the address where the
106 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
107 well as some additional information specific to the exception. */
108 PEXCEPTION_POINTERS excptr;
109 PEXCEPTION_RECORD excprec;
110 PCONTEXT ctxrec;
112 #include <lmcons.h>
113 #include <shlobj.h>
115 #include <tlhelp32.h>
116 #include <psapi.h>
117 #ifndef _MSC_VER
118 #include <w32api.h>
119 #endif
120 #if _WIN32_WINNT < 0x0500
121 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
122 /* This either is not in psapi.h or guarded by higher value of
123 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
124 defines it in psapi.h */
125 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
126 DWORD cb;
127 DWORD PageFaultCount;
128 SIZE_T PeakWorkingSetSize;
129 SIZE_T WorkingSetSize;
130 SIZE_T QuotaPeakPagedPoolUsage;
131 SIZE_T QuotaPagedPoolUsage;
132 SIZE_T QuotaPeakNonPagedPoolUsage;
133 SIZE_T QuotaNonPagedPoolUsage;
134 SIZE_T PagefileUsage;
135 SIZE_T PeakPagefileUsage;
136 SIZE_T PrivateUsage;
137 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
138 #endif
139 #endif
141 #include <winioctl.h>
142 #include <aclapi.h>
143 #include <sddl.h>
145 #include <sys/acl.h>
146 #include <acl.h>
148 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
149 define them by hand if not already defined. */
150 #ifndef SDDL_REVISION_1
151 #define SDDL_REVISION_1 1
152 #endif /* SDDL_REVISION_1 */
154 #if defined(_MSC_VER) || defined(_W64)
155 /* MSVC and MinGW64 don't provide the definition of
156 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
157 which cannot be included because it triggers conflicts with other
158 Windows API headers. So we define it here by hand. */
160 typedef struct _REPARSE_DATA_BUFFER {
161 ULONG ReparseTag;
162 USHORT ReparseDataLength;
163 USHORT Reserved;
164 union {
165 struct {
166 USHORT SubstituteNameOffset;
167 USHORT SubstituteNameLength;
168 USHORT PrintNameOffset;
169 USHORT PrintNameLength;
170 ULONG Flags;
171 WCHAR PathBuffer[1];
172 } SymbolicLinkReparseBuffer;
173 struct {
174 USHORT SubstituteNameOffset;
175 USHORT SubstituteNameLength;
176 USHORT PrintNameOffset;
177 USHORT PrintNameLength;
178 WCHAR PathBuffer[1];
179 } MountPointReparseBuffer;
180 struct {
181 UCHAR DataBuffer[1];
182 } GenericReparseBuffer;
183 } DUMMYUNIONNAME;
184 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
186 #ifndef FILE_DEVICE_FILE_SYSTEM
187 #define FILE_DEVICE_FILE_SYSTEM 9
188 #endif
189 #ifndef METHOD_BUFFERED
190 #define METHOD_BUFFERED 0
191 #endif
192 #ifndef FILE_ANY_ACCESS
193 #define FILE_ANY_ACCESS 0x00000000
194 #endif
195 #ifndef CTL_CODE
196 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
197 #endif
198 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
199 #ifndef FSCTL_GET_REPARSE_POINT
200 #define FSCTL_GET_REPARSE_POINT \
201 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
202 #endif
203 #endif
205 /* TCP connection support. */
206 #include <sys/socket.h>
207 #undef socket
208 #undef bind
209 #undef connect
210 #undef htons
211 #undef ntohs
212 #undef inet_addr
213 #undef gethostname
214 #undef gethostbyname
215 #undef getservbyname
216 #undef getpeername
217 #undef shutdown
218 #undef setsockopt
219 #undef listen
220 #undef getsockname
221 #undef accept
222 #undef recvfrom
223 #undef sendto
225 #include <iphlpapi.h> /* should be after winsock2.h */
227 #include "w32.h"
228 #include <dirent.h>
229 #include "w32common.h"
230 #include "w32heap.h"
231 #include "w32select.h"
232 #include "systime.h"
233 #include "dispextern.h" /* for xstrcasecmp */
234 #include "coding.h" /* for Vlocale_coding_system */
236 #include "careadlinkat.h"
237 #include "allocator.h"
239 /* For serial_configure and serial_open. */
240 #include "process.h"
242 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
243 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
245 Lisp_Object QCloaded_from;
247 void globals_of_w32 (void);
248 static DWORD get_rid (PSID);
249 static int is_symlink (const char *);
250 static char * chase_symlinks (const char *);
251 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
252 static int restore_privilege (TOKEN_PRIVILEGES *);
253 static BOOL WINAPI revert_to_self (void);
255 static int sys_access (const char *, int);
256 extern void *e_malloc (size_t);
257 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
258 struct timespec *, void *);
259 extern int sys_dup (int);
264 /* Initialization states.
266 WARNING: If you add any more such variables for additional APIs,
267 you MUST add initialization for them to globals_of_w32
268 below. This is because these variables might get set
269 to non-NULL values during dumping, but the dumped Emacs
270 cannot reuse those values, because it could be run on a
271 different version of the OS, where API addresses are
272 different. */
273 static BOOL g_b_init_is_windows_9x;
274 static BOOL g_b_init_open_process_token;
275 static BOOL g_b_init_get_token_information;
276 static BOOL g_b_init_lookup_account_sid;
277 static BOOL g_b_init_get_sid_sub_authority;
278 static BOOL g_b_init_get_sid_sub_authority_count;
279 static BOOL g_b_init_get_security_info;
280 static BOOL g_b_init_get_file_security_w;
281 static BOOL g_b_init_get_file_security_a;
282 static BOOL g_b_init_get_security_descriptor_owner;
283 static BOOL g_b_init_get_security_descriptor_group;
284 static BOOL g_b_init_is_valid_sid;
285 static BOOL g_b_init_create_toolhelp32_snapshot;
286 static BOOL g_b_init_process32_first;
287 static BOOL g_b_init_process32_next;
288 static BOOL g_b_init_open_thread_token;
289 static BOOL g_b_init_impersonate_self;
290 static BOOL g_b_init_revert_to_self;
291 static BOOL g_b_init_get_process_memory_info;
292 static BOOL g_b_init_get_process_working_set_size;
293 static BOOL g_b_init_global_memory_status;
294 static BOOL g_b_init_global_memory_status_ex;
295 static BOOL g_b_init_get_length_sid;
296 static BOOL g_b_init_equal_sid;
297 static BOOL g_b_init_copy_sid;
298 static BOOL g_b_init_get_native_system_info;
299 static BOOL g_b_init_get_system_times;
300 static BOOL g_b_init_create_symbolic_link_w;
301 static BOOL g_b_init_create_symbolic_link_a;
302 static BOOL g_b_init_get_security_descriptor_dacl;
303 static BOOL g_b_init_convert_sd_to_sddl;
304 static BOOL g_b_init_convert_sddl_to_sd;
305 static BOOL g_b_init_is_valid_security_descriptor;
306 static BOOL g_b_init_set_file_security_w;
307 static BOOL g_b_init_set_file_security_a;
308 static BOOL g_b_init_set_named_security_info_w;
309 static BOOL g_b_init_set_named_security_info_a;
310 static BOOL g_b_init_get_adapters_info;
312 BOOL g_b_init_compare_string_w;
315 BEGIN: Wrapper functions around OpenProcessToken
316 and other functions in advapi32.dll that are only
317 supported in Windows NT / 2k / XP
319 /* ** Function pointer typedefs ** */
320 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
321 HANDLE ProcessHandle,
322 DWORD DesiredAccess,
323 PHANDLE TokenHandle);
324 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
325 HANDLE TokenHandle,
326 TOKEN_INFORMATION_CLASS TokenInformationClass,
327 LPVOID TokenInformation,
328 DWORD TokenInformationLength,
329 PDWORD ReturnLength);
330 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
331 HANDLE process_handle,
332 LPFILETIME creation_time,
333 LPFILETIME exit_time,
334 LPFILETIME kernel_time,
335 LPFILETIME user_time);
337 GetProcessTimes_Proc get_process_times_fn = NULL;
339 #ifdef _UNICODE
340 const char * const LookupAccountSid_Name = "LookupAccountSidW";
341 #else
342 const char * const LookupAccountSid_Name = "LookupAccountSidA";
343 #endif
344 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
345 LPCTSTR lpSystemName,
346 PSID Sid,
347 LPTSTR Name,
348 LPDWORD cbName,
349 LPTSTR DomainName,
350 LPDWORD cbDomainName,
351 PSID_NAME_USE peUse);
352 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
353 PSID pSid,
354 DWORD n);
355 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
356 PSID pSid);
357 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
358 HANDLE handle,
359 SE_OBJECT_TYPE ObjectType,
360 SECURITY_INFORMATION SecurityInfo,
361 PSID *ppsidOwner,
362 PSID *ppsidGroup,
363 PACL *ppDacl,
364 PACL *ppSacl,
365 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
366 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
367 LPCWSTR lpFileName,
368 SECURITY_INFORMATION RequestedInformation,
369 PSECURITY_DESCRIPTOR pSecurityDescriptor,
370 DWORD nLength,
371 LPDWORD lpnLengthNeeded);
372 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
373 LPCSTR lpFileName,
374 SECURITY_INFORMATION RequestedInformation,
375 PSECURITY_DESCRIPTOR pSecurityDescriptor,
376 DWORD nLength,
377 LPDWORD lpnLengthNeeded);
378 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
379 LPCWSTR lpFileName,
380 SECURITY_INFORMATION SecurityInformation,
381 PSECURITY_DESCRIPTOR pSecurityDescriptor);
382 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
383 LPCSTR lpFileName,
384 SECURITY_INFORMATION SecurityInformation,
385 PSECURITY_DESCRIPTOR pSecurityDescriptor);
386 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
387 LPCWSTR lpObjectName,
388 SE_OBJECT_TYPE ObjectType,
389 SECURITY_INFORMATION SecurityInformation,
390 PSID psidOwner,
391 PSID psidGroup,
392 PACL pDacl,
393 PACL pSacl);
394 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
395 LPCSTR lpObjectName,
396 SE_OBJECT_TYPE ObjectType,
397 SECURITY_INFORMATION SecurityInformation,
398 PSID psidOwner,
399 PSID psidGroup,
400 PACL pDacl,
401 PACL pSacl);
402 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
403 PSECURITY_DESCRIPTOR pSecurityDescriptor,
404 PSID *pOwner,
405 LPBOOL lpbOwnerDefaulted);
406 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
407 PSECURITY_DESCRIPTOR pSecurityDescriptor,
408 PSID *pGroup,
409 LPBOOL lpbGroupDefaulted);
410 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
411 PSECURITY_DESCRIPTOR pSecurityDescriptor,
412 LPBOOL lpbDaclPresent,
413 PACL *pDacl,
414 LPBOOL lpbDaclDefaulted);
415 typedef BOOL (WINAPI * IsValidSid_Proc) (
416 PSID sid);
417 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
418 DWORD dwFlags,
419 DWORD th32ProcessID);
420 typedef BOOL (WINAPI * Process32First_Proc) (
421 HANDLE hSnapshot,
422 LPPROCESSENTRY32 lppe);
423 typedef BOOL (WINAPI * Process32Next_Proc) (
424 HANDLE hSnapshot,
425 LPPROCESSENTRY32 lppe);
426 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
427 HANDLE ThreadHandle,
428 DWORD DesiredAccess,
429 BOOL OpenAsSelf,
430 PHANDLE TokenHandle);
431 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
432 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
433 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
434 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
435 HANDLE Process,
436 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
437 DWORD cb);
438 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
439 HANDLE hProcess,
440 PSIZE_T lpMinimumWorkingSetSize,
441 PSIZE_T lpMaximumWorkingSetSize);
442 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
443 LPMEMORYSTATUS lpBuffer);
444 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
445 LPMEMORY_STATUS_EX lpBuffer);
446 typedef BOOL (WINAPI * CopySid_Proc) (
447 DWORD nDestinationSidLength,
448 PSID pDestinationSid,
449 PSID pSourceSid);
450 typedef BOOL (WINAPI * EqualSid_Proc) (
451 PSID pSid1,
452 PSID pSid2);
453 typedef DWORD (WINAPI * GetLengthSid_Proc) (
454 PSID pSid);
455 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
456 LPSYSTEM_INFO lpSystemInfo);
457 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
458 LPFILETIME lpIdleTime,
459 LPFILETIME lpKernelTime,
460 LPFILETIME lpUserTime);
461 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
462 LPCWSTR lpSymlinkFileName,
463 LPCWSTR lpTargetFileName,
464 DWORD dwFlags);
465 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
466 LPCSTR lpSymlinkFileName,
467 LPCSTR lpTargetFileName,
468 DWORD dwFlags);
469 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
470 LPCTSTR StringSecurityDescriptor,
471 DWORD StringSDRevision,
472 PSECURITY_DESCRIPTOR *SecurityDescriptor,
473 PULONG SecurityDescriptorSize);
474 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
475 PSECURITY_DESCRIPTOR SecurityDescriptor,
476 DWORD RequestedStringSDRevision,
477 SECURITY_INFORMATION SecurityInformation,
478 LPTSTR *StringSecurityDescriptor,
479 PULONG StringSecurityDescriptorLen);
480 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
481 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
482 PIP_ADAPTER_INFO pAdapterInfo,
483 PULONG pOutBufLen);
485 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
486 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
488 /* ** A utility function ** */
489 static BOOL
490 is_windows_9x (void)
492 static BOOL s_b_ret = 0;
493 OSVERSIONINFO os_ver;
494 if (g_b_init_is_windows_9x == 0)
496 g_b_init_is_windows_9x = 1;
497 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
498 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
499 if (GetVersionEx (&os_ver))
501 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
504 return s_b_ret;
507 static Lisp_Object ltime (ULONGLONG);
509 /* Get total user and system times for get-internal-run-time.
510 Returns a list of integers if the times are provided by the OS
511 (NT derivatives), otherwise it returns the result of current-time. */
512 Lisp_Object
513 w32_get_internal_run_time (void)
515 if (get_process_times_fn)
517 FILETIME create, exit, kernel, user;
518 HANDLE proc = GetCurrentProcess ();
519 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
521 LARGE_INTEGER user_int, kernel_int, total;
522 user_int.LowPart = user.dwLowDateTime;
523 user_int.HighPart = user.dwHighDateTime;
524 kernel_int.LowPart = kernel.dwLowDateTime;
525 kernel_int.HighPart = kernel.dwHighDateTime;
526 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
527 return ltime (total.QuadPart);
531 return Fcurrent_time ();
534 /* ** The wrapper functions ** */
536 static BOOL WINAPI
537 open_process_token (HANDLE ProcessHandle,
538 DWORD DesiredAccess,
539 PHANDLE TokenHandle)
541 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
542 HMODULE hm_advapi32 = NULL;
543 if (is_windows_9x () == TRUE)
545 return FALSE;
547 if (g_b_init_open_process_token == 0)
549 g_b_init_open_process_token = 1;
550 hm_advapi32 = LoadLibrary ("Advapi32.dll");
551 s_pfn_Open_Process_Token =
552 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
554 if (s_pfn_Open_Process_Token == NULL)
556 return FALSE;
558 return (
559 s_pfn_Open_Process_Token (
560 ProcessHandle,
561 DesiredAccess,
562 TokenHandle)
566 static BOOL WINAPI
567 get_token_information (HANDLE TokenHandle,
568 TOKEN_INFORMATION_CLASS TokenInformationClass,
569 LPVOID TokenInformation,
570 DWORD TokenInformationLength,
571 PDWORD ReturnLength)
573 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
574 HMODULE hm_advapi32 = NULL;
575 if (is_windows_9x () == TRUE)
577 return FALSE;
579 if (g_b_init_get_token_information == 0)
581 g_b_init_get_token_information = 1;
582 hm_advapi32 = LoadLibrary ("Advapi32.dll");
583 s_pfn_Get_Token_Information =
584 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
586 if (s_pfn_Get_Token_Information == NULL)
588 return FALSE;
590 return (
591 s_pfn_Get_Token_Information (
592 TokenHandle,
593 TokenInformationClass,
594 TokenInformation,
595 TokenInformationLength,
596 ReturnLength)
600 static BOOL WINAPI
601 lookup_account_sid (LPCTSTR lpSystemName,
602 PSID Sid,
603 LPTSTR Name,
604 LPDWORD cbName,
605 LPTSTR DomainName,
606 LPDWORD cbDomainName,
607 PSID_NAME_USE peUse)
609 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
610 HMODULE hm_advapi32 = NULL;
611 if (is_windows_9x () == TRUE)
613 return FALSE;
615 if (g_b_init_lookup_account_sid == 0)
617 g_b_init_lookup_account_sid = 1;
618 hm_advapi32 = LoadLibrary ("Advapi32.dll");
619 s_pfn_Lookup_Account_Sid =
620 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
622 if (s_pfn_Lookup_Account_Sid == NULL)
624 return FALSE;
626 return (
627 s_pfn_Lookup_Account_Sid (
628 lpSystemName,
629 Sid,
630 Name,
631 cbName,
632 DomainName,
633 cbDomainName,
634 peUse)
638 static PDWORD WINAPI
639 get_sid_sub_authority (PSID pSid, DWORD n)
641 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
642 static DWORD zero = 0U;
643 HMODULE hm_advapi32 = NULL;
644 if (is_windows_9x () == TRUE)
646 return &zero;
648 if (g_b_init_get_sid_sub_authority == 0)
650 g_b_init_get_sid_sub_authority = 1;
651 hm_advapi32 = LoadLibrary ("Advapi32.dll");
652 s_pfn_Get_Sid_Sub_Authority =
653 (GetSidSubAuthority_Proc) GetProcAddress (
654 hm_advapi32, "GetSidSubAuthority");
656 if (s_pfn_Get_Sid_Sub_Authority == NULL)
658 return &zero;
660 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
663 static PUCHAR WINAPI
664 get_sid_sub_authority_count (PSID pSid)
666 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
667 static UCHAR zero = 0U;
668 HMODULE hm_advapi32 = NULL;
669 if (is_windows_9x () == TRUE)
671 return &zero;
673 if (g_b_init_get_sid_sub_authority_count == 0)
675 g_b_init_get_sid_sub_authority_count = 1;
676 hm_advapi32 = LoadLibrary ("Advapi32.dll");
677 s_pfn_Get_Sid_Sub_Authority_Count =
678 (GetSidSubAuthorityCount_Proc) GetProcAddress (
679 hm_advapi32, "GetSidSubAuthorityCount");
681 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
683 return &zero;
685 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
688 static DWORD WINAPI
689 get_security_info (HANDLE handle,
690 SE_OBJECT_TYPE ObjectType,
691 SECURITY_INFORMATION SecurityInfo,
692 PSID *ppsidOwner,
693 PSID *ppsidGroup,
694 PACL *ppDacl,
695 PACL *ppSacl,
696 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
698 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
699 HMODULE hm_advapi32 = NULL;
700 if (is_windows_9x () == TRUE)
702 return FALSE;
704 if (g_b_init_get_security_info == 0)
706 g_b_init_get_security_info = 1;
707 hm_advapi32 = LoadLibrary ("Advapi32.dll");
708 s_pfn_Get_Security_Info =
709 (GetSecurityInfo_Proc) GetProcAddress (
710 hm_advapi32, "GetSecurityInfo");
712 if (s_pfn_Get_Security_Info == NULL)
714 return FALSE;
716 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
717 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
718 ppSecurityDescriptor));
721 static BOOL WINAPI
722 get_file_security (const char *lpFileName,
723 SECURITY_INFORMATION RequestedInformation,
724 PSECURITY_DESCRIPTOR pSecurityDescriptor,
725 DWORD nLength,
726 LPDWORD lpnLengthNeeded)
728 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
729 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
730 HMODULE hm_advapi32 = NULL;
731 if (is_windows_9x () == TRUE)
733 errno = ENOTSUP;
734 return FALSE;
736 if (w32_unicode_filenames)
738 wchar_t filename_w[MAX_PATH];
740 if (g_b_init_get_file_security_w == 0)
742 g_b_init_get_file_security_w = 1;
743 hm_advapi32 = LoadLibrary ("Advapi32.dll");
744 s_pfn_Get_File_SecurityW =
745 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
746 "GetFileSecurityW");
748 if (s_pfn_Get_File_SecurityW == NULL)
750 errno = ENOTSUP;
751 return FALSE;
753 filename_to_utf16 (lpFileName, filename_w);
754 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
755 pSecurityDescriptor, nLength,
756 lpnLengthNeeded));
758 else
760 char filename_a[MAX_PATH];
762 if (g_b_init_get_file_security_a == 0)
764 g_b_init_get_file_security_a = 1;
765 hm_advapi32 = LoadLibrary ("Advapi32.dll");
766 s_pfn_Get_File_SecurityA =
767 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
768 "GetFileSecurityA");
770 if (s_pfn_Get_File_SecurityA == NULL)
772 errno = ENOTSUP;
773 return FALSE;
775 filename_to_ansi (lpFileName, filename_a);
776 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
777 pSecurityDescriptor, nLength,
778 lpnLengthNeeded));
782 static BOOL WINAPI
783 set_file_security (const char *lpFileName,
784 SECURITY_INFORMATION SecurityInformation,
785 PSECURITY_DESCRIPTOR pSecurityDescriptor)
787 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
788 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
789 HMODULE hm_advapi32 = NULL;
790 if (is_windows_9x () == TRUE)
792 errno = ENOTSUP;
793 return FALSE;
795 if (w32_unicode_filenames)
797 wchar_t filename_w[MAX_PATH];
799 if (g_b_init_set_file_security_w == 0)
801 g_b_init_set_file_security_w = 1;
802 hm_advapi32 = LoadLibrary ("Advapi32.dll");
803 s_pfn_Set_File_SecurityW =
804 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
805 "SetFileSecurityW");
807 if (s_pfn_Set_File_SecurityW == NULL)
809 errno = ENOTSUP;
810 return FALSE;
812 filename_to_utf16 (lpFileName, filename_w);
813 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
814 pSecurityDescriptor));
816 else
818 char filename_a[MAX_PATH];
820 if (g_b_init_set_file_security_a == 0)
822 g_b_init_set_file_security_a = 1;
823 hm_advapi32 = LoadLibrary ("Advapi32.dll");
824 s_pfn_Set_File_SecurityA =
825 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
826 "SetFileSecurityA");
828 if (s_pfn_Set_File_SecurityA == NULL)
830 errno = ENOTSUP;
831 return FALSE;
833 filename_to_ansi (lpFileName, filename_a);
834 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
835 pSecurityDescriptor));
839 static DWORD WINAPI
840 set_named_security_info (LPCTSTR lpObjectName,
841 SE_OBJECT_TYPE ObjectType,
842 SECURITY_INFORMATION SecurityInformation,
843 PSID psidOwner,
844 PSID psidGroup,
845 PACL pDacl,
846 PACL pSacl)
848 static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
849 static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
850 HMODULE hm_advapi32 = NULL;
851 if (is_windows_9x () == TRUE)
853 errno = ENOTSUP;
854 return ENOTSUP;
856 if (w32_unicode_filenames)
858 wchar_t filename_w[MAX_PATH];
860 if (g_b_init_set_named_security_info_w == 0)
862 g_b_init_set_named_security_info_w = 1;
863 hm_advapi32 = LoadLibrary ("Advapi32.dll");
864 s_pfn_Set_Named_Security_InfoW =
865 (SetNamedSecurityInfoW_Proc) GetProcAddress (hm_advapi32,
866 "SetNamedSecurityInfoW");
868 if (s_pfn_Set_Named_Security_InfoW == NULL)
870 errno = ENOTSUP;
871 return ENOTSUP;
873 filename_to_utf16 (lpObjectName, filename_w);
874 return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
875 SecurityInformation, psidOwner,
876 psidGroup, pDacl, pSacl));
878 else
880 char filename_a[MAX_PATH];
882 if (g_b_init_set_named_security_info_a == 0)
884 g_b_init_set_named_security_info_a = 1;
885 hm_advapi32 = LoadLibrary ("Advapi32.dll");
886 s_pfn_Set_Named_Security_InfoA =
887 (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
888 "SetNamedSecurityInfoA");
890 if (s_pfn_Set_Named_Security_InfoA == NULL)
892 errno = ENOTSUP;
893 return ENOTSUP;
895 filename_to_ansi (lpObjectName, filename_a);
896 return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
897 SecurityInformation, psidOwner,
898 psidGroup, pDacl, pSacl));
902 static BOOL WINAPI
903 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
904 PSID *pOwner,
905 LPBOOL lpbOwnerDefaulted)
907 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
908 HMODULE hm_advapi32 = NULL;
909 if (is_windows_9x () == TRUE)
911 errno = ENOTSUP;
912 return FALSE;
914 if (g_b_init_get_security_descriptor_owner == 0)
916 g_b_init_get_security_descriptor_owner = 1;
917 hm_advapi32 = LoadLibrary ("Advapi32.dll");
918 s_pfn_Get_Security_Descriptor_Owner =
919 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
920 hm_advapi32, "GetSecurityDescriptorOwner");
922 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
924 errno = ENOTSUP;
925 return FALSE;
927 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
928 lpbOwnerDefaulted));
931 static BOOL WINAPI
932 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
933 PSID *pGroup,
934 LPBOOL lpbGroupDefaulted)
936 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
937 HMODULE hm_advapi32 = NULL;
938 if (is_windows_9x () == TRUE)
940 errno = ENOTSUP;
941 return FALSE;
943 if (g_b_init_get_security_descriptor_group == 0)
945 g_b_init_get_security_descriptor_group = 1;
946 hm_advapi32 = LoadLibrary ("Advapi32.dll");
947 s_pfn_Get_Security_Descriptor_Group =
948 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
949 hm_advapi32, "GetSecurityDescriptorGroup");
951 if (s_pfn_Get_Security_Descriptor_Group == NULL)
953 errno = ENOTSUP;
954 return FALSE;
956 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
957 lpbGroupDefaulted));
960 static BOOL WINAPI
961 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
962 LPBOOL lpbDaclPresent,
963 PACL *pDacl,
964 LPBOOL lpbDaclDefaulted)
966 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
967 HMODULE hm_advapi32 = NULL;
968 if (is_windows_9x () == TRUE)
970 errno = ENOTSUP;
971 return FALSE;
973 if (g_b_init_get_security_descriptor_dacl == 0)
975 g_b_init_get_security_descriptor_dacl = 1;
976 hm_advapi32 = LoadLibrary ("Advapi32.dll");
977 s_pfn_Get_Security_Descriptor_Dacl =
978 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
979 hm_advapi32, "GetSecurityDescriptorDacl");
981 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
983 errno = ENOTSUP;
984 return FALSE;
986 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
987 lpbDaclPresent, pDacl,
988 lpbDaclDefaulted));
991 static BOOL WINAPI
992 is_valid_sid (PSID sid)
994 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
995 HMODULE hm_advapi32 = NULL;
996 if (is_windows_9x () == TRUE)
998 return FALSE;
1000 if (g_b_init_is_valid_sid == 0)
1002 g_b_init_is_valid_sid = 1;
1003 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1004 s_pfn_Is_Valid_Sid =
1005 (IsValidSid_Proc) GetProcAddress (
1006 hm_advapi32, "IsValidSid");
1008 if (s_pfn_Is_Valid_Sid == NULL)
1010 return FALSE;
1012 return (s_pfn_Is_Valid_Sid (sid));
1015 static BOOL WINAPI
1016 equal_sid (PSID sid1, PSID sid2)
1018 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
1019 HMODULE hm_advapi32 = NULL;
1020 if (is_windows_9x () == TRUE)
1022 return FALSE;
1024 if (g_b_init_equal_sid == 0)
1026 g_b_init_equal_sid = 1;
1027 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1028 s_pfn_Equal_Sid =
1029 (EqualSid_Proc) GetProcAddress (
1030 hm_advapi32, "EqualSid");
1032 if (s_pfn_Equal_Sid == NULL)
1034 return FALSE;
1036 return (s_pfn_Equal_Sid (sid1, sid2));
1039 static DWORD WINAPI
1040 get_length_sid (PSID sid)
1042 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
1043 HMODULE hm_advapi32 = NULL;
1044 if (is_windows_9x () == TRUE)
1046 return 0;
1048 if (g_b_init_get_length_sid == 0)
1050 g_b_init_get_length_sid = 1;
1051 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1052 s_pfn_Get_Length_Sid =
1053 (GetLengthSid_Proc) GetProcAddress (
1054 hm_advapi32, "GetLengthSid");
1056 if (s_pfn_Get_Length_Sid == NULL)
1058 return 0;
1060 return (s_pfn_Get_Length_Sid (sid));
1063 static BOOL WINAPI
1064 copy_sid (DWORD destlen, PSID dest, PSID src)
1066 static CopySid_Proc s_pfn_Copy_Sid = NULL;
1067 HMODULE hm_advapi32 = NULL;
1068 if (is_windows_9x () == TRUE)
1070 return FALSE;
1072 if (g_b_init_copy_sid == 0)
1074 g_b_init_copy_sid = 1;
1075 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1076 s_pfn_Copy_Sid =
1077 (CopySid_Proc) GetProcAddress (
1078 hm_advapi32, "CopySid");
1080 if (s_pfn_Copy_Sid == NULL)
1082 return FALSE;
1084 return (s_pfn_Copy_Sid (destlen, dest, src));
1088 END: Wrapper functions around OpenProcessToken
1089 and other functions in advapi32.dll that are only
1090 supported in Windows NT / 2k / XP
1093 static void WINAPI
1094 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1096 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1097 if (is_windows_9x () != TRUE)
1099 if (g_b_init_get_native_system_info == 0)
1101 g_b_init_get_native_system_info = 1;
1102 s_pfn_Get_Native_System_Info =
1103 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1104 "GetNativeSystemInfo");
1106 if (s_pfn_Get_Native_System_Info != NULL)
1107 s_pfn_Get_Native_System_Info (lpSystemInfo);
1109 else
1110 lpSystemInfo->dwNumberOfProcessors = -1;
1113 static BOOL WINAPI
1114 get_system_times (LPFILETIME lpIdleTime,
1115 LPFILETIME lpKernelTime,
1116 LPFILETIME lpUserTime)
1118 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1119 if (is_windows_9x () == TRUE)
1121 return FALSE;
1123 if (g_b_init_get_system_times == 0)
1125 g_b_init_get_system_times = 1;
1126 s_pfn_Get_System_times =
1127 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1128 "GetSystemTimes");
1130 if (s_pfn_Get_System_times == NULL)
1131 return FALSE;
1132 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1135 static BOOLEAN WINAPI
1136 create_symbolic_link (LPCSTR lpSymlinkFilename,
1137 LPCSTR lpTargetFileName,
1138 DWORD dwFlags)
1140 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1141 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1142 BOOLEAN retval;
1144 if (is_windows_9x () == TRUE)
1146 errno = ENOSYS;
1147 return 0;
1149 if (w32_unicode_filenames)
1151 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1153 if (g_b_init_create_symbolic_link_w == 0)
1155 g_b_init_create_symbolic_link_w = 1;
1156 s_pfn_Create_Symbolic_LinkW =
1157 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1158 "CreateSymbolicLinkW");
1160 if (s_pfn_Create_Symbolic_LinkW == NULL)
1162 errno = ENOSYS;
1163 return 0;
1166 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1167 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1168 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1169 /* If we were denied creation of the symlink, try again after
1170 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1171 if (!retval)
1173 TOKEN_PRIVILEGES priv_current;
1175 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1176 &priv_current))
1178 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1179 restore_privilege (&priv_current);
1180 revert_to_self ();
1184 else
1186 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1188 if (g_b_init_create_symbolic_link_a == 0)
1190 g_b_init_create_symbolic_link_a = 1;
1191 s_pfn_Create_Symbolic_LinkA =
1192 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1193 "CreateSymbolicLinkA");
1195 if (s_pfn_Create_Symbolic_LinkA == NULL)
1197 errno = ENOSYS;
1198 return 0;
1201 filename_to_ansi (lpSymlinkFilename, symfn_a);
1202 filename_to_ansi (lpTargetFileName, tgtfn_a);
1203 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1204 /* If we were denied creation of the symlink, try again after
1205 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1206 if (!retval)
1208 TOKEN_PRIVILEGES priv_current;
1210 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1211 &priv_current))
1213 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1214 restore_privilege (&priv_current);
1215 revert_to_self ();
1219 return retval;
1222 static BOOL WINAPI
1223 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1225 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1227 if (is_windows_9x () == TRUE)
1229 errno = ENOTSUP;
1230 return FALSE;
1233 if (g_b_init_is_valid_security_descriptor == 0)
1235 g_b_init_is_valid_security_descriptor = 1;
1236 s_pfn_Is_Valid_Security_Descriptor_Proc =
1237 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1238 "IsValidSecurityDescriptor");
1240 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1242 errno = ENOTSUP;
1243 return FALSE;
1246 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1249 static BOOL WINAPI
1250 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1251 DWORD RequestedStringSDRevision,
1252 SECURITY_INFORMATION SecurityInformation,
1253 LPTSTR *StringSecurityDescriptor,
1254 PULONG StringSecurityDescriptorLen)
1256 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1257 BOOL retval;
1259 if (is_windows_9x () == TRUE)
1261 errno = ENOTSUP;
1262 return FALSE;
1265 if (g_b_init_convert_sd_to_sddl == 0)
1267 g_b_init_convert_sd_to_sddl = 1;
1268 #ifdef _UNICODE
1269 s_pfn_Convert_SD_To_SDDL =
1270 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1271 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1272 #else
1273 s_pfn_Convert_SD_To_SDDL =
1274 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1275 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1276 #endif
1278 if (s_pfn_Convert_SD_To_SDDL == NULL)
1280 errno = ENOTSUP;
1281 return FALSE;
1284 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1285 RequestedStringSDRevision,
1286 SecurityInformation,
1287 StringSecurityDescriptor,
1288 StringSecurityDescriptorLen);
1290 return retval;
1293 static BOOL WINAPI
1294 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1295 DWORD StringSDRevision,
1296 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1297 PULONG SecurityDescriptorSize)
1299 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1300 BOOL retval;
1302 if (is_windows_9x () == TRUE)
1304 errno = ENOTSUP;
1305 return FALSE;
1308 if (g_b_init_convert_sddl_to_sd == 0)
1310 g_b_init_convert_sddl_to_sd = 1;
1311 #ifdef _UNICODE
1312 s_pfn_Convert_SDDL_To_SD =
1313 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1314 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1315 #else
1316 s_pfn_Convert_SDDL_To_SD =
1317 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1318 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1319 #endif
1321 if (s_pfn_Convert_SDDL_To_SD == NULL)
1323 errno = ENOTSUP;
1324 return FALSE;
1327 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1328 StringSDRevision,
1329 SecurityDescriptor,
1330 SecurityDescriptorSize);
1332 return retval;
1335 static DWORD WINAPI
1336 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1338 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1339 HMODULE hm_iphlpapi = NULL;
1341 if (is_windows_9x () == TRUE)
1342 return ERROR_NOT_SUPPORTED;
1344 if (g_b_init_get_adapters_info == 0)
1346 g_b_init_get_adapters_info = 1;
1347 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1348 if (hm_iphlpapi)
1349 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1350 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1352 if (s_pfn_Get_Adapters_Info == NULL)
1353 return ERROR_NOT_SUPPORTED;
1354 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1359 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1360 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1362 This is called from alloc.c:valid_pointer_p. */
1364 w32_valid_pointer_p (void *p, int size)
1366 SIZE_T done;
1367 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1369 if (h)
1371 unsigned char *buf = alloca (size);
1372 int retval = ReadProcessMemory (h, p, buf, size, &done);
1374 CloseHandle (h);
1375 return retval;
1377 else
1378 return -1;
1383 /* Here's an overview of how the Windows build supports file names
1384 that cannot be encoded by the current system codepage.
1386 From the POV of Lisp and layers of C code above the functions here,
1387 Emacs on Windows pretends that its file names are encoded in UTF-8;
1388 see encode_file and decode_file on coding.c. Any file name that is
1389 passed as a unibyte string to C functions defined here is assumed
1390 to be in UTF-8 encoding. Any file name returned by functions
1391 defined here must be in UTF-8 encoding, with only a few exceptions
1392 reserved for a couple of special cases. (Be sure to use
1393 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1394 as they can be much longer than MAX_PATH!)
1396 The UTF-8 encoded file names cannot be passed to system APIs, as
1397 Windows does not support that. Therefore, they are converted
1398 either to UTF-16 or to the ANSI codepage, depending on the value of
1399 w32-unicode-filenames, before calling any system APIs or CRT library
1400 functions. The default value of that variable is determined by the
1401 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1402 user can change that default (although I don't see why would she
1403 want to).
1405 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1406 filename_from_utf16, and filename_from_ansi, are the workhorses of
1407 these conversions. They rely on Windows native APIs
1408 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1409 functions from coding.c here, because they allocate memory, which
1410 is a bad idea on the level of libc, which is what the functions
1411 here emulate. (If you worry about performance due to constant
1412 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1413 it was measured to take only a few microseconds on a not-so-fast
1414 machine, and second, that's exactly what the ANSI APIs we used
1415 before did anyway, because they are just thin wrappers around the
1416 Unicode APIs.)
1418 The variables file-name-coding-system and default-file-name-coding-system
1419 still exist, but are actually used only when a file name needs to
1420 be converted to the ANSI codepage. This happens all the time when
1421 w32-unicode-filenames is nil, but can also happen from time to time
1422 when it is t. Otherwise, these variables have no effect on file-name
1423 encoding when w32-unicode-filenames is t; this is similar to
1424 selection-coding-system.
1426 This arrangement works very well, but it has a few gotchas and
1427 limitations:
1429 . Lisp code that encodes or decodes file names manually should
1430 normally use 'utf-8' as the coding-system on Windows,
1431 disregarding file-name-coding-system. This is a somewhat
1432 unpleasant consequence, but it cannot be avoided. Fortunately,
1433 very few Lisp packages need to do that.
1435 More generally, passing to library functions (e.g., fopen or
1436 opendir) file names already encoded in the ANSI codepage is
1437 explicitly *verboten*, as all those functions, as shadowed and
1438 emulated here, assume they will receive UTF-8 encoded file names.
1440 For the same reasons, no CRT function or Win32 API can be called
1441 directly in Emacs sources, without either converting the file
1442 names from UTF-8 to UTF-16 or ANSI codepage, or going through
1443 some shadowing function defined here.
1445 . Environment variables stored in Vprocess_environment are encoded
1446 in the ANSI codepage, so if getenv/egetenv is used for a variable
1447 whose value is a file name or a list of directories, it needs to
1448 be converted to UTF-8, before it is used as argument to functions
1449 or decoded into a Lisp string.
1451 . File names passed to external libraries, like the image libraries
1452 and GnuTLS, need special handling. These libraries generally
1453 don't support UTF-16 or UTF-8 file names, so they must get file
1454 names encoded in the ANSI codepage. To facilitate using these
1455 libraries with file names that are not encodable in the ANSI
1456 codepage, use the function ansi_encode_filename, which will try
1457 to use the short 8+3 alias of a file name if that file name is
1458 not encodable in the ANSI codepage. See image.c and gnutls.c for
1459 examples of how this should be done.
1461 . Running subprocesses in non-ASCII directories and with non-ASCII
1462 file arguments is limited to the current codepage (even though
1463 Emacs is perfectly capable of finding an executable program file
1464 in a directory whose name cannot be encoded in the current
1465 codepage). This is because the command-line arguments are
1466 encoded _before_ they get to the w32-specific level, and the
1467 encoding is not known in advance (it doesn't have to be the
1468 current ANSI codepage), so w32proc.c functions cannot re-encode
1469 them in UTF-16. This should be fixed, but will also require
1470 changes in cmdproxy. The current limitation is not terribly bad
1471 anyway, since very few, if any, Windows console programs that are
1472 likely to be invoked by Emacs support UTF-16 encoded command
1473 lines.
1475 . For similar reasons, server.el and emacsclient are also limited
1476 to the current ANSI codepage for now.
1478 . Emacs itself can only handle command-line arguments encoded in
1479 the current codepage.
1481 . Turning on w32-unicode-filename on Windows 9X (if it at all
1482 works) requires UNICOWS.DLL, which is thus a requirement even in
1483 non-GUI sessions, something the we previously avoided. */
1487 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1488 codepage defined by file-name-coding-system. */
1490 /* Current codepage for encoding file names. */
1491 static int file_name_codepage;
1493 /* Produce a Windows ANSI codepage suitable for encoding file names.
1494 Return the information about that codepage in CP_INFO. */
1495 static int
1496 codepage_for_filenames (CPINFO *cp_info)
1498 /* A simple cache to avoid calling GetCPInfo every time we need to
1499 encode/decode a file name. The file-name encoding is not
1500 supposed to be changed too frequently, if ever. */
1501 static Lisp_Object last_file_name_encoding;
1502 static CPINFO cp;
1503 Lisp_Object current_encoding;
1505 current_encoding = Vfile_name_coding_system;
1506 if (NILP (current_encoding))
1507 current_encoding = Vdefault_file_name_coding_system;
1509 if (!EQ (last_file_name_encoding, current_encoding))
1511 /* Default to the current ANSI codepage. */
1512 file_name_codepage = w32_ansi_code_page;
1514 if (NILP (current_encoding))
1516 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1517 char *cp = NULL, *end;
1518 int cpnum;
1520 if (strncmp (cpname, "cp", 2) == 0)
1521 cp = cpname + 2;
1522 else if (strncmp (cpname, "windows-", 8) == 0)
1523 cp = cpname + 8;
1525 if (cp)
1527 end = cp;
1528 cpnum = strtol (cp, &end, 10);
1529 if (cpnum && *end == '\0' && end - cp >= 2)
1530 file_name_codepage = cpnum;
1534 if (!file_name_codepage)
1535 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1537 if (!GetCPInfo (file_name_codepage, &cp))
1539 file_name_codepage = CP_ACP;
1540 if (!GetCPInfo (file_name_codepage, &cp))
1541 emacs_abort ();
1544 if (cp_info)
1545 *cp_info = cp;
1547 return file_name_codepage;
1551 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1553 int result = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
1554 fn_out, MAX_PATH);
1556 if (!result)
1558 DWORD err = GetLastError ();
1560 switch (err)
1562 case ERROR_INVALID_FLAGS:
1563 case ERROR_INVALID_PARAMETER:
1564 errno = EINVAL;
1565 break;
1566 case ERROR_INSUFFICIENT_BUFFER:
1567 case ERROR_NO_UNICODE_TRANSLATION:
1568 default:
1569 errno = ENOENT;
1570 break;
1572 return -1;
1574 return 0;
1578 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1580 int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1581 fn_out, MAX_UTF8_PATH, NULL, NULL);
1583 if (!result)
1585 DWORD err = GetLastError ();
1587 switch (err)
1589 case ERROR_INVALID_FLAGS:
1590 case ERROR_INVALID_PARAMETER:
1591 errno = EINVAL;
1592 break;
1593 case ERROR_INSUFFICIENT_BUFFER:
1594 case ERROR_NO_UNICODE_TRANSLATION:
1595 default:
1596 errno = ENOENT;
1597 break;
1599 return -1;
1601 return 0;
1605 filename_to_ansi (const char *fn_in, char *fn_out)
1607 wchar_t fn_utf16[MAX_PATH];
1609 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1611 int result;
1612 int codepage = codepage_for_filenames (NULL);
1614 result = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
1615 fn_out, MAX_PATH, NULL, NULL);
1616 if (!result)
1618 DWORD err = GetLastError ();
1620 switch (err)
1622 case ERROR_INVALID_FLAGS:
1623 case ERROR_INVALID_PARAMETER:
1624 errno = EINVAL;
1625 break;
1626 case ERROR_INSUFFICIENT_BUFFER:
1627 case ERROR_NO_UNICODE_TRANSLATION:
1628 default:
1629 errno = ENOENT;
1630 break;
1632 return -1;
1634 return 0;
1636 return -1;
1640 filename_from_ansi (const char *fn_in, char *fn_out)
1642 wchar_t fn_utf16[MAX_PATH];
1643 int codepage = codepage_for_filenames (NULL);
1644 int result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
1645 fn_utf16, MAX_PATH);
1647 if (!result)
1649 DWORD err = GetLastError ();
1651 switch (err)
1653 case ERROR_INVALID_FLAGS:
1654 case ERROR_INVALID_PARAMETER:
1655 errno = EINVAL;
1656 break;
1657 case ERROR_INSUFFICIENT_BUFFER:
1658 case ERROR_NO_UNICODE_TRANSLATION:
1659 default:
1660 errno = ENOENT;
1661 break;
1663 return -1;
1665 return filename_from_utf16 (fn_utf16, fn_out);
1670 /* The directory where we started, in UTF-8. */
1671 static char startup_dir[MAX_UTF8_PATH];
1673 /* Get the current working directory. */
1674 char *
1675 getcwd (char *dir, int dirsize)
1677 if (!dirsize)
1679 errno = EINVAL;
1680 return NULL;
1682 if (dirsize <= strlen (startup_dir))
1684 errno = ERANGE;
1685 return NULL;
1687 #if 0
1688 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1689 return dir;
1690 return NULL;
1691 #else
1692 /* Emacs doesn't actually change directory itself, it stays in the
1693 same directory where it was started. */
1694 strcpy (dir, startup_dir);
1695 return dir;
1696 #endif
1699 /* Emulate getloadavg. */
1701 struct load_sample {
1702 time_t sample_time;
1703 ULONGLONG idle;
1704 ULONGLONG kernel;
1705 ULONGLONG user;
1708 /* Number of processors on this machine. */
1709 static unsigned num_of_processors;
1711 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1712 static struct load_sample samples[16*60];
1713 static int first_idx = -1, last_idx = -1;
1714 static int max_idx = ARRAYELTS (samples);
1716 static int
1717 buf_next (int from)
1719 int next_idx = from + 1;
1721 if (next_idx >= max_idx)
1722 next_idx = 0;
1724 return next_idx;
1727 static int
1728 buf_prev (int from)
1730 int prev_idx = from - 1;
1732 if (prev_idx < 0)
1733 prev_idx = max_idx - 1;
1735 return prev_idx;
1738 static void
1739 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1741 SYSTEM_INFO sysinfo;
1742 FILETIME ft_idle, ft_user, ft_kernel;
1744 /* Initialize the number of processors on this machine. */
1745 if (num_of_processors <= 0)
1747 get_native_system_info (&sysinfo);
1748 num_of_processors = sysinfo.dwNumberOfProcessors;
1749 if (num_of_processors <= 0)
1751 GetSystemInfo (&sysinfo);
1752 num_of_processors = sysinfo.dwNumberOfProcessors;
1754 if (num_of_processors <= 0)
1755 num_of_processors = 1;
1758 /* TODO: Take into account threads that are ready to run, by
1759 sampling the "\System\Processor Queue Length" performance
1760 counter. The code below accounts only for threads that are
1761 actually running. */
1763 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1765 ULARGE_INTEGER uidle, ukernel, uuser;
1767 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1768 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1769 memcpy (&uuser, &ft_user, sizeof (ft_user));
1770 *idle = uidle.QuadPart;
1771 *kernel = ukernel.QuadPart;
1772 *user = uuser.QuadPart;
1774 else
1776 *idle = 0;
1777 *kernel = 0;
1778 *user = 0;
1782 /* Produce the load average for a given time interval, using the
1783 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1784 1-minute, 5-minute, or 15-minute average, respectively. */
1785 static double
1786 getavg (int which)
1788 double retval = -1.0;
1789 double tdiff;
1790 int idx;
1791 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1792 time_t now = samples[last_idx].sample_time;
1794 if (first_idx != last_idx)
1796 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1798 tdiff = difftime (now, samples[idx].sample_time);
1799 if (tdiff >= span - 2*DBL_EPSILON*now)
1801 long double sys =
1802 samples[last_idx].kernel + samples[last_idx].user
1803 - (samples[idx].kernel + samples[idx].user);
1804 long double idl = samples[last_idx].idle - samples[idx].idle;
1806 retval = (1.0 - idl / sys) * num_of_processors;
1807 break;
1809 if (idx == first_idx)
1810 break;
1814 return retval;
1818 getloadavg (double loadavg[], int nelem)
1820 int elem;
1821 ULONGLONG idle, kernel, user;
1822 time_t now = time (NULL);
1824 /* If system time jumped back for some reason, delete all samples
1825 whose time is later than the current wall-clock time. This
1826 prevents load average figures from becoming frozen for prolonged
1827 periods of time, when system time is reset backwards. */
1828 if (last_idx >= 0)
1830 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1832 if (last_idx == first_idx)
1834 first_idx = last_idx = -1;
1835 break;
1837 last_idx = buf_prev (last_idx);
1841 /* Store another sample. We ignore samples that are less than 1 sec
1842 apart. */
1843 if (last_idx < 0
1844 || (difftime (now, samples[last_idx].sample_time)
1845 >= 1.0 - 2*DBL_EPSILON*now))
1847 sample_system_load (&idle, &kernel, &user);
1848 last_idx = buf_next (last_idx);
1849 samples[last_idx].sample_time = now;
1850 samples[last_idx].idle = idle;
1851 samples[last_idx].kernel = kernel;
1852 samples[last_idx].user = user;
1853 /* If the buffer has more that 15 min worth of samples, discard
1854 the old ones. */
1855 if (first_idx == -1)
1856 first_idx = last_idx;
1857 while (first_idx != last_idx
1858 && (difftime (now, samples[first_idx].sample_time)
1859 >= 15.0*60 + 2*DBL_EPSILON*now))
1860 first_idx = buf_next (first_idx);
1863 for (elem = 0; elem < nelem; elem++)
1865 double avg = getavg (elem);
1867 if (avg < 0)
1868 break;
1869 loadavg[elem] = avg;
1872 return elem;
1875 /* Emulate getpwuid, getpwnam and others. */
1877 #define PASSWD_FIELD_SIZE 256
1879 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1880 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1881 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1882 static char dflt_passwd_dir[MAX_UTF8_PATH];
1883 static char dflt_passwd_shell[MAX_UTF8_PATH];
1885 static struct passwd dflt_passwd =
1887 dflt_passwd_name,
1888 dflt_passwd_passwd,
1892 dflt_passwd_gecos,
1893 dflt_passwd_dir,
1894 dflt_passwd_shell,
1897 static char dflt_group_name[GNLEN+1];
1899 static struct group dflt_group =
1901 /* When group information is not available, we return this as the
1902 group for all files. */
1903 dflt_group_name,
1907 unsigned
1908 getuid (void)
1910 return dflt_passwd.pw_uid;
1913 unsigned
1914 geteuid (void)
1916 /* I could imagine arguing for checking to see whether the user is
1917 in the Administrators group and returning a UID of 0 for that
1918 case, but I don't know how wise that would be in the long run. */
1919 return getuid ();
1922 unsigned
1923 getgid (void)
1925 return dflt_passwd.pw_gid;
1928 unsigned
1929 getegid (void)
1931 return getgid ();
1934 struct passwd *
1935 getpwuid (unsigned uid)
1937 if (uid == dflt_passwd.pw_uid)
1938 return &dflt_passwd;
1939 return NULL;
1942 struct group *
1943 getgrgid (gid_t gid)
1945 return &dflt_group;
1948 struct passwd *
1949 getpwnam (char *name)
1951 struct passwd *pw;
1953 pw = getpwuid (getuid ());
1954 if (!pw)
1955 return pw;
1957 if (xstrcasecmp (name, pw->pw_name))
1958 return NULL;
1960 return pw;
1963 static void
1964 init_user_info (void)
1966 /* Find the user's real name by opening the process token and
1967 looking up the name associated with the user-sid in that token.
1969 Use the relative portion of the identifier authority value from
1970 the user-sid as the user id value (same for group id using the
1971 primary group sid from the process token). */
1973 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1974 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1975 DWORD glength = sizeof (gname);
1976 HANDLE token = NULL;
1977 SID_NAME_USE user_type;
1978 unsigned char *buf = NULL;
1979 DWORD blen = 0;
1980 TOKEN_USER user_token;
1981 TOKEN_PRIMARY_GROUP group_token;
1982 BOOL result;
1984 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1985 if (result)
1987 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1988 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1990 buf = xmalloc (blen);
1991 result = get_token_information (token, TokenUser,
1992 (LPVOID)buf, blen, &needed);
1993 if (result)
1995 memcpy (&user_token, buf, sizeof (user_token));
1996 result = lookup_account_sid (NULL, user_token.User.Sid,
1997 uname, &ulength,
1998 domain, &dlength, &user_type);
2001 else
2002 result = FALSE;
2004 if (result)
2006 strcpy (dflt_passwd.pw_name, uname);
2007 /* Determine a reasonable uid value. */
2008 if (xstrcasecmp ("administrator", uname) == 0)
2010 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
2011 dflt_passwd.pw_gid = 513; /* well-known None gid */
2013 else
2015 /* Use the last sub-authority value of the RID, the relative
2016 portion of the SID, as user/group ID. */
2017 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
2019 /* Get group id and name. */
2020 result = get_token_information (token, TokenPrimaryGroup,
2021 (LPVOID)buf, blen, &needed);
2022 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2024 buf = xrealloc (buf, blen = needed);
2025 result = get_token_information (token, TokenPrimaryGroup,
2026 (LPVOID)buf, blen, &needed);
2028 if (result)
2030 memcpy (&group_token, buf, sizeof (group_token));
2031 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
2032 dlength = sizeof (domain);
2033 /* If we can get at the real Primary Group name, use that.
2034 Otherwise, the default group name was already set to
2035 "None" in globals_of_w32. */
2036 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
2037 gname, &glength, NULL, &dlength,
2038 &user_type))
2039 strcpy (dflt_group_name, gname);
2041 else
2042 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2045 /* If security calls are not supported (presumably because we
2046 are running under Windows 9X), fallback to this: */
2047 else if (GetUserName (uname, &ulength))
2049 strcpy (dflt_passwd.pw_name, uname);
2050 if (xstrcasecmp ("administrator", uname) == 0)
2051 dflt_passwd.pw_uid = 0;
2052 else
2053 dflt_passwd.pw_uid = 123;
2054 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2056 else
2058 strcpy (dflt_passwd.pw_name, "unknown");
2059 dflt_passwd.pw_uid = 123;
2060 dflt_passwd.pw_gid = 123;
2062 dflt_group.gr_gid = dflt_passwd.pw_gid;
2064 /* Set dir and shell from environment variables. */
2065 if (w32_unicode_filenames)
2067 wchar_t *home = _wgetenv (L"HOME");
2068 wchar_t *shell = _wgetenv (L"SHELL");
2070 /* Ensure HOME and SHELL are defined. */
2071 if (home == NULL)
2072 emacs_abort ();
2073 if (shell == NULL)
2074 emacs_abort ();
2075 filename_from_utf16 (home, dflt_passwd.pw_dir);
2076 filename_from_utf16 (shell, dflt_passwd.pw_shell);
2078 else
2080 char *home = getenv ("HOME");
2081 char *shell = getenv ("SHELL");
2083 if (home == NULL)
2084 emacs_abort ();
2085 if (shell == NULL)
2086 emacs_abort ();
2087 filename_from_ansi (home, dflt_passwd.pw_dir);
2088 filename_from_ansi (shell, dflt_passwd.pw_shell);
2091 xfree (buf);
2092 if (token)
2093 CloseHandle (token);
2097 random (void)
2099 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
2100 return ((rand () << 15) | rand ());
2103 void
2104 srandom (int seed)
2106 srand (seed);
2109 /* Return the maximum length in bytes of a multibyte character
2110 sequence encoded in the current ANSI codepage. This is required to
2111 correctly walk the encoded file names one character at a time. */
2112 static int
2113 max_filename_mbslen (void)
2115 CPINFO cp_info;
2117 codepage_for_filenames (&cp_info);
2118 return cp_info.MaxCharSize;
2121 /* Normalize filename by converting in-place all of its path
2122 separators to the separator specified by PATH_SEP. */
2124 static void
2125 normalize_filename (register char *fp, char path_sep)
2127 char *p2;
2129 /* Always lower-case drive letters a-z, even if the filesystem
2130 preserves case in filenames.
2131 This is so filenames can be compared by string comparison
2132 functions that are case-sensitive. Even case-preserving filesystems
2133 do not distinguish case in drive letters. */
2134 p2 = fp + 1;
2136 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2138 *fp += 'a' - 'A';
2139 fp += 2;
2142 while (*fp)
2144 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2145 *fp = path_sep;
2146 fp++;
2150 /* Destructively turn backslashes into slashes. */
2151 void
2152 dostounix_filename (register char *p)
2154 normalize_filename (p, '/');
2157 /* Destructively turn slashes into backslashes. */
2158 void
2159 unixtodos_filename (register char *p)
2161 normalize_filename (p, '\\');
2164 /* Remove all CR's that are followed by a LF.
2165 (From msdos.c...probably should figure out a way to share it,
2166 although this code isn't going to ever change.) */
2167 static int
2168 crlf_to_lf (register int n, register unsigned char *buf)
2170 unsigned char *np = buf;
2171 unsigned char *startp = buf;
2172 unsigned char *endp = buf + n;
2174 if (n == 0)
2175 return n;
2176 while (buf < endp - 1)
2178 if (*buf == 0x0d)
2180 if (*(++buf) != 0x0a)
2181 *np++ = 0x0d;
2183 else
2184 *np++ = *buf++;
2186 if (buf < endp)
2187 *np++ = *buf++;
2188 return np - startp;
2191 /* Parse the root part of file name, if present. Return length and
2192 optionally store pointer to char after root. */
2193 static int
2194 parse_root (const char * name, const char ** pPath)
2196 const char * start = name;
2198 if (name == NULL)
2199 return 0;
2201 /* find the root name of the volume if given */
2202 if (isalpha (name[0]) && name[1] == ':')
2204 /* skip past drive specifier */
2205 name += 2;
2206 if (IS_DIRECTORY_SEP (name[0]))
2207 name++;
2209 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2211 int slashes = 2;
2213 name += 2;
2216 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2217 break;
2218 name++;
2220 while ( *name );
2221 if (IS_DIRECTORY_SEP (name[0]))
2222 name++;
2225 if (pPath)
2226 *pPath = name;
2228 return name - start;
2231 /* Get long base name for name; name is assumed to be absolute. */
2232 static int
2233 get_long_basename (char * name, char * buf, int size)
2235 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2236 char fname_utf8[MAX_UTF8_PATH];
2237 int len = 0;
2238 int cstatus = -1;
2240 /* Must be valid filename, no wild cards or other invalid characters. */
2241 if (strpbrk (name, "*?|<>\""))
2242 return 0;
2244 if (w32_unicode_filenames)
2246 wchar_t fname_utf16[MAX_PATH];
2247 WIN32_FIND_DATAW find_data_wide;
2249 filename_to_utf16 (name, fname_utf16);
2250 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2251 if (dir_handle != INVALID_HANDLE_VALUE)
2252 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2254 else
2256 char fname_ansi[MAX_PATH];
2257 WIN32_FIND_DATAA find_data_ansi;
2259 filename_to_ansi (name, fname_ansi);
2260 /* If the ANSI name includes ? characters, it is not encodable
2261 in the ANSI codepage. In that case, we deliver the question
2262 marks to the caller; calling FindFirstFileA in this case
2263 could return some unrelated file name in the same
2264 directory. */
2265 if (_mbspbrk (fname_ansi, "?"))
2267 /* Find the basename of fname_ansi. */
2268 char *p = strrchr (fname_ansi, '\\');
2270 if (!p)
2271 p = fname_ansi;
2272 else
2273 p++;
2274 cstatus = filename_from_ansi (p, fname_utf8);
2276 else
2278 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2279 if (dir_handle != INVALID_HANDLE_VALUE)
2280 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2284 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2285 memcpy (buf, fname_utf8, len + 1);
2286 else
2287 len = 0;
2289 if (dir_handle != INVALID_HANDLE_VALUE)
2290 FindClose (dir_handle);
2292 return len;
2295 /* Get long name for file, if possible (assumed to be absolute). */
2296 BOOL
2297 w32_get_long_filename (char * name, char * buf, int size)
2299 char * o = buf;
2300 char * p;
2301 const char * q;
2302 char full[ MAX_UTF8_PATH ];
2303 int len;
2305 len = strlen (name);
2306 if (len >= MAX_UTF8_PATH)
2307 return FALSE;
2309 /* Use local copy for destructive modification. */
2310 memcpy (full, name, len+1);
2311 unixtodos_filename (full);
2313 /* Copy root part verbatim. */
2314 len = parse_root (full, (const char **)&p);
2315 memcpy (o, full, len);
2316 o += len;
2317 *o = '\0';
2318 size -= len;
2320 while (p != NULL && *p)
2322 q = p;
2323 p = strchr (q, '\\');
2324 if (p) *p = '\0';
2325 len = get_long_basename (full, o, size);
2326 if (len > 0)
2328 o += len;
2329 size -= len;
2330 if (p != NULL)
2332 *p++ = '\\';
2333 if (size < 2)
2334 return FALSE;
2335 *o++ = '\\';
2336 size--;
2337 *o = '\0';
2340 else
2341 return FALSE;
2344 return TRUE;
2347 unsigned int
2348 w32_get_short_filename (char * name, char * buf, int size)
2350 if (w32_unicode_filenames)
2352 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2353 unsigned int retval;
2355 filename_to_utf16 (name, name_utf16);
2356 retval = GetShortPathNameW (name_utf16, short_name, size);
2357 if (retval && retval < size)
2358 filename_from_utf16 (short_name, buf);
2359 return retval;
2361 else
2363 char name_ansi[MAX_PATH];
2365 filename_to_ansi (name, name_ansi);
2366 return GetShortPathNameA (name_ansi, buf, size);
2370 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2371 MS-Windows ANSI codepage. If FILENAME includes characters not
2372 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2373 if it exists. This is needed because the w32 build wants to
2374 support file names outside of the system locale, but image
2375 libraries typically don't support wide (a.k.a. "Unicode") APIs
2376 required for that. */
2378 Lisp_Object
2379 ansi_encode_filename (Lisp_Object filename)
2381 Lisp_Object encoded_filename;
2382 char fname[MAX_PATH];
2384 filename_to_ansi (SSDATA (filename), fname);
2385 if (_mbspbrk (fname, "?"))
2387 char shortname[MAX_PATH];
2389 if (w32_get_short_filename (SDATA (filename), shortname, MAX_PATH))
2391 dostounix_filename (shortname);
2392 encoded_filename = build_string (shortname);
2395 else
2396 encoded_filename = build_unibyte_string (fname);
2397 return encoded_filename;
2400 static int
2401 is_unc_volume (const char *filename)
2403 const char *ptr = filename;
2405 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2406 return 0;
2408 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2409 return 0;
2411 return 1;
2414 /* Emulate the Posix unsetenv. */
2416 unsetenv (const char *name)
2418 char *var;
2419 size_t name_len;
2421 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2423 errno = EINVAL;
2424 return -1;
2426 name_len = strlen (name);
2427 /* MS docs says an environment variable cannot be longer than 32K. */
2428 if (name_len > 32767)
2430 errno = ENOMEM;
2431 return 0;
2433 /* It is safe to use 'alloca' with 32K size, since the stack is at
2434 least 2MB, and we set it to 8MB in the link command line. */
2435 var = alloca (name_len + 2);
2436 strncpy (var, name, name_len);
2437 var[name_len++] = '=';
2438 var[name_len] = '\0';
2439 return _putenv (var);
2442 /* MS _putenv doesn't support removing a variable when the argument
2443 does not include the '=' character, so we fix that here. */
2445 sys_putenv (char *str)
2447 const char *const name_end = strchr (str, '=');
2449 if (name_end == NULL)
2451 /* Remove the variable from the environment. */
2452 return unsetenv (str);
2455 return _putenv (str);
2458 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2460 LPBYTE
2461 w32_get_resource (char *key, LPDWORD lpdwtype)
2463 LPBYTE lpvalue;
2464 HKEY hrootkey = NULL;
2465 DWORD cbData;
2467 /* Check both the current user and the local machine to see if
2468 we have any resources. */
2470 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2472 lpvalue = NULL;
2474 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2475 && (lpvalue = xmalloc (cbData)) != NULL
2476 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2478 RegCloseKey (hrootkey);
2479 return (lpvalue);
2482 xfree (lpvalue);
2484 RegCloseKey (hrootkey);
2487 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2489 lpvalue = NULL;
2491 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2492 && (lpvalue = xmalloc (cbData)) != NULL
2493 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2495 RegCloseKey (hrootkey);
2496 return (lpvalue);
2499 xfree (lpvalue);
2501 RegCloseKey (hrootkey);
2504 return (NULL);
2507 /* The argv[] array holds ANSI-encoded strings, and so this function
2508 works with ANS_encoded strings. */
2509 void
2510 init_environment (char ** argv)
2512 static const char * const tempdirs[] = {
2513 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2516 int i;
2518 const int imax = ARRAYELTS (tempdirs);
2520 /* Implementation note: This function explicitly works with ANSI
2521 file names, not with UTF-8 encoded file names. This is because
2522 this function pushes variables into the Emacs's environment, and
2523 the environment variables are always assumed to be in the
2524 locale-specific encoding. Do NOT call any functions that accept
2525 UTF-8 file names from this function! */
2527 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2528 temporary files and assume "/tmp" if $TMPDIR is unset, which
2529 will break on DOS/Windows. Refuse to work if we cannot find
2530 a directory, not even "c:/", usable for that purpose. */
2531 for (i = 0; i < imax ; i++)
2533 const char *tmp = tempdirs[i];
2535 if (*tmp == '$')
2536 tmp = getenv (tmp + 1);
2537 /* Note that `access' can lie to us if the directory resides on a
2538 read-only filesystem, like CD-ROM or a write-protected floppy.
2539 The only way to be really sure is to actually create a file and
2540 see if it succeeds. But I think that's too much to ask. */
2542 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2543 if (tmp && sys_access (tmp, D_OK) == 0)
2545 char * var = alloca (strlen (tmp) + 8);
2546 sprintf (var, "TMPDIR=%s", tmp);
2547 _putenv (strdup (var));
2548 break;
2551 if (i >= imax)
2552 cmd_error_internal
2553 (Fcons (Qerror,
2554 Fcons (build_string ("no usable temporary directories found!!"),
2555 Qnil)),
2556 "While setting TMPDIR: ");
2558 /* Check for environment variables and use registry settings if they
2559 don't exist. Fallback on default values where applicable. */
2561 int i;
2562 LPBYTE lpval;
2563 DWORD dwType;
2564 char locale_name[32];
2565 char default_home[MAX_PATH];
2566 int appdata = 0;
2568 static const struct env_entry
2570 char * name;
2571 char * def_value;
2572 } dflt_envvars[] =
2574 /* If the default value is NULL, we will use the value from the
2575 outside environment or the Registry, but will not push the
2576 variable into the Emacs environment if it is defined neither
2577 in the Registry nor in the outside environment. */
2578 {"HOME", "C:/"},
2579 {"PRELOAD_WINSOCK", NULL},
2580 {"emacs_dir", "C:/emacs"},
2581 {"EMACSLOADPATH", NULL},
2582 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2583 {"EMACSDATA", NULL},
2584 {"EMACSPATH", NULL},
2585 {"INFOPATH", NULL},
2586 {"EMACSDOC", NULL},
2587 {"TERM", "cmd"},
2588 {"LANG", NULL},
2591 #define N_ENV_VARS ARRAYELTS (dflt_envvars)
2593 /* We need to copy dflt_envvars[] and work on the copy because we
2594 don't want the dumped Emacs to inherit the values of
2595 environment variables we saw during dumping (which could be on
2596 a different system). The defaults above must be left intact. */
2597 struct env_entry env_vars[N_ENV_VARS];
2599 for (i = 0; i < N_ENV_VARS; i++)
2600 env_vars[i] = dflt_envvars[i];
2602 /* For backwards compatibility, check if a .emacs file exists in C:/
2603 If not, then we can try to default to the appdata directory under the
2604 user's profile, which is more likely to be writable. */
2605 if (sys_access ("C:/.emacs", F_OK) != 0)
2607 HRESULT profile_result;
2608 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2609 of Windows 95 and NT4 that have not been updated to include
2610 MSIE 5. */
2611 ShGetFolderPath_fn get_folder_path;
2612 get_folder_path = (ShGetFolderPath_fn)
2613 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2615 if (get_folder_path != NULL)
2617 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2618 0, default_home);
2620 /* If we can't get the appdata dir, revert to old behavior. */
2621 if (profile_result == S_OK)
2623 env_vars[0].def_value = default_home;
2624 appdata = 1;
2629 /* Get default locale info and use it for LANG. */
2630 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2631 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2632 locale_name, sizeof (locale_name)))
2634 for (i = 0; i < N_ENV_VARS; i++)
2636 if (strcmp (env_vars[i].name, "LANG") == 0)
2638 env_vars[i].def_value = locale_name;
2639 break;
2644 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2646 /* Treat emacs_dir specially: set it unconditionally based on our
2647 location. */
2649 char *p;
2650 char modname[MAX_PATH];
2652 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2653 emacs_abort ();
2654 if ((p = _mbsrchr (modname, '\\')) == NULL)
2655 emacs_abort ();
2656 *p = 0;
2658 if ((p = _mbsrchr (modname, '\\'))
2659 /* From bin means installed Emacs, from src means uninstalled. */
2660 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2662 char buf[SET_ENV_BUF_SIZE];
2663 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2665 *p = 0;
2666 for (p = modname; *p; p = CharNext (p))
2667 if (*p == '\\') *p = '/';
2669 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2670 _putenv (strdup (buf));
2671 /* If we are running from the Posix-like build tree, define
2672 SHELL to point to our own cmdproxy. The loop below will
2673 then disregard PATH_EXEC and the default value. */
2674 if (within_build_tree)
2676 _snprintf (buf, sizeof (buf) - 1,
2677 "SHELL=%s/nt/cmdproxy.exe", modname);
2678 _putenv (strdup (buf));
2683 for (i = 0; i < N_ENV_VARS; i++)
2685 if (!getenv (env_vars[i].name))
2687 int dont_free = 0;
2688 char bufc[SET_ENV_BUF_SIZE];
2690 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2691 /* Also ignore empty environment variables. */
2692 || *lpval == 0)
2694 xfree (lpval);
2695 dont_free = 1;
2696 if (strcmp (env_vars[i].name, "SHELL") == 0)
2698 /* Look for cmdproxy.exe in every directory in
2699 PATH_EXEC. FIXME: This does not find cmdproxy
2700 in nt/ when we run uninstalled. */
2701 char fname[MAX_PATH];
2702 const char *pstart = PATH_EXEC, *pend;
2704 do {
2705 pend = _mbschr (pstart, ';');
2706 if (!pend)
2707 pend = pstart + strlen (pstart);
2708 /* Be defensive against series of ;;; characters. */
2709 if (pend > pstart)
2711 strncpy (fname, pstart, pend - pstart);
2712 fname[pend - pstart] = '/';
2713 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2714 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2715 sizeof (bufc));
2716 if (sys_access (bufc, F_OK) == 0)
2718 lpval = bufc;
2719 dwType = REG_SZ;
2720 break;
2723 if (*pend)
2724 pstart = pend + 1;
2725 else
2726 pstart = pend;
2727 if (!*pstart)
2729 /* If not found in any directory, use the
2730 default as the last resort. */
2731 lpval = env_vars[i].def_value;
2732 dwType = REG_EXPAND_SZ;
2734 } while (*pstart);
2736 else
2738 lpval = env_vars[i].def_value;
2739 dwType = REG_EXPAND_SZ;
2741 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2742 Vdelayed_warnings_list
2743 = Fcons (listn (CONSTYPE_HEAP, 2,
2744 intern ("initialization"),
2745 build_string ("Setting HOME to C:\\ by default is deprecated")),
2746 Vdelayed_warnings_list);
2749 if (lpval)
2751 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2753 if (dwType == REG_EXPAND_SZ)
2754 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2755 else if (dwType == REG_SZ)
2756 strcpy (buf1, lpval);
2757 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2759 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2760 buf1);
2761 _putenv (strdup (buf2));
2764 if (!dont_free)
2765 xfree (lpval);
2771 /* Rebuild system configuration to reflect invoking system. */
2772 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2774 /* Another special case: on NT, the PATH variable is actually named
2775 "Path" although cmd.exe (perhaps NT itself) arranges for
2776 environment variable lookup and setting to be case insensitive.
2777 However, Emacs assumes a fully case sensitive environment, so we
2778 need to change "Path" to "PATH" to match the expectations of
2779 various elisp packages. We do this by the sneaky method of
2780 modifying the string in the C runtime environ entry.
2782 The same applies to COMSPEC. */
2784 char ** envp;
2786 for (envp = environ; *envp; envp++)
2787 if (_strnicmp (*envp, "PATH=", 5) == 0)
2788 memcpy (*envp, "PATH=", 5);
2789 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
2790 memcpy (*envp, "COMSPEC=", 8);
2793 /* Remember the initial working directory for getcwd. */
2794 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2795 Does it matter anywhere in Emacs? */
2796 if (w32_unicode_filenames)
2798 wchar_t wstartup_dir[MAX_PATH];
2800 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2801 emacs_abort ();
2802 filename_from_utf16 (wstartup_dir, startup_dir);
2804 else
2806 char astartup_dir[MAX_PATH];
2808 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2809 emacs_abort ();
2810 filename_from_ansi (astartup_dir, startup_dir);
2814 static char modname[MAX_PATH];
2816 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2817 emacs_abort ();
2818 argv[0] = modname;
2821 /* Determine if there is a middle mouse button, to allow parse_button
2822 to decide whether right mouse events should be mouse-2 or
2823 mouse-3. */
2824 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2826 init_user_info ();
2829 /* Called from expand-file-name when default-directory is not a string. */
2831 char *
2832 emacs_root_dir (void)
2834 static char root_dir[MAX_UTF8_PATH];
2835 const char *p;
2837 p = getenv ("emacs_dir");
2838 if (p == NULL)
2839 emacs_abort ();
2840 filename_from_ansi (p, root_dir);
2841 root_dir[parse_root (root_dir, NULL)] = '\0';
2842 dostounix_filename (root_dir);
2843 return root_dir;
2846 #include <sys/timeb.h>
2848 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2850 gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
2852 struct _timeb tb;
2853 _ftime (&tb);
2855 tv->tv_sec = tb.time;
2856 tv->tv_usec = tb.millitm * 1000L;
2857 /* Implementation note: _ftime sometimes doesn't update the dstflag
2858 according to the new timezone when the system timezone is
2859 changed. We could fix that by using GetSystemTime and
2860 GetTimeZoneInformation, but that doesn't seem necessary, since
2861 Emacs always calls gettimeofday with the 2nd argument NULL (see
2862 current_emacs_time). */
2863 if (tz)
2865 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2866 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2868 return 0;
2871 /* Emulate fdutimens. */
2873 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2874 TIMESPEC[0] and TIMESPEC[1], respectively.
2875 FD must be either negative -- in which case it is ignored --
2876 or a file descriptor that is open on FILE.
2877 If FD is nonnegative, then FILE can be NULL, which means
2878 use just futimes instead of utimes.
2879 If TIMESPEC is null, FAIL.
2880 Return 0 on success, -1 (setting errno) on failure. */
2883 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2885 if (!timespec)
2887 errno = ENOSYS;
2888 return -1;
2890 if (fd < 0 && !file)
2892 errno = EBADF;
2893 return -1;
2895 /* _futime's prototype defines 2nd arg as having the type 'struct
2896 _utimbuf', while utime needs to accept 'struct utimbuf' for
2897 compatibility with Posix. So we need to use 2 different (but
2898 equivalent) types to avoid compiler warnings, sigh. */
2899 if (fd >= 0)
2901 struct _utimbuf _ut;
2903 _ut.actime = timespec[0].tv_sec;
2904 _ut.modtime = timespec[1].tv_sec;
2905 return _futime (fd, &_ut);
2907 else
2909 struct utimbuf ut;
2911 ut.actime = timespec[0].tv_sec;
2912 ut.modtime = timespec[1].tv_sec;
2913 /* Call 'utime', which is implemented below, not the MS library
2914 function, which fails on directories. */
2915 return utime (file, &ut);
2920 /* ------------------------------------------------------------------------- */
2921 /* IO support and wrapper functions for the Windows API. */
2922 /* ------------------------------------------------------------------------- */
2924 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2925 on network directories, so we handle that case here.
2926 (Ulrich Leodolter, 1/11/95). */
2927 char *
2928 sys_ctime (const time_t *t)
2930 char *str = (char *) ctime (t);
2931 return (str ? str : "Sun Jan 01 00:00:00 1970");
2934 /* Emulate sleep...we could have done this with a define, but that
2935 would necessitate including windows.h in the files that used it.
2936 This is much easier. */
2937 void
2938 sys_sleep (int seconds)
2940 Sleep (seconds * 1000);
2943 /* Internal MSVC functions for low-level descriptor munging */
2944 extern int __cdecl _set_osfhnd (int fd, long h);
2945 extern int __cdecl _free_osfhnd (int fd);
2947 /* parallel array of private info on file handles */
2948 filedesc fd_info [ MAXDESC ];
2950 typedef struct volume_info_data {
2951 struct volume_info_data * next;
2953 /* time when info was obtained */
2954 DWORD timestamp;
2956 /* actual volume info */
2957 char * root_dir;
2958 DWORD serialnum;
2959 DWORD maxcomp;
2960 DWORD flags;
2961 char * name;
2962 char * type;
2963 } volume_info_data;
2965 /* Global referenced by various functions. */
2966 static volume_info_data volume_info;
2968 /* Vector to indicate which drives are local and fixed (for which cached
2969 data never expires). */
2970 static BOOL fixed_drives[26];
2972 /* Consider cached volume information to be stale if older than 10s,
2973 at least for non-local drives. Info for fixed drives is never stale. */
2974 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2975 #define VOLINFO_STILL_VALID( root_dir, info ) \
2976 ( ( isalpha (root_dir[0]) && \
2977 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2978 || GetTickCount () - info->timestamp < 10000 )
2980 /* Cache support functions. */
2982 /* Simple linked list with linear search is sufficient. */
2983 static volume_info_data *volume_cache = NULL;
2985 static volume_info_data *
2986 lookup_volume_info (char * root_dir)
2988 volume_info_data * info;
2990 for (info = volume_cache; info; info = info->next)
2991 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2992 break;
2993 return info;
2996 static void
2997 add_volume_info (char * root_dir, volume_info_data * info)
2999 info->root_dir = xstrdup (root_dir);
3000 unixtodos_filename (info->root_dir);
3001 info->next = volume_cache;
3002 volume_cache = info;
3006 /* Wrapper for GetVolumeInformation, which uses caching to avoid
3007 performance penalty (~2ms on 486 for local drives, 7.5ms for local
3008 cdrom drive, ~5-10ms or more for remote drives on LAN). */
3009 static volume_info_data *
3010 GetCachedVolumeInformation (char * root_dir)
3012 volume_info_data * info;
3013 char default_root[ MAX_UTF8_PATH ];
3014 char name[MAX_PATH+1];
3015 char type[MAX_PATH+1];
3017 /* NULL for root_dir means use root from current directory. */
3018 if (root_dir == NULL)
3020 if (w32_unicode_filenames)
3022 wchar_t curdirw[MAX_PATH];
3024 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
3025 return NULL;
3026 filename_from_utf16 (curdirw, default_root);
3028 else
3030 char curdira[MAX_PATH];
3032 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
3033 return NULL;
3034 filename_from_ansi (curdira, default_root);
3036 parse_root (default_root, (const char **)&root_dir);
3037 *root_dir = 0;
3038 root_dir = default_root;
3041 /* Local fixed drives can be cached permanently. Removable drives
3042 cannot be cached permanently, since the volume name and serial
3043 number (if nothing else) can change. Remote drives should be
3044 treated as if they are removable, since there is no sure way to
3045 tell whether they are or not. Also, the UNC association of drive
3046 letters mapped to remote volumes can be changed at any time (even
3047 by other processes) without notice.
3049 As a compromise, so we can benefit from caching info for remote
3050 volumes, we use a simple expiry mechanism to invalidate cache
3051 entries that are more than ten seconds old. */
3053 #if 0
3054 /* No point doing this, because WNetGetConnection is even slower than
3055 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
3056 GetDriveType is about the only call of this type which does not
3057 involve network access, and so is extremely quick). */
3059 /* Map drive letter to UNC if remote. */
3060 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
3062 char remote_name[ 256 ];
3063 char drive[3] = { root_dir[0], ':' };
3065 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
3066 == NO_ERROR)
3067 /* do something */ ;
3069 #endif
3071 info = lookup_volume_info (root_dir);
3073 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
3075 DWORD serialnum;
3076 DWORD maxcomp;
3077 DWORD flags;
3079 /* Info is not cached, or is stale. */
3080 if (w32_unicode_filenames)
3082 wchar_t root_w[MAX_PATH];
3083 wchar_t name_w[MAX_PATH+1];
3084 wchar_t type_w[MAX_PATH+1];
3086 filename_to_utf16 (root_dir, root_w);
3087 if (!GetVolumeInformationW (root_w,
3088 name_w, sizeof (name_w),
3089 &serialnum,
3090 &maxcomp,
3091 &flags,
3092 type_w, sizeof (type_w)))
3093 return NULL;
3094 /* Hmm... not really 100% correct, as these 2 are not file
3095 names... */
3096 filename_from_utf16 (name_w, name);
3097 filename_from_utf16 (type_w, type);
3099 else
3101 char root_a[MAX_PATH];
3102 char name_a[MAX_PATH+1];
3103 char type_a[MAX_PATH+1];
3105 filename_to_ansi (root_dir, root_a);
3106 if (!GetVolumeInformationA (root_a,
3107 name_a, sizeof (name_a),
3108 &serialnum,
3109 &maxcomp,
3110 &flags,
3111 type_a, sizeof (type_a)))
3112 return NULL;
3113 filename_from_ansi (name_a, name);
3114 filename_from_ansi (type_a, type);
3117 /* Cache the volume information for future use, overwriting existing
3118 entry if present. */
3119 if (info == NULL)
3121 info = xmalloc (sizeof (volume_info_data));
3122 add_volume_info (root_dir, info);
3124 else
3126 xfree (info->name);
3127 xfree (info->type);
3130 info->name = xstrdup (name);
3131 unixtodos_filename (info->name);
3132 info->serialnum = serialnum;
3133 info->maxcomp = maxcomp;
3134 info->flags = flags;
3135 info->type = xstrdup (type);
3136 info->timestamp = GetTickCount ();
3139 return info;
3142 /* Get information on the volume where NAME is held; set path pointer to
3143 start of pathname in NAME (past UNC header\volume header if present),
3144 if pPath is non-NULL.
3146 Note: if NAME includes symlinks, the information is for the volume
3147 of the symlink, not of its target. That's because, even though
3148 GetVolumeInformation returns information about the symlink target
3149 of its argument, we only pass the root directory to
3150 GetVolumeInformation, not the full NAME. */
3151 static int
3152 get_volume_info (const char * name, const char ** pPath)
3154 char temp[MAX_UTF8_PATH];
3155 char *rootname = NULL; /* default to current volume */
3156 volume_info_data * info;
3157 int root_len = parse_root (name, pPath);
3159 if (name == NULL)
3160 return FALSE;
3162 /* Copy the root name of the volume, if given. */
3163 if (root_len)
3165 strncpy (temp, name, root_len);
3166 temp[root_len] = '\0';
3167 unixtodos_filename (temp);
3168 rootname = temp;
3171 info = GetCachedVolumeInformation (rootname);
3172 if (info != NULL)
3174 /* Set global referenced by other functions. */
3175 volume_info = *info;
3176 return TRUE;
3178 return FALSE;
3181 /* Determine if volume is FAT format (ie. only supports short 8.3
3182 names); also set path pointer to start of pathname in name, if
3183 pPath is non-NULL. */
3184 static int
3185 is_fat_volume (const char * name, const char ** pPath)
3187 if (get_volume_info (name, pPath))
3188 return (volume_info.maxcomp == 12);
3189 return FALSE;
3192 /* Convert all slashes in a filename to backslashes, and map filename
3193 to a valid 8.3 name if necessary. The result is a pointer to a
3194 static buffer, so CAVEAT EMPTOR! */
3195 const char *
3196 map_w32_filename (const char * name, const char ** pPath)
3198 static char shortname[MAX_UTF8_PATH];
3199 char * str = shortname;
3200 char c;
3201 char * path;
3202 const char * save_name = name;
3204 if (strlen (name) >= sizeof (shortname))
3206 /* Return a filename which will cause callers to fail. */
3207 strcpy (shortname, "?");
3208 return shortname;
3211 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3213 register int left = 8; /* maximum number of chars in part */
3214 register int extn = 0; /* extension added? */
3215 register int dots = 2; /* maximum number of dots allowed */
3217 while (name < path)
3218 *str++ = *name++; /* skip past UNC header */
3220 while ((c = *name++))
3222 switch ( c )
3224 case ':':
3225 case '\\':
3226 case '/':
3227 *str++ = (c == ':' ? ':' : '\\');
3228 extn = 0; /* reset extension flags */
3229 dots = 2; /* max 2 dots */
3230 left = 8; /* max length 8 for main part */
3231 break;
3232 case '.':
3233 if ( dots )
3235 /* Convert path components of the form .xxx to _xxx,
3236 but leave . and .. as they are. This allows .emacs
3237 to be read as _emacs, for example. */
3239 if (! *name ||
3240 *name == '.' ||
3241 IS_DIRECTORY_SEP (*name))
3243 *str++ = '.';
3244 dots--;
3246 else
3248 *str++ = '_';
3249 left--;
3250 dots = 0;
3253 else if ( !extn )
3255 *str++ = '.';
3256 extn = 1; /* we've got an extension */
3257 left = 3; /* 3 chars in extension */
3259 else
3261 /* any embedded dots after the first are converted to _ */
3262 *str++ = '_';
3264 break;
3265 case '~':
3266 case '#': /* don't lose these, they're important */
3267 if ( ! left )
3268 str[-1] = c; /* replace last character of part */
3269 /* FALLTHRU */
3270 default:
3271 if ( left && 'A' <= c && c <= 'Z' )
3273 *str++ = tolower (c); /* map to lower case (looks nicer) */
3274 left--;
3275 dots = 0; /* started a path component */
3277 break;
3280 *str = '\0';
3282 else
3284 strcpy (shortname, name);
3285 unixtodos_filename (shortname);
3288 if (pPath)
3289 *pPath = shortname + (path - save_name);
3291 return shortname;
3294 static int
3295 is_exec (const char * name)
3297 char * p = strrchr (name, '.');
3298 return
3299 (p != NULL
3300 && (xstrcasecmp (p, ".exe") == 0 ||
3301 xstrcasecmp (p, ".com") == 0 ||
3302 xstrcasecmp (p, ".bat") == 0 ||
3303 xstrcasecmp (p, ".cmd") == 0));
3306 /* Emulate the Unix directory procedures opendir, closedir, and
3307 readdir. We rename them to sys_* names because some versions of
3308 MinGW startup code call opendir and readdir to glob wildcards, and
3309 the code that calls them doesn't grok UTF-8 encoded file names we
3310 produce in dirent->d_name[]. */
3312 struct dirent dir_static; /* simulated directory contents */
3313 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3314 static int dir_is_fat;
3315 static char dir_pathname[MAX_UTF8_PATH];
3316 static WIN32_FIND_DATAW dir_find_data_w;
3317 static WIN32_FIND_DATAA dir_find_data_a;
3318 #define DIR_FIND_DATA_W 1
3319 #define DIR_FIND_DATA_A 2
3320 static int last_dir_find_data = -1;
3322 /* Support shares on a network resource as subdirectories of a read-only
3323 root directory. */
3324 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3325 static HANDLE open_unc_volume (const char *);
3326 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3327 static void close_unc_volume (HANDLE);
3329 DIR *
3330 sys_opendir (const char *filename)
3332 DIR *dirp;
3334 /* Opening is done by FindFirstFile. However, a read is inherent to
3335 this operation, so we defer the open until read time. */
3337 if (dir_find_handle != INVALID_HANDLE_VALUE)
3338 return NULL;
3339 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3340 return NULL;
3342 /* Note: We don't support traversal of UNC volumes via symlinks.
3343 Doing so would mean punishing 99.99% of use cases by resolving
3344 all the possible symlinks in FILENAME, recursively. */
3345 if (is_unc_volume (filename))
3347 wnet_enum_handle = open_unc_volume (filename);
3348 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3349 return NULL;
3352 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3353 return NULL;
3355 dirp->dd_fd = 0;
3356 dirp->dd_loc = 0;
3357 dirp->dd_size = 0;
3359 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3360 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3361 /* Note: We don't support symlinks to file names on FAT volumes.
3362 Doing so would mean punishing 99.99% of use cases by resolving
3363 all the possible symlinks in FILENAME, recursively. */
3364 dir_is_fat = is_fat_volume (filename, NULL);
3366 return dirp;
3369 void
3370 sys_closedir (DIR *dirp)
3372 /* If we have a find-handle open, close it. */
3373 if (dir_find_handle != INVALID_HANDLE_VALUE)
3375 FindClose (dir_find_handle);
3376 dir_find_handle = INVALID_HANDLE_VALUE;
3378 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3380 close_unc_volume (wnet_enum_handle);
3381 wnet_enum_handle = INVALID_HANDLE_VALUE;
3383 xfree ((char *) dirp);
3386 struct dirent *
3387 sys_readdir (DIR *dirp)
3389 int downcase = !NILP (Vw32_downcase_file_names);
3391 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3393 if (!read_unc_volume (wnet_enum_handle,
3394 dir_find_data_w.cFileName,
3395 dir_find_data_a.cFileName,
3396 MAX_PATH))
3397 return NULL;
3399 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3400 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3402 char filename[MAX_UTF8_PATH + 2];
3403 int ln;
3405 strcpy (filename, dir_pathname);
3406 ln = strlen (filename) - 1;
3407 if (!IS_DIRECTORY_SEP (filename[ln]))
3408 strcat (filename, "\\");
3409 strcat (filename, "*");
3411 /* Note: No need to resolve symlinks in FILENAME, because
3412 FindFirst opens the directory that is the target of a
3413 symlink. */
3414 if (w32_unicode_filenames)
3416 wchar_t fnw[MAX_PATH];
3418 filename_to_utf16 (filename, fnw);
3419 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3421 else
3423 char fna[MAX_PATH];
3425 filename_to_ansi (filename, fna);
3426 /* If FILENAME is not representable by the current ANSI
3427 codepage, we don't want FindFirstFileA to interpret the
3428 '?' characters as a wildcard. */
3429 if (_mbspbrk (fna, "?"))
3430 dir_find_handle = INVALID_HANDLE_VALUE;
3431 else
3432 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3435 if (dir_find_handle == INVALID_HANDLE_VALUE)
3436 return NULL;
3438 else if (w32_unicode_filenames)
3440 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3441 return NULL;
3443 else
3445 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3446 return NULL;
3449 /* Emacs never uses this value, so don't bother making it match
3450 value returned by stat(). */
3451 dir_static.d_ino = 1;
3453 if (w32_unicode_filenames)
3455 if (downcase || dir_is_fat)
3457 wchar_t tem[MAX_PATH];
3459 wcscpy (tem, dir_find_data_w.cFileName);
3460 CharLowerW (tem);
3461 filename_from_utf16 (tem, dir_static.d_name);
3463 else
3464 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3465 last_dir_find_data = DIR_FIND_DATA_W;
3467 else
3469 char tem[MAX_PATH];
3471 /* If the file name in cFileName[] includes `?' characters, it
3472 means the original file name used characters that cannot be
3473 represented by the current ANSI codepage. To avoid total
3474 lossage, retrieve the short 8+3 alias of the long file
3475 name. */
3476 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3478 strcpy (tem, dir_find_data_a.cAlternateFileName);
3479 /* 8+3 aliases are returned in all caps, which could break
3480 various alists that look at filenames' extensions. */
3481 downcase = 1;
3483 else if (downcase || dir_is_fat)
3484 strcpy (tem, dir_find_data_a.cFileName);
3485 else
3486 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3487 if (downcase || dir_is_fat)
3489 _mbslwr (tem);
3490 filename_from_ansi (tem, dir_static.d_name);
3492 last_dir_find_data = DIR_FIND_DATA_A;
3495 dir_static.d_namlen = strlen (dir_static.d_name);
3496 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3497 dir_static.d_namlen - dir_static.d_namlen % 4;
3499 return &dir_static;
3502 static HANDLE
3503 open_unc_volume (const char *path)
3505 const char *fn = map_w32_filename (path, NULL);
3506 DWORD result;
3507 HANDLE henum;
3509 if (w32_unicode_filenames)
3511 NETRESOURCEW nrw;
3512 wchar_t fnw[MAX_PATH];
3514 nrw.dwScope = RESOURCE_GLOBALNET;
3515 nrw.dwType = RESOURCETYPE_DISK;
3516 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3517 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3518 nrw.lpLocalName = NULL;
3519 filename_to_utf16 (fn, fnw);
3520 nrw.lpRemoteName = fnw;
3521 nrw.lpComment = NULL;
3522 nrw.lpProvider = NULL;
3524 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3525 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3527 else
3529 NETRESOURCEA nra;
3530 char fna[MAX_PATH];
3532 nra.dwScope = RESOURCE_GLOBALNET;
3533 nra.dwType = RESOURCETYPE_DISK;
3534 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3535 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3536 nra.lpLocalName = NULL;
3537 filename_to_ansi (fn, fna);
3538 nra.lpRemoteName = fna;
3539 nra.lpComment = NULL;
3540 nra.lpProvider = NULL;
3542 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3543 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3545 if (result == NO_ERROR)
3546 return henum;
3547 else
3548 return INVALID_HANDLE_VALUE;
3551 static void *
3552 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3554 DWORD count;
3555 int result;
3556 char *buffer;
3557 DWORD bufsize = 512;
3558 void *retval;
3560 count = 1;
3561 if (w32_unicode_filenames)
3563 wchar_t *ptrw;
3565 bufsize *= 2;
3566 buffer = alloca (bufsize);
3567 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3568 if (result != NO_ERROR)
3569 return NULL;
3570 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3571 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3572 ptrw += 2;
3573 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3574 ptrw++;
3575 wcsncpy (fname_w, ptrw, size);
3576 retval = fname_w;
3578 else
3580 int dbcs_p = max_filename_mbslen () > 1;
3581 char *ptra;
3583 buffer = alloca (bufsize);
3584 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3585 if (result != NO_ERROR)
3586 return NULL;
3587 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3588 ptra += 2;
3589 if (!dbcs_p)
3590 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3591 else
3593 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3594 ptra = CharNextExA (file_name_codepage, ptra, 0);
3596 ptra++;
3597 strncpy (fname_a, ptra, size);
3598 retval = fname_a;
3601 return retval;
3604 static void
3605 close_unc_volume (HANDLE henum)
3607 if (henum != INVALID_HANDLE_VALUE)
3608 WNetCloseEnum (henum);
3611 static DWORD
3612 unc_volume_file_attributes (const char *path)
3614 HANDLE henum;
3615 DWORD attrs;
3617 henum = open_unc_volume (path);
3618 if (henum == INVALID_HANDLE_VALUE)
3619 return -1;
3621 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3623 close_unc_volume (henum);
3625 return attrs;
3628 /* Ensure a network connection is authenticated. */
3629 static void
3630 logon_network_drive (const char *path)
3632 char share[MAX_UTF8_PATH];
3633 int n_slashes;
3634 char drive[4];
3635 UINT drvtype;
3636 char *p;
3637 DWORD val;
3639 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3640 drvtype = DRIVE_REMOTE;
3641 else if (path[0] == '\0' || path[1] != ':')
3642 drvtype = GetDriveType (NULL);
3643 else
3645 drive[0] = path[0];
3646 drive[1] = ':';
3647 drive[2] = '\\';
3648 drive[3] = '\0';
3649 drvtype = GetDriveType (drive);
3652 /* Only logon to networked drives. */
3653 if (drvtype != DRIVE_REMOTE)
3654 return;
3656 n_slashes = 2;
3657 strncpy (share, path, MAX_UTF8_PATH);
3658 /* Truncate to just server and share name. */
3659 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3661 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3663 *p = '\0';
3664 break;
3668 if (w32_unicode_filenames)
3670 NETRESOURCEW resourcew;
3671 wchar_t share_w[MAX_PATH];
3673 resourcew.dwScope = RESOURCE_GLOBALNET;
3674 resourcew.dwType = RESOURCETYPE_DISK;
3675 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3676 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3677 resourcew.lpLocalName = NULL;
3678 filename_to_utf16 (share, share_w);
3679 resourcew.lpRemoteName = share_w;
3680 resourcew.lpProvider = NULL;
3682 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3684 else
3686 NETRESOURCEA resourcea;
3687 char share_a[MAX_PATH];
3689 resourcea.dwScope = RESOURCE_GLOBALNET;
3690 resourcea.dwType = RESOURCETYPE_DISK;
3691 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3692 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3693 resourcea.lpLocalName = NULL;
3694 filename_to_ansi (share, share_a);
3695 resourcea.lpRemoteName = share_a;
3696 resourcea.lpProvider = NULL;
3698 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3701 switch (val)
3703 case NO_ERROR:
3704 case ERROR_ALREADY_ASSIGNED:
3705 break;
3706 case ERROR_ACCESS_DENIED:
3707 case ERROR_LOGON_FAILURE:
3708 errno = EACCES;
3709 break;
3710 case ERROR_BUSY:
3711 errno = EAGAIN;
3712 break;
3713 case ERROR_BAD_NET_NAME:
3714 case ERROR_NO_NET_OR_BAD_PATH:
3715 case ERROR_NO_NETWORK:
3716 case ERROR_CANCELLED:
3717 default:
3718 errno = ENOENT;
3719 break;
3723 /* Emulate faccessat(2). */
3725 faccessat (int dirfd, const char * path, int mode, int flags)
3727 DWORD attributes;
3729 if (dirfd != AT_FDCWD
3730 && !(IS_DIRECTORY_SEP (path[0])
3731 || IS_DEVICE_SEP (path[1])))
3733 errno = EBADF;
3734 return -1;
3737 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3738 newer versions blow up when passed D_OK. */
3739 path = map_w32_filename (path, NULL);
3740 /* If the last element of PATH is a symlink, we need to resolve it
3741 to get the attributes of its target file. Note: any symlinks in
3742 PATH elements other than the last one are transparently resolved
3743 by GetFileAttributes below. */
3744 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3745 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3746 path = chase_symlinks (path);
3748 if (w32_unicode_filenames)
3750 wchar_t path_w[MAX_PATH];
3752 filename_to_utf16 (path, path_w);
3753 attributes = GetFileAttributesW (path_w);
3755 else
3757 char path_a[MAX_PATH];
3759 filename_to_ansi (path, path_a);
3760 attributes = GetFileAttributesA (path_a);
3763 if (attributes == -1)
3765 DWORD w32err = GetLastError ();
3767 switch (w32err)
3769 case ERROR_INVALID_NAME:
3770 case ERROR_BAD_PATHNAME:
3771 if (is_unc_volume (path))
3773 attributes = unc_volume_file_attributes (path);
3774 if (attributes == -1)
3776 errno = EACCES;
3777 return -1;
3779 break;
3781 /* FALLTHROUGH */
3782 case ERROR_FILE_NOT_FOUND:
3783 case ERROR_BAD_NETPATH:
3784 errno = ENOENT;
3785 break;
3786 default:
3787 errno = EACCES;
3788 break;
3790 return -1;
3792 if ((mode & X_OK) != 0
3793 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3795 errno = EACCES;
3796 return -1;
3798 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3800 errno = EACCES;
3801 return -1;
3803 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3805 errno = EACCES;
3806 return -1;
3808 return 0;
3811 /* A version of 'access' to be used locally with file names in
3812 locale-specific encoding. Does not resolve symlinks and does not
3813 support file names on FAT12 and FAT16 volumes, but that's OK, since
3814 we only invoke this function for files inside the Emacs source or
3815 installation tree, on directories (so any symlinks should have the
3816 directory bit set), and on short file names such as "C:/.emacs". */
3817 static int
3818 sys_access (const char *fname, int mode)
3820 char fname_copy[MAX_PATH], *p;
3821 DWORD attributes;
3823 strcpy (fname_copy, fname);
3824 /* Do the equivalent of unixtodos_filename. */
3825 for (p = fname_copy; *p; p = CharNext (p))
3826 if (*p == '/')
3827 *p = '\\';
3829 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
3831 DWORD w32err = GetLastError ();
3833 switch (w32err)
3835 case ERROR_INVALID_NAME:
3836 case ERROR_BAD_PATHNAME:
3837 case ERROR_FILE_NOT_FOUND:
3838 case ERROR_BAD_NETPATH:
3839 errno = ENOENT;
3840 break;
3841 default:
3842 errno = EACCES;
3843 break;
3845 return -1;
3847 if ((mode & X_OK) != 0
3848 && !(is_exec (fname_copy)
3849 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3851 errno = EACCES;
3852 return -1;
3854 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3856 errno = EACCES;
3857 return -1;
3859 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3861 errno = EACCES;
3862 return -1;
3864 return 0;
3867 /* Shadow some MSVC runtime functions to map requests for long filenames
3868 to reasonable short names if necessary. This was originally added to
3869 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3870 long file names. */
3873 sys_chdir (const char * path)
3875 path = map_w32_filename (path, NULL);
3876 if (w32_unicode_filenames)
3878 wchar_t newdir_w[MAX_PATH];
3880 if (filename_to_utf16 (path, newdir_w) == 0)
3881 return _wchdir (newdir_w);
3882 return -1;
3884 else
3886 char newdir_a[MAX_PATH];
3888 if (filename_to_ansi (path, newdir_a) == 0)
3889 return _chdir (newdir_a);
3890 return -1;
3895 sys_chmod (const char * path, int mode)
3897 path = chase_symlinks (map_w32_filename (path, NULL));
3898 if (w32_unicode_filenames)
3900 wchar_t path_w[MAX_PATH];
3902 filename_to_utf16 (path, path_w);
3903 return _wchmod (path_w, mode);
3905 else
3907 char path_a[MAX_PATH];
3909 filename_to_ansi (path, path_a);
3910 return _chmod (path_a, mode);
3915 sys_creat (const char * path, int mode)
3917 path = map_w32_filename (path, NULL);
3918 if (w32_unicode_filenames)
3920 wchar_t path_w[MAX_PATH];
3922 filename_to_utf16 (path, path_w);
3923 return _wcreat (path_w, mode);
3925 else
3927 char path_a[MAX_PATH];
3929 filename_to_ansi (path, path_a);
3930 return _creat (path_a, mode);
3934 FILE *
3935 sys_fopen (const char * path, const char * mode)
3937 int fd;
3938 int oflag;
3939 const char * mode_save = mode;
3941 /* Force all file handles to be non-inheritable. This is necessary to
3942 ensure child processes don't unwittingly inherit handles that might
3943 prevent future file access. */
3945 if (mode[0] == 'r')
3946 oflag = O_RDONLY;
3947 else if (mode[0] == 'w' || mode[0] == 'a')
3948 oflag = O_WRONLY | O_CREAT | O_TRUNC;
3949 else
3950 return NULL;
3952 /* Only do simplistic option parsing. */
3953 while (*++mode)
3954 if (mode[0] == '+')
3956 oflag &= ~(O_RDONLY | O_WRONLY);
3957 oflag |= O_RDWR;
3959 else if (mode[0] == 'b')
3961 oflag &= ~O_TEXT;
3962 oflag |= O_BINARY;
3964 else if (mode[0] == 't')
3966 oflag &= ~O_BINARY;
3967 oflag |= O_TEXT;
3969 else break;
3971 path = map_w32_filename (path, NULL);
3972 if (w32_unicode_filenames)
3974 wchar_t path_w[MAX_PATH];
3976 filename_to_utf16 (path, path_w);
3977 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
3979 else
3981 char path_a[MAX_PATH];
3983 filename_to_ansi (path, path_a);
3984 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
3986 if (fd < 0)
3987 return NULL;
3989 return _fdopen (fd, mode_save);
3992 /* This only works on NTFS volumes, but is useful to have. */
3994 sys_link (const char * old, const char * new)
3996 HANDLE fileh;
3997 int result = -1;
3998 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
3999 wchar_t oldname_w[MAX_PATH];
4000 char oldname_a[MAX_PATH];
4002 if (old == NULL || new == NULL)
4004 errno = ENOENT;
4005 return -1;
4008 strcpy (oldname, map_w32_filename (old, NULL));
4009 strcpy (newname, map_w32_filename (new, NULL));
4011 if (w32_unicode_filenames)
4013 filename_to_utf16 (oldname, oldname_w);
4014 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
4015 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4017 else
4019 filename_to_ansi (oldname, oldname_a);
4020 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
4021 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4023 if (fileh != INVALID_HANDLE_VALUE)
4025 int wlen;
4027 /* Confusingly, the "alternate" stream name field does not apply
4028 when restoring a hard link, and instead contains the actual
4029 stream data for the link (ie. the name of the link to create).
4030 The WIN32_STREAM_ID structure before the cStreamName field is
4031 the stream header, which is then immediately followed by the
4032 stream data. */
4034 struct {
4035 WIN32_STREAM_ID wid;
4036 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
4037 } data;
4039 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
4040 indicates that flag is unsupported for CP_UTF8, and OTOH says
4041 it is the default anyway. */
4042 wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
4043 data.wid.cStreamName, MAX_PATH);
4044 if (wlen > 0)
4046 LPVOID context = NULL;
4047 DWORD wbytes = 0;
4049 data.wid.dwStreamId = BACKUP_LINK;
4050 data.wid.dwStreamAttributes = 0;
4051 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
4052 data.wid.Size.HighPart = 0;
4053 data.wid.dwStreamNameSize = 0;
4055 if (BackupWrite (fileh, (LPBYTE)&data,
4056 offsetof (WIN32_STREAM_ID, cStreamName)
4057 + data.wid.Size.LowPart,
4058 &wbytes, FALSE, FALSE, &context)
4059 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
4061 /* succeeded */
4062 result = 0;
4064 else
4066 DWORD err = GetLastError ();
4067 DWORD attributes;
4069 switch (err)
4071 case ERROR_ACCESS_DENIED:
4072 /* This is what happens when OLDNAME is a directory,
4073 since Windows doesn't support hard links to
4074 directories. Posix says to set errno to EPERM in
4075 that case. */
4076 if (w32_unicode_filenames)
4077 attributes = GetFileAttributesW (oldname_w);
4078 else
4079 attributes = GetFileAttributesA (oldname_a);
4080 if (attributes != -1
4081 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
4082 errno = EPERM;
4083 else if (attributes == -1
4084 && is_unc_volume (oldname)
4085 && unc_volume_file_attributes (oldname) != -1)
4086 errno = EPERM;
4087 else
4088 errno = EACCES;
4089 break;
4090 case ERROR_TOO_MANY_LINKS:
4091 errno = EMLINK;
4092 break;
4093 case ERROR_NOT_SAME_DEVICE:
4094 errno = EXDEV;
4095 break;
4096 default:
4097 errno = EINVAL;
4098 break;
4103 CloseHandle (fileh);
4105 else
4106 errno = ENOENT;
4108 return result;
4112 sys_mkdir (const char * path)
4114 path = map_w32_filename (path, NULL);
4116 if (w32_unicode_filenames)
4118 wchar_t path_w[MAX_PATH];
4120 filename_to_utf16 (path, path_w);
4121 return _wmkdir (path_w);
4123 else
4125 char path_a[MAX_PATH];
4127 filename_to_ansi (path, path_a);
4128 return _mkdir (path_a);
4133 sys_open (const char * path, int oflag, int mode)
4135 const char* mpath = map_w32_filename (path, NULL);
4136 int res = -1;
4138 if (w32_unicode_filenames)
4140 wchar_t mpath_w[MAX_PATH];
4142 filename_to_utf16 (mpath, mpath_w);
4143 /* If possible, try to open file without _O_CREAT, to be able to
4144 write to existing hidden and system files. Force all file
4145 handles to be non-inheritable. */
4146 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4147 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4148 if (res < 0)
4149 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4151 else
4153 char mpath_a[MAX_PATH];
4155 filename_to_ansi (mpath, mpath_a);
4156 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4157 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4158 if (res < 0)
4159 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4162 return res;
4165 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
4166 when using mktemp.
4168 Standard algorithm for generating a temporary file name seems to be
4169 use pid or tid with a letter on the front (in place of the 6 X's)
4170 and cycle through the letters to find a unique name. We extend
4171 that to allow any reasonable character as the first of the 6 X's,
4172 so that the number of simultaneously used temporary files will be
4173 greater. */
4176 mkostemp (char * template, int flags)
4178 char * p;
4179 int i, fd = -1;
4180 unsigned uid = GetCurrentThreadId ();
4181 int save_errno = errno;
4182 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
4184 errno = EINVAL;
4185 if (template == NULL)
4186 return -1;
4188 p = template + strlen (template);
4189 i = 5;
4190 /* replace up to the last 5 X's with uid in decimal */
4191 while (--p >= template && p[0] == 'X' && --i >= 0)
4193 p[0] = '0' + uid % 10;
4194 uid /= 10;
4197 if (i < 0 && p[0] == 'X')
4199 i = 0;
4202 p[0] = first_char[i];
4203 if ((fd = sys_open (template,
4204 flags | _O_CREAT | _O_EXCL | _O_RDWR,
4205 S_IRUSR | S_IWUSR)) >= 0
4206 || errno != EEXIST)
4208 if (fd >= 0)
4209 errno = save_errno;
4210 return fd;
4213 while (++i < sizeof (first_char));
4216 /* Template is badly formed or else we can't generate a unique name. */
4217 return -1;
4221 fchmod (int fd, mode_t mode)
4223 return 0;
4227 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4229 BOOL result;
4230 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4231 int newname_dev;
4232 int oldname_dev;
4233 bool have_temp_a = false;
4235 /* MoveFile on Windows 95 doesn't correctly change the short file name
4236 alias in a number of circumstances (it is not easy to predict when
4237 just by looking at oldname and newname, unfortunately). In these
4238 cases, renaming through a temporary name avoids the problem.
4240 A second problem on Windows 95 is that renaming through a temp name when
4241 newname is uppercase fails (the final long name ends up in
4242 lowercase, although the short alias might be uppercase) UNLESS the
4243 long temp name is not 8.3.
4245 So, on Windows 95 we always rename through a temp name, and we make sure
4246 the temp name has a long extension to ensure correct renaming. */
4248 strcpy (temp, map_w32_filename (oldname, NULL));
4250 /* volume_info is set indirectly by map_w32_filename. */
4251 oldname_dev = volume_info.serialnum;
4253 if (os_subtype == OS_9X)
4255 char * o;
4256 char * p;
4257 int i = 0;
4258 char oldname_a[MAX_PATH];
4260 oldname = map_w32_filename (oldname, NULL);
4261 filename_to_ansi (oldname, oldname_a);
4262 filename_to_ansi (temp, temp_a);
4263 if ((o = strrchr (oldname_a, '\\')))
4264 o++;
4265 else
4266 o = (char *) oldname_a;
4268 if ((p = strrchr (temp_a, '\\')))
4269 p++;
4270 else
4271 p = temp_a;
4275 /* Force temp name to require a manufactured 8.3 alias - this
4276 seems to make the second rename work properly. */
4277 sprintf (p, "_.%s.%u", o, i);
4278 i++;
4279 result = rename (oldname_a, temp_a);
4281 /* This loop must surely terminate! */
4282 while (result < 0 && errno == EEXIST);
4283 if (result < 0)
4284 return -1;
4285 have_temp_a = true;
4288 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4289 (at least if it is a file; don't do this for directories).
4291 Since we mustn't do this if we are just changing the case of the
4292 file name (we would end up deleting the file we are trying to
4293 rename!), we let rename detect if the destination file already
4294 exists - that way we avoid the possible pitfalls of trying to
4295 determine ourselves whether two names really refer to the same
4296 file, which is not always possible in the general case. (Consider
4297 all the permutations of shared or subst'd drives, etc.) */
4299 newname = map_w32_filename (newname, NULL);
4301 /* volume_info is set indirectly by map_w32_filename. */
4302 newname_dev = volume_info.serialnum;
4304 if (w32_unicode_filenames)
4306 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4308 filename_to_utf16 (temp, temp_w);
4309 filename_to_utf16 (newname, newname_w);
4310 result = _wrename (temp_w, newname_w);
4311 if (result < 0 && force)
4313 DWORD w32err = GetLastError ();
4315 if (errno == EACCES
4316 && newname_dev != oldname_dev)
4318 /* The implementation of `rename' on Windows does not return
4319 errno = EXDEV when you are moving a directory to a
4320 different storage device (ex. logical disk). It returns
4321 EACCES instead. So here we handle such situations and
4322 return EXDEV. */
4323 DWORD attributes;
4325 if ((attributes = GetFileAttributesW (temp_w)) != -1
4326 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4327 errno = EXDEV;
4329 else if (errno == EEXIST)
4331 if (_wchmod (newname_w, 0666) != 0)
4332 return result;
4333 if (_wunlink (newname_w) != 0)
4334 return result;
4335 result = _wrename (temp_w, newname_w);
4337 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4338 && is_symlink (temp))
4340 /* This is Windows prohibiting the user from creating a
4341 symlink in another place, since that requires
4342 privileges. */
4343 errno = EPERM;
4347 else
4349 char newname_a[MAX_PATH];
4351 if (!have_temp_a)
4352 filename_to_ansi (temp, temp_a);
4353 filename_to_ansi (newname, newname_a);
4354 result = rename (temp_a, newname_a);
4355 if (result < 0 && force)
4357 DWORD w32err = GetLastError ();
4359 if (errno == EACCES
4360 && newname_dev != oldname_dev)
4362 DWORD attributes;
4364 if ((attributes = GetFileAttributesA (temp_a)) != -1
4365 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4366 errno = EXDEV;
4368 else if (errno == EEXIST)
4370 if (_chmod (newname_a, 0666) != 0)
4371 return result;
4372 if (_unlink (newname_a) != 0)
4373 return result;
4374 result = rename (temp_a, newname_a);
4376 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4377 && is_symlink (temp))
4378 errno = EPERM;
4382 return result;
4386 sys_rename (char const *old, char const *new)
4388 return sys_rename_replace (old, new, TRUE);
4392 sys_rmdir (const char * path)
4394 path = map_w32_filename (path, NULL);
4396 if (w32_unicode_filenames)
4398 wchar_t path_w[MAX_PATH];
4400 filename_to_utf16 (path, path_w);
4401 return _wrmdir (path_w);
4403 else
4405 char path_a[MAX_PATH];
4407 filename_to_ansi (path, path_a);
4408 return _rmdir (path_a);
4413 sys_unlink (const char * path)
4415 path = map_w32_filename (path, NULL);
4417 if (w32_unicode_filenames)
4419 wchar_t path_w[MAX_PATH];
4421 filename_to_utf16 (path, path_w);
4422 /* On Unix, unlink works without write permission. */
4423 _wchmod (path_w, 0666);
4424 return _wunlink (path_w);
4426 else
4428 char path_a[MAX_PATH];
4430 filename_to_ansi (path, path_a);
4431 _chmod (path_a, 0666);
4432 return _unlink (path_a);
4436 static FILETIME utc_base_ft;
4437 static ULONGLONG utc_base; /* In 100ns units */
4438 static int init = 0;
4440 #define FILETIME_TO_U64(result, ft) \
4441 do { \
4442 ULARGE_INTEGER uiTemp; \
4443 uiTemp.LowPart = (ft).dwLowDateTime; \
4444 uiTemp.HighPart = (ft).dwHighDateTime; \
4445 result = uiTemp.QuadPart; \
4446 } while (0)
4448 static void
4449 initialize_utc_base (void)
4451 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4452 SYSTEMTIME st;
4454 st.wYear = 1970;
4455 st.wMonth = 1;
4456 st.wDay = 1;
4457 st.wHour = 0;
4458 st.wMinute = 0;
4459 st.wSecond = 0;
4460 st.wMilliseconds = 0;
4462 SystemTimeToFileTime (&st, &utc_base_ft);
4463 FILETIME_TO_U64 (utc_base, utc_base_ft);
4466 static time_t
4467 convert_time (FILETIME ft)
4469 ULONGLONG tmp;
4471 if (!init)
4473 initialize_utc_base ();
4474 init = 1;
4477 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4478 return 0;
4480 FILETIME_TO_U64 (tmp, ft);
4481 return (time_t) ((tmp - utc_base) / 10000000L);
4484 static void
4485 convert_from_time_t (time_t time, FILETIME * pft)
4487 ULARGE_INTEGER tmp;
4489 if (!init)
4491 initialize_utc_base ();
4492 init = 1;
4495 /* time in 100ns units since 1-Jan-1601 */
4496 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4497 pft->dwHighDateTime = tmp.HighPart;
4498 pft->dwLowDateTime = tmp.LowPart;
4501 static PSECURITY_DESCRIPTOR
4502 get_file_security_desc_by_handle (HANDLE h)
4504 PSECURITY_DESCRIPTOR psd = NULL;
4505 DWORD err;
4506 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4507 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4509 err = get_security_info (h, SE_FILE_OBJECT, si,
4510 NULL, NULL, NULL, NULL, &psd);
4511 if (err != ERROR_SUCCESS)
4512 return NULL;
4514 return psd;
4517 static PSECURITY_DESCRIPTOR
4518 get_file_security_desc_by_name (const char *fname)
4520 PSECURITY_DESCRIPTOR psd = NULL;
4521 DWORD sd_len, err;
4522 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4523 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4525 if (!get_file_security (fname, si, psd, 0, &sd_len))
4527 err = GetLastError ();
4528 if (err != ERROR_INSUFFICIENT_BUFFER)
4529 return NULL;
4532 psd = xmalloc (sd_len);
4533 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4535 xfree (psd);
4536 return NULL;
4539 return psd;
4542 static DWORD
4543 get_rid (PSID sid)
4545 unsigned n_subauthorities;
4547 /* Use the last sub-authority value of the RID, the relative
4548 portion of the SID, as user/group ID. */
4549 n_subauthorities = *get_sid_sub_authority_count (sid);
4550 if (n_subauthorities < 1)
4551 return 0; /* the "World" RID */
4552 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4555 /* Caching SID and account values for faster lokup. */
4557 struct w32_id {
4558 unsigned rid;
4559 struct w32_id *next;
4560 char name[GNLEN+1];
4561 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4564 static struct w32_id *w32_idlist;
4566 static int
4567 w32_cached_id (PSID sid, unsigned *id, char *name)
4569 struct w32_id *tail, *found;
4571 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4573 if (equal_sid ((PSID)tail->sid, sid))
4575 found = tail;
4576 break;
4579 if (found)
4581 *id = found->rid;
4582 strcpy (name, found->name);
4583 return 1;
4585 else
4586 return 0;
4589 static void
4590 w32_add_to_cache (PSID sid, unsigned id, char *name)
4592 DWORD sid_len;
4593 struct w32_id *new_entry;
4595 /* We don't want to leave behind stale cache from when Emacs was
4596 dumped. */
4597 if (initialized)
4599 sid_len = get_length_sid (sid);
4600 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4601 if (new_entry)
4603 new_entry->rid = id;
4604 strcpy (new_entry->name, name);
4605 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4606 new_entry->next = w32_idlist;
4607 w32_idlist = new_entry;
4612 #define UID 1
4613 #define GID 2
4615 static int
4616 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4618 PSID sid = NULL;
4619 BOOL dflt;
4620 SID_NAME_USE ignore;
4621 char name[UNLEN+1];
4622 DWORD name_len = sizeof (name);
4623 char domain[1024];
4624 DWORD domain_len = sizeof (domain);
4625 int use_dflt = 0;
4626 int result;
4628 if (what == UID)
4629 result = get_security_descriptor_owner (psd, &sid, &dflt);
4630 else if (what == GID)
4631 result = get_security_descriptor_group (psd, &sid, &dflt);
4632 else
4633 result = 0;
4635 if (!result || !is_valid_sid (sid))
4636 use_dflt = 1;
4637 else if (!w32_cached_id (sid, id, nm))
4639 if (!lookup_account_sid (NULL, sid, name, &name_len,
4640 domain, &domain_len, &ignore)
4641 || name_len > UNLEN+1)
4642 use_dflt = 1;
4643 else
4645 *id = get_rid (sid);
4646 strcpy (nm, name);
4647 w32_add_to_cache (sid, *id, name);
4650 return use_dflt;
4653 static void
4654 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4656 int dflt_usr = 0, dflt_grp = 0;
4658 if (!psd)
4660 dflt_usr = 1;
4661 dflt_grp = 1;
4663 else
4665 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4666 dflt_usr = 1;
4667 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4668 dflt_grp = 1;
4670 /* Consider files to belong to current user/group, if we cannot get
4671 more accurate information. */
4672 if (dflt_usr)
4674 st->st_uid = dflt_passwd.pw_uid;
4675 strcpy (st->st_uname, dflt_passwd.pw_name);
4677 if (dflt_grp)
4679 st->st_gid = dflt_passwd.pw_gid;
4680 strcpy (st->st_gname, dflt_group.gr_name);
4684 /* Return non-zero if NAME is a potentially slow filesystem. */
4686 is_slow_fs (const char *name)
4688 char drive_root[4];
4689 UINT devtype;
4691 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4692 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4693 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4694 devtype = GetDriveType (NULL); /* use root of current drive */
4695 else
4697 /* GetDriveType needs the root directory of the drive. */
4698 strncpy (drive_root, name, 2);
4699 drive_root[2] = '\\';
4700 drive_root[3] = '\0';
4701 devtype = GetDriveType (drive_root);
4703 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4706 /* If this is non-zero, the caller wants accurate information about
4707 file's owner and group, which could be expensive to get. dired.c
4708 uses this flag when needed for the job at hand. */
4709 int w32_stat_get_owner_group;
4711 /* MSVC stat function can't cope with UNC names and has other bugs, so
4712 replace it with our own. This also allows us to calculate consistent
4713 inode values and owner/group without hacks in the main Emacs code,
4714 and support file names encoded in UTF-8. */
4716 static int
4717 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4719 char *name, *save_name, *r;
4720 WIN32_FIND_DATAW wfd_w;
4721 WIN32_FIND_DATAA wfd_a;
4722 HANDLE fh;
4723 unsigned __int64 fake_inode = 0;
4724 int permission;
4725 int len;
4726 int rootdir = FALSE;
4727 PSECURITY_DESCRIPTOR psd = NULL;
4728 int is_a_symlink = 0;
4729 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4730 DWORD access_rights = 0;
4731 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4732 FILETIME ctime, atime, wtime;
4733 wchar_t name_w[MAX_PATH];
4734 char name_a[MAX_PATH];
4736 if (path == NULL || buf == NULL)
4738 errno = EFAULT;
4739 return -1;
4742 save_name = name = (char *) map_w32_filename (path, &path);
4743 /* Must be valid filename, no wild cards or other invalid
4744 characters. */
4745 if (strpbrk (name, "*?|<>\""))
4747 errno = ENOENT;
4748 return -1;
4751 len = strlen (name);
4752 /* Allocate 1 extra byte so that we could append a slash to a root
4753 directory, down below. */
4754 name = strcpy (alloca (len + 2), name);
4756 /* Avoid a somewhat costly call to is_symlink if the filesystem
4757 doesn't support symlinks. */
4758 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4759 is_a_symlink = is_symlink (name);
4761 /* Plan A: Open the file and get all the necessary information via
4762 the resulting handle. This solves several issues in one blow:
4764 . retrieves attributes for the target of a symlink, if needed
4765 . gets attributes of root directories and symlinks pointing to
4766 root directories, thus avoiding the need for special-casing
4767 these and detecting them by examining the file-name format
4768 . retrieves more accurate attributes (e.g., non-zero size for
4769 some directories, esp. directories that are junction points)
4770 . correctly resolves "c:/..", "/.." and similar file names
4771 . avoids run-time penalties for 99% of use cases
4773 Plan A is always tried first, unless the user asked not to (but
4774 if the file is a symlink and we need to follow links, we try Plan
4775 A even if the user asked not to).
4777 If Plan A fails, we go to Plan B (below), where various
4778 potentially expensive techniques must be used to handle "special"
4779 files such as UNC volumes etc. */
4780 if (!(NILP (Vw32_get_true_file_attributes)
4781 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
4782 /* Following symlinks requires getting the info by handle. */
4783 || (is_a_symlink && follow_symlinks))
4785 BY_HANDLE_FILE_INFORMATION info;
4787 if (is_a_symlink && !follow_symlinks)
4788 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
4789 /* READ_CONTROL access rights are required to get security info
4790 by handle. But if the OS doesn't support security in the
4791 first place, we don't need to try. */
4792 if (is_windows_9x () != TRUE)
4793 access_rights |= READ_CONTROL;
4795 if (w32_unicode_filenames)
4797 filename_to_utf16 (name, name_w);
4798 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
4799 file_flags, NULL);
4800 /* If CreateFile fails with READ_CONTROL, try again with
4801 zero as access rights. */
4802 if (fh == INVALID_HANDLE_VALUE && access_rights)
4803 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
4804 file_flags, NULL);
4806 else
4808 filename_to_ansi (name, name_a);
4809 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
4810 file_flags, NULL);
4811 if (fh == INVALID_HANDLE_VALUE && access_rights)
4812 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
4813 file_flags, NULL);
4815 if (fh == INVALID_HANDLE_VALUE)
4816 goto no_true_file_attributes;
4818 /* This is more accurate in terms of getting the correct number
4819 of links, but is quite slow (it is noticeable when Emacs is
4820 making a list of file name completions). */
4821 if (GetFileInformationByHandle (fh, &info))
4823 nlinks = info.nNumberOfLinks;
4824 /* Might as well use file index to fake inode values, but this
4825 is not guaranteed to be unique unless we keep a handle open
4826 all the time (even then there are situations where it is
4827 not unique). Reputedly, there are at most 48 bits of info
4828 (on NTFS, presumably less on FAT). */
4829 fake_inode = info.nFileIndexHigh;
4830 fake_inode <<= 32;
4831 fake_inode += info.nFileIndexLow;
4832 serialnum = info.dwVolumeSerialNumber;
4833 fs_high = info.nFileSizeHigh;
4834 fs_low = info.nFileSizeLow;
4835 ctime = info.ftCreationTime;
4836 atime = info.ftLastAccessTime;
4837 wtime = info.ftLastWriteTime;
4838 fattrs = info.dwFileAttributes;
4840 else
4842 /* We don't go to Plan B here, because it's not clear that
4843 it's a good idea. The only known use case where
4844 CreateFile succeeds, but GetFileInformationByHandle fails
4845 (with ERROR_INVALID_FUNCTION) is for character devices
4846 such as NUL, PRN, etc. For these, switching to Plan B is
4847 a net loss, because we lose the character device
4848 attribute returned by GetFileType below (FindFirstFile
4849 doesn't set that bit in the attributes), and the other
4850 fields don't make sense for character devices anyway.
4851 Emacs doesn't really care for non-file entities in the
4852 context of l?stat, so neither do we. */
4854 /* w32err is assigned so one could put a breakpoint here and
4855 examine its value, when GetFileInformationByHandle
4856 fails. */
4857 DWORD w32err = GetLastError ();
4859 switch (w32err)
4861 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
4862 errno = ENOENT;
4863 return -1;
4867 /* Test for a symlink before testing for a directory, since
4868 symlinks to directories have the directory bit set, but we
4869 don't want them to appear as directories. */
4870 if (is_a_symlink && !follow_symlinks)
4871 buf->st_mode = S_IFLNK;
4872 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4873 buf->st_mode = S_IFDIR;
4874 else
4876 DWORD ftype = GetFileType (fh);
4878 switch (ftype)
4880 case FILE_TYPE_DISK:
4881 buf->st_mode = S_IFREG;
4882 break;
4883 case FILE_TYPE_PIPE:
4884 buf->st_mode = S_IFIFO;
4885 break;
4886 case FILE_TYPE_CHAR:
4887 case FILE_TYPE_UNKNOWN:
4888 default:
4889 buf->st_mode = S_IFCHR;
4892 /* We produce the fallback owner and group data, based on the
4893 current user that runs Emacs, in the following cases:
4895 . caller didn't request owner and group info
4896 . this is Windows 9X
4897 . getting security by handle failed, and we need to produce
4898 information for the target of a symlink (this is better
4899 than producing a potentially misleading info about the
4900 symlink itself)
4902 If getting security by handle fails, and we don't need to
4903 resolve symlinks, we try getting security by name. */
4904 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4905 get_file_owner_and_group (NULL, buf);
4906 else
4908 psd = get_file_security_desc_by_handle (fh);
4909 if (psd)
4911 get_file_owner_and_group (psd, buf);
4912 LocalFree (psd);
4914 else if (!(is_a_symlink && follow_symlinks))
4916 psd = get_file_security_desc_by_name (name);
4917 get_file_owner_and_group (psd, buf);
4918 xfree (psd);
4920 else
4921 get_file_owner_and_group (NULL, buf);
4923 CloseHandle (fh);
4925 else
4927 no_true_file_attributes:
4928 /* Plan B: Either getting a handle on the file failed, or the
4929 caller explicitly asked us to not bother making this
4930 information more accurate.
4932 Implementation note: In Plan B, we never bother to resolve
4933 symlinks, even if we got here because we tried Plan A and
4934 failed. That's because, even if the caller asked for extra
4935 precision by setting Vw32_get_true_file_attributes to t,
4936 resolving symlinks requires acquiring a file handle to the
4937 symlink, which we already know will fail. And if the user
4938 did not ask for extra precision, resolving symlinks will fly
4939 in the face of that request, since the user then wants the
4940 lightweight version of the code. */
4941 rootdir = (path >= save_name + len - 1
4942 && (IS_DIRECTORY_SEP (*path) || *path == 0));
4944 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4945 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
4946 if (IS_DIRECTORY_SEP (r[0])
4947 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
4948 r[1] = r[2] = '\0';
4950 /* Note: If NAME is a symlink to the root of a UNC volume
4951 (i.e. "\\SERVER"), we will not detect that here, and we will
4952 return data about the symlink as result of FindFirst below.
4953 This is unfortunate, but that marginal use case does not
4954 justify a call to chase_symlinks which would impose a penalty
4955 on all the other use cases. (We get here for symlinks to
4956 roots of UNC volumes because CreateFile above fails for them,
4957 unlike with symlinks to root directories X:\ of drives.) */
4958 if (is_unc_volume (name))
4960 fattrs = unc_volume_file_attributes (name);
4961 if (fattrs == -1)
4962 return -1;
4964 ctime = atime = wtime = utc_base_ft;
4966 else if (rootdir)
4968 /* Make sure root directories end in a slash. */
4969 if (!IS_DIRECTORY_SEP (name[len-1]))
4970 strcat (name, "\\");
4971 if (GetDriveType (name) < 2)
4973 errno = ENOENT;
4974 return -1;
4977 fattrs = FILE_ATTRIBUTE_DIRECTORY;
4978 ctime = atime = wtime = utc_base_ft;
4980 else
4982 int have_wfd = -1;
4984 /* Make sure non-root directories do NOT end in a slash,
4985 otherwise FindFirstFile might fail. */
4986 if (IS_DIRECTORY_SEP (name[len-1]))
4987 name[len - 1] = 0;
4989 /* (This is hacky, but helps when doing file completions on
4990 network drives.) Optimize by using information available from
4991 active readdir if possible. */
4992 len = strlen (dir_pathname);
4993 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
4994 len--;
4995 if (dir_find_handle != INVALID_HANDLE_VALUE
4996 && last_dir_find_data != -1
4997 && !(is_a_symlink && follow_symlinks)
4998 /* The 2 file-name comparisons below support only ASCII
4999 characters, and will lose (compare not equal) when
5000 the file names include non-ASCII characters that are
5001 the same but for the case. However, doing this
5002 properly involves: (a) converting both file names to
5003 UTF-16, (b) lower-casing both names using CharLowerW,
5004 and (c) comparing the results; this would be quite a
5005 bit slower, whereas Plan B is for users who want
5006 lightweight albeit inaccurate version of 'stat'. */
5007 && c_strncasecmp (save_name, dir_pathname, len) == 0
5008 && IS_DIRECTORY_SEP (name[len])
5009 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
5011 have_wfd = last_dir_find_data;
5012 /* This was the last entry returned by readdir. */
5013 if (last_dir_find_data == DIR_FIND_DATA_W)
5014 wfd_w = dir_find_data_w;
5015 else
5016 wfd_a = dir_find_data_a;
5018 else
5020 logon_network_drive (name);
5022 if (w32_unicode_filenames)
5024 filename_to_utf16 (name, name_w);
5025 fh = FindFirstFileW (name_w, &wfd_w);
5026 have_wfd = DIR_FIND_DATA_W;
5028 else
5030 filename_to_ansi (name, name_a);
5031 /* If NAME includes characters not representable by
5032 the current ANSI codepage, filename_to_ansi
5033 usually replaces them with a '?'. We don't want
5034 to let FindFirstFileA interpret those as wildcards,
5035 and "succeed", returning us data from some random
5036 file in the same directory. */
5037 if (_mbspbrk (name_a, "?"))
5038 fh = INVALID_HANDLE_VALUE;
5039 else
5040 fh = FindFirstFileA (name_a, &wfd_a);
5041 have_wfd = DIR_FIND_DATA_A;
5043 if (fh == INVALID_HANDLE_VALUE)
5045 errno = ENOENT;
5046 return -1;
5048 FindClose (fh);
5050 /* Note: if NAME is a symlink, the information we get from
5051 FindFirstFile is for the symlink, not its target. */
5052 if (have_wfd == DIR_FIND_DATA_W)
5054 fattrs = wfd_w.dwFileAttributes;
5055 ctime = wfd_w.ftCreationTime;
5056 atime = wfd_w.ftLastAccessTime;
5057 wtime = wfd_w.ftLastWriteTime;
5058 fs_high = wfd_w.nFileSizeHigh;
5059 fs_low = wfd_w.nFileSizeLow;
5061 else
5063 fattrs = wfd_a.dwFileAttributes;
5064 ctime = wfd_a.ftCreationTime;
5065 atime = wfd_a.ftLastAccessTime;
5066 wtime = wfd_a.ftLastWriteTime;
5067 fs_high = wfd_a.nFileSizeHigh;
5068 fs_low = wfd_a.nFileSizeLow;
5070 fake_inode = 0;
5071 nlinks = 1;
5072 serialnum = volume_info.serialnum;
5074 if (is_a_symlink && !follow_symlinks)
5075 buf->st_mode = S_IFLNK;
5076 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5077 buf->st_mode = S_IFDIR;
5078 else
5079 buf->st_mode = S_IFREG;
5081 get_file_owner_and_group (NULL, buf);
5084 buf->st_ino = fake_inode;
5086 buf->st_dev = serialnum;
5087 buf->st_rdev = serialnum;
5089 buf->st_size = fs_high;
5090 buf->st_size <<= 32;
5091 buf->st_size += fs_low;
5092 buf->st_nlink = nlinks;
5094 /* Convert timestamps to Unix format. */
5095 buf->st_mtime = convert_time (wtime);
5096 buf->st_atime = convert_time (atime);
5097 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5098 buf->st_ctime = convert_time (ctime);
5099 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5101 /* determine rwx permissions */
5102 if (is_a_symlink && !follow_symlinks)
5103 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5104 else
5106 if (fattrs & FILE_ATTRIBUTE_READONLY)
5107 permission = S_IREAD;
5108 else
5109 permission = S_IREAD | S_IWRITE;
5111 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5112 permission |= S_IEXEC;
5113 else if (is_exec (name))
5114 permission |= S_IEXEC;
5117 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5119 return 0;
5123 stat (const char * path, struct stat * buf)
5125 return stat_worker (path, buf, 1);
5129 lstat (const char * path, struct stat * buf)
5131 return stat_worker (path, buf, 0);
5135 fstatat (int fd, char const *name, struct stat *st, int flags)
5137 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5138 This is good enough for the current usage in Emacs, but is fragile.
5140 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5141 Gnulib does this and can serve as a model. */
5142 char fullname[MAX_UTF8_PATH];
5144 if (fd != AT_FDCWD)
5146 char lastc = dir_pathname[strlen (dir_pathname) - 1];
5148 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
5149 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
5150 < 0)
5152 errno = ENAMETOOLONG;
5153 return -1;
5155 name = fullname;
5158 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5161 /* Provide fstat and utime as well as stat for consistent handling of
5162 file timestamps. */
5164 fstat (int desc, struct stat * buf)
5166 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5167 BY_HANDLE_FILE_INFORMATION info;
5168 unsigned __int64 fake_inode;
5169 int permission;
5171 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5173 case FILE_TYPE_DISK:
5174 buf->st_mode = S_IFREG;
5175 if (!GetFileInformationByHandle (fh, &info))
5177 errno = EACCES;
5178 return -1;
5180 break;
5181 case FILE_TYPE_PIPE:
5182 buf->st_mode = S_IFIFO;
5183 goto non_disk;
5184 case FILE_TYPE_CHAR:
5185 case FILE_TYPE_UNKNOWN:
5186 default:
5187 buf->st_mode = S_IFCHR;
5188 non_disk:
5189 memset (&info, 0, sizeof (info));
5190 info.dwFileAttributes = 0;
5191 info.ftCreationTime = utc_base_ft;
5192 info.ftLastAccessTime = utc_base_ft;
5193 info.ftLastWriteTime = utc_base_ft;
5196 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5197 buf->st_mode = S_IFDIR;
5199 buf->st_nlink = info.nNumberOfLinks;
5200 /* Might as well use file index to fake inode values, but this
5201 is not guaranteed to be unique unless we keep a handle open
5202 all the time (even then there are situations where it is
5203 not unique). Reputedly, there are at most 48 bits of info
5204 (on NTFS, presumably less on FAT). */
5205 fake_inode = info.nFileIndexHigh;
5206 fake_inode <<= 32;
5207 fake_inode += info.nFileIndexLow;
5209 /* MSVC defines _ino_t to be short; other libc's might not. */
5210 if (sizeof (buf->st_ino) == 2)
5211 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5212 else
5213 buf->st_ino = fake_inode;
5215 /* If the caller so requested, get the true file owner and group.
5216 Otherwise, consider the file to belong to the current user. */
5217 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5218 get_file_owner_and_group (NULL, buf);
5219 else
5221 PSECURITY_DESCRIPTOR psd = NULL;
5223 psd = get_file_security_desc_by_handle (fh);
5224 if (psd)
5226 get_file_owner_and_group (psd, buf);
5227 LocalFree (psd);
5229 else
5230 get_file_owner_and_group (NULL, buf);
5233 buf->st_dev = info.dwVolumeSerialNumber;
5234 buf->st_rdev = info.dwVolumeSerialNumber;
5236 buf->st_size = info.nFileSizeHigh;
5237 buf->st_size <<= 32;
5238 buf->st_size += info.nFileSizeLow;
5240 /* Convert timestamps to Unix format. */
5241 buf->st_mtime = convert_time (info.ftLastWriteTime);
5242 buf->st_atime = convert_time (info.ftLastAccessTime);
5243 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5244 buf->st_ctime = convert_time (info.ftCreationTime);
5245 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5247 /* determine rwx permissions */
5248 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5249 permission = S_IREAD;
5250 else
5251 permission = S_IREAD | S_IWRITE;
5253 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5254 permission |= S_IEXEC;
5255 else
5257 #if 0 /* no way of knowing the filename */
5258 char * p = strrchr (name, '.');
5259 if (p != NULL &&
5260 (xstrcasecmp (p, ".exe") == 0 ||
5261 xstrcasecmp (p, ".com") == 0 ||
5262 xstrcasecmp (p, ".bat") == 0 ||
5263 xstrcasecmp (p, ".cmd") == 0))
5264 permission |= S_IEXEC;
5265 #endif
5268 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5270 return 0;
5273 /* A version of 'utime' which handles directories as well as
5274 files. */
5277 utime (const char *name, struct utimbuf *times)
5279 struct utimbuf deftime;
5280 HANDLE fh;
5281 FILETIME mtime;
5282 FILETIME atime;
5284 if (times == NULL)
5286 deftime.modtime = deftime.actime = time (NULL);
5287 times = &deftime;
5290 if (w32_unicode_filenames)
5292 wchar_t name_utf16[MAX_PATH];
5294 if (filename_to_utf16 (name, name_utf16) != 0)
5295 return -1; /* errno set by filename_to_utf16 */
5297 /* Need write access to set times. */
5298 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5299 /* If NAME specifies a directory, FILE_SHARE_DELETE
5300 allows other processes to delete files inside it,
5301 while we have the directory open. */
5302 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5303 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5305 else
5307 char name_ansi[MAX_PATH];
5309 if (filename_to_ansi (name, name_ansi) != 0)
5310 return -1; /* errno set by filename_to_ansi */
5312 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5313 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5314 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5316 if (fh != INVALID_HANDLE_VALUE)
5318 convert_from_time_t (times->actime, &atime);
5319 convert_from_time_t (times->modtime, &mtime);
5320 if (!SetFileTime (fh, NULL, &atime, &mtime))
5322 CloseHandle (fh);
5323 errno = EACCES;
5324 return -1;
5326 CloseHandle (fh);
5328 else
5330 DWORD err = GetLastError ();
5332 switch (err)
5334 case ERROR_FILE_NOT_FOUND:
5335 case ERROR_PATH_NOT_FOUND:
5336 case ERROR_INVALID_DRIVE:
5337 case ERROR_BAD_NETPATH:
5338 case ERROR_DEV_NOT_EXIST:
5339 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5340 file name includes ?s, i.e. translation to ANSI failed. */
5341 case ERROR_INVALID_NAME:
5342 errno = ENOENT;
5343 break;
5344 case ERROR_TOO_MANY_OPEN_FILES:
5345 errno = ENFILE;
5346 break;
5347 case ERROR_ACCESS_DENIED:
5348 case ERROR_SHARING_VIOLATION:
5349 errno = EACCES;
5350 break;
5351 default:
5352 errno = EINVAL;
5353 break;
5355 return -1;
5357 return 0;
5361 sys_umask (int mode)
5363 static int current_mask;
5364 int retval, arg = 0;
5366 /* The only bit we really support is the write bit. Files are
5367 always readable on MS-Windows, and the execute bit does not exist
5368 at all. */
5369 /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
5370 to prevent access by other users on NTFS. */
5371 if ((mode & S_IWRITE) != 0)
5372 arg |= S_IWRITE;
5374 retval = _umask (arg);
5375 /* Merge into the return value the bits they've set the last time,
5376 which msvcrt.dll ignores and never returns. Emacs insists on its
5377 notion of mask being identical to what we return. */
5378 retval |= (current_mask & ~S_IWRITE);
5379 current_mask = mode;
5381 return retval;
5385 /* Symlink-related functions. */
5386 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5387 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5388 #endif
5391 symlink (char const *filename, char const *linkname)
5393 char linkfn[MAX_UTF8_PATH], *tgtfn;
5394 DWORD flags = 0;
5395 int dir_access, filename_ends_in_slash;
5397 /* Diagnostics follows Posix as much as possible. */
5398 if (filename == NULL || linkname == NULL)
5400 errno = EFAULT;
5401 return -1;
5403 if (!*filename)
5405 errno = ENOENT;
5406 return -1;
5408 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5410 errno = ENAMETOOLONG;
5411 return -1;
5414 strcpy (linkfn, map_w32_filename (linkname, NULL));
5415 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5417 errno = EPERM;
5418 return -1;
5421 /* Note: since empty FILENAME was already rejected, we can safely
5422 refer to FILENAME[1]. */
5423 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5425 /* Non-absolute FILENAME is understood as being relative to
5426 LINKNAME's directory. We need to prepend that directory to
5427 FILENAME to get correct results from faccessat below, since
5428 otherwise it will interpret FILENAME relative to the
5429 directory where the Emacs process runs. Note that
5430 make-symbolic-link always makes sure LINKNAME is a fully
5431 expanded file name. */
5432 char tem[MAX_UTF8_PATH];
5433 char *p = linkfn + strlen (linkfn);
5435 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5436 p--;
5437 if (p > linkfn)
5438 strncpy (tem, linkfn, p - linkfn);
5439 tem[p - linkfn] = '\0';
5440 strcat (tem, filename);
5441 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5443 else
5444 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5446 /* Since Windows distinguishes between symlinks to directories and
5447 to files, we provide a kludgy feature: if FILENAME doesn't
5448 exist, but ends in a slash, we create a symlink to directory. If
5449 FILENAME exists and is a directory, we always create a symlink to
5450 directory. */
5451 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5452 if (dir_access == 0 || filename_ends_in_slash)
5453 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5455 tgtfn = (char *)map_w32_filename (filename, NULL);
5456 if (filename_ends_in_slash)
5457 tgtfn[strlen (tgtfn) - 1] = '\0';
5459 errno = 0;
5460 if (!create_symbolic_link (linkfn, tgtfn, flags))
5462 /* ENOSYS is set by create_symbolic_link, when it detects that
5463 the OS doesn't support the CreateSymbolicLink API. */
5464 if (errno != ENOSYS)
5466 DWORD w32err = GetLastError ();
5468 switch (w32err)
5470 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5471 TGTFN point to the same file name, go figure. */
5472 case ERROR_SUCCESS:
5473 case ERROR_FILE_EXISTS:
5474 errno = EEXIST;
5475 break;
5476 case ERROR_ACCESS_DENIED:
5477 errno = EACCES;
5478 break;
5479 case ERROR_FILE_NOT_FOUND:
5480 case ERROR_PATH_NOT_FOUND:
5481 case ERROR_BAD_NETPATH:
5482 case ERROR_INVALID_REPARSE_DATA:
5483 errno = ENOENT;
5484 break;
5485 case ERROR_DIRECTORY:
5486 errno = EISDIR;
5487 break;
5488 case ERROR_PRIVILEGE_NOT_HELD:
5489 case ERROR_NOT_ALL_ASSIGNED:
5490 errno = EPERM;
5491 break;
5492 case ERROR_DISK_FULL:
5493 errno = ENOSPC;
5494 break;
5495 default:
5496 errno = EINVAL;
5497 break;
5500 return -1;
5502 return 0;
5505 /* A quick inexpensive test of whether FILENAME identifies a file that
5506 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5507 must already be in the normalized form returned by
5508 map_w32_filename.
5510 Note: for repeated operations on many files, it is best to test
5511 whether the underlying volume actually supports symlinks, by
5512 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5513 avoid the call to this function if it doesn't. That's because the
5514 call to GetFileAttributes takes a non-negligible time, especially
5515 on non-local or removable filesystems. See stat_worker for an
5516 example of how to do that. */
5517 static int
5518 is_symlink (const char *filename)
5520 DWORD attrs;
5521 wchar_t filename_w[MAX_PATH];
5522 char filename_a[MAX_PATH];
5523 WIN32_FIND_DATAW wfdw;
5524 WIN32_FIND_DATAA wfda;
5525 HANDLE fh;
5526 int attrs_mean_symlink;
5528 if (w32_unicode_filenames)
5530 filename_to_utf16 (filename, filename_w);
5531 attrs = GetFileAttributesW (filename_w);
5533 else
5535 filename_to_ansi (filename, filename_a);
5536 attrs = GetFileAttributesA (filename_a);
5538 if (attrs == -1)
5540 DWORD w32err = GetLastError ();
5542 switch (w32err)
5544 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5545 break;
5546 case ERROR_ACCESS_DENIED:
5547 errno = EACCES;
5548 break;
5549 case ERROR_FILE_NOT_FOUND:
5550 case ERROR_PATH_NOT_FOUND:
5551 default:
5552 errno = ENOENT;
5553 break;
5555 return 0;
5557 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5558 return 0;
5559 logon_network_drive (filename);
5560 if (w32_unicode_filenames)
5562 fh = FindFirstFileW (filename_w, &wfdw);
5563 attrs_mean_symlink =
5564 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5565 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5567 else if (_mbspbrk (filename_a, "?"))
5569 /* filename_to_ansi failed to convert the file name. */
5570 errno = ENOENT;
5571 return 0;
5573 else
5575 fh = FindFirstFileA (filename_a, &wfda);
5576 attrs_mean_symlink =
5577 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5578 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5580 if (fh == INVALID_HANDLE_VALUE)
5581 return 0;
5582 FindClose (fh);
5583 return attrs_mean_symlink;
5586 /* If NAME identifies a symbolic link, copy into BUF the file name of
5587 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5588 null-terminate the target name, even if it fits. Return the number
5589 of bytes copied, or -1 if NAME is not a symlink or any error was
5590 encountered while resolving it. The file name copied into BUF is
5591 encoded in the current ANSI codepage. */
5592 ssize_t
5593 readlink (const char *name, char *buf, size_t buf_size)
5595 const char *path;
5596 TOKEN_PRIVILEGES privs;
5597 int restore_privs = 0;
5598 HANDLE sh;
5599 ssize_t retval;
5600 char resolved[MAX_UTF8_PATH];
5602 if (name == NULL)
5604 errno = EFAULT;
5605 return -1;
5607 if (!*name)
5609 errno = ENOENT;
5610 return -1;
5613 path = map_w32_filename (name, NULL);
5615 if (strlen (path) > MAX_UTF8_PATH)
5617 errno = ENAMETOOLONG;
5618 return -1;
5621 errno = 0;
5622 if (is_windows_9x () == TRUE
5623 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5624 || !is_symlink (path))
5626 if (!errno)
5627 errno = EINVAL; /* not a symlink */
5628 return -1;
5631 /* Done with simple tests, now we're in for some _real_ work. */
5632 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5633 restore_privs = 1;
5634 /* Implementation note: From here and onward, don't return early,
5635 since that will fail to restore the original set of privileges of
5636 the calling thread. */
5638 retval = -1; /* not too optimistic, are we? */
5640 /* Note: In the next call to CreateFile, we use zero as the 2nd
5641 argument because, when the symlink is a hidden/system file,
5642 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5643 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5644 and directory symlinks. */
5645 if (w32_unicode_filenames)
5647 wchar_t path_w[MAX_PATH];
5649 filename_to_utf16 (path, path_w);
5650 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5651 FILE_FLAG_OPEN_REPARSE_POINT
5652 | FILE_FLAG_BACKUP_SEMANTICS,
5653 NULL);
5655 else
5657 char path_a[MAX_PATH];
5659 filename_to_ansi (path, path_a);
5660 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5661 FILE_FLAG_OPEN_REPARSE_POINT
5662 | FILE_FLAG_BACKUP_SEMANTICS,
5663 NULL);
5665 if (sh != INVALID_HANDLE_VALUE)
5667 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5668 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5669 DWORD retbytes;
5671 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5672 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5673 &retbytes, NULL))
5674 errno = EIO;
5675 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5676 errno = EINVAL;
5677 else
5679 /* Copy the link target name, in wide characters, from
5680 reparse_data, then convert it to multibyte encoding in
5681 the current locale's codepage. */
5682 WCHAR *lwname;
5683 size_t lname_size;
5684 USHORT lwname_len =
5685 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5686 WCHAR *lwname_src =
5687 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5688 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5689 size_t size_to_copy = buf_size;
5691 /* According to MSDN, PrintNameLength does not include the
5692 terminating null character. */
5693 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5694 memcpy (lwname, lwname_src, lwname_len);
5695 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5696 filename_from_utf16 (lwname, resolved);
5697 dostounix_filename (resolved);
5698 lname_size = strlen (resolved) + 1;
5699 if (lname_size <= buf_size)
5700 size_to_copy = lname_size;
5701 strncpy (buf, resolved, size_to_copy);
5702 /* Success! */
5703 retval = size_to_copy;
5705 CloseHandle (sh);
5707 else
5709 /* CreateFile failed. */
5710 DWORD w32err2 = GetLastError ();
5712 switch (w32err2)
5714 case ERROR_FILE_NOT_FOUND:
5715 case ERROR_PATH_NOT_FOUND:
5716 errno = ENOENT;
5717 break;
5718 case ERROR_ACCESS_DENIED:
5719 case ERROR_TOO_MANY_OPEN_FILES:
5720 errno = EACCES;
5721 break;
5722 default:
5723 errno = EPERM;
5724 break;
5727 if (restore_privs)
5729 restore_privilege (&privs);
5730 revert_to_self ();
5733 return retval;
5736 ssize_t
5737 readlinkat (int fd, char const *name, char *buffer,
5738 size_t buffer_size)
5740 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5741 as in fstatat. FIXME: Add proper support for readlinkat. */
5742 char fullname[MAX_UTF8_PATH];
5744 if (fd != AT_FDCWD)
5746 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5747 < 0)
5749 errno = ENAMETOOLONG;
5750 return -1;
5752 name = fullname;
5755 return readlink (name, buffer, buffer_size);
5758 /* If FILE is a symlink, return its target (stored in a static
5759 buffer); otherwise return FILE.
5761 This function repeatedly resolves symlinks in the last component of
5762 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5763 until it arrives at a file whose last component is not a symlink,
5764 or some error occurs. It returns the target of the last
5765 successfully resolved symlink in the chain. If it succeeds to
5766 resolve even a single symlink, the value returned is an absolute
5767 file name with backslashes (result of GetFullPathName). By
5768 contrast, if the original FILE is returned, it is unaltered.
5770 Note: This function can set errno even if it succeeds.
5772 Implementation note: we only resolve the last portion ("basename")
5773 of the argument FILE and of each following file in the chain,
5774 disregarding any possible symlinks in its leading directories.
5775 This is because Windows system calls and library functions
5776 transparently resolve symlinks in leading directories and return
5777 correct information, as long as the basename is not a symlink. */
5778 static char *
5779 chase_symlinks (const char *file)
5781 static char target[MAX_UTF8_PATH];
5782 char link[MAX_UTF8_PATH];
5783 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
5784 char target_a[MAX_PATH], link_a[MAX_PATH];
5785 ssize_t res, link_len;
5786 int loop_count = 0;
5788 if (is_windows_9x () == TRUE || !is_symlink (file))
5789 return (char *)file;
5791 if (w32_unicode_filenames)
5793 wchar_t file_w[MAX_PATH];
5795 filename_to_utf16 (file, file_w);
5796 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
5797 return (char *)file;
5798 filename_from_utf16 (link_w, link);
5800 else
5802 char file_a[MAX_PATH];
5804 filename_to_ansi (file, file_a);
5805 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
5806 return (char *)file;
5807 filename_from_ansi (link_a, link);
5809 link_len = strlen (link);
5811 target[0] = '\0';
5812 do {
5814 /* Remove trailing slashes, as we want to resolve the last
5815 non-trivial part of the link name. */
5816 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
5817 link[link_len--] = '\0';
5819 res = readlink (link, target, MAX_UTF8_PATH);
5820 if (res > 0)
5822 target[res] = '\0';
5823 if (!(IS_DEVICE_SEP (target[1])
5824 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
5826 /* Target is relative. Append it to the directory part of
5827 the symlink, then copy the result back to target. */
5828 char *p = link + link_len;
5830 while (p > link && !IS_ANY_SEP (p[-1]))
5831 p--;
5832 strcpy (p, target);
5833 strcpy (target, link);
5835 /* Resolve any "." and ".." to get a fully-qualified file name
5836 in link[] again. */
5837 if (w32_unicode_filenames)
5839 filename_to_utf16 (target, target_w);
5840 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
5841 if (link_len > 0)
5842 filename_from_utf16 (link_w, link);
5844 else
5846 filename_to_ansi (target, target_a);
5847 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
5848 if (link_len > 0)
5849 filename_from_ansi (link_a, link);
5851 link_len = strlen (link);
5853 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
5855 if (loop_count > 100)
5856 errno = ELOOP;
5858 if (target[0] == '\0') /* not a single call to readlink succeeded */
5859 return (char *)file;
5860 return target;
5864 /* Posix ACL emulation. */
5867 acl_valid (acl_t acl)
5869 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
5872 char *
5873 acl_to_text (acl_t acl, ssize_t *size)
5875 LPTSTR str_acl;
5876 SECURITY_INFORMATION flags =
5877 OWNER_SECURITY_INFORMATION |
5878 GROUP_SECURITY_INFORMATION |
5879 DACL_SECURITY_INFORMATION;
5880 char *retval = NULL;
5881 ULONG local_size;
5882 int e = errno;
5884 errno = 0;
5886 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
5888 errno = e;
5889 /* We don't want to mix heaps, so we duplicate the string in our
5890 heap and free the one allocated by the API. */
5891 retval = xstrdup (str_acl);
5892 if (size)
5893 *size = local_size;
5894 LocalFree (str_acl);
5896 else if (errno != ENOTSUP)
5897 errno = EINVAL;
5899 return retval;
5902 acl_t
5903 acl_from_text (const char *acl_str)
5905 PSECURITY_DESCRIPTOR psd, retval = NULL;
5906 ULONG sd_size;
5907 int e = errno;
5909 errno = 0;
5911 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
5913 errno = e;
5914 retval = xmalloc (sd_size);
5915 memcpy (retval, psd, sd_size);
5916 LocalFree (psd);
5918 else if (errno != ENOTSUP)
5919 errno = EINVAL;
5921 return retval;
5925 acl_free (void *ptr)
5927 xfree (ptr);
5928 return 0;
5931 acl_t
5932 acl_get_file (const char *fname, acl_type_t type)
5934 PSECURITY_DESCRIPTOR psd = NULL;
5935 const char *filename;
5937 if (type == ACL_TYPE_ACCESS)
5939 DWORD sd_len, err;
5940 SECURITY_INFORMATION si =
5941 OWNER_SECURITY_INFORMATION |
5942 GROUP_SECURITY_INFORMATION |
5943 DACL_SECURITY_INFORMATION ;
5944 int e = errno;
5946 filename = map_w32_filename (fname, NULL);
5947 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5948 fname = chase_symlinks (filename);
5949 else
5950 fname = filename;
5952 errno = 0;
5953 if (!get_file_security (fname, si, psd, 0, &sd_len)
5954 && errno != ENOTSUP)
5956 err = GetLastError ();
5957 if (err == ERROR_INSUFFICIENT_BUFFER)
5959 psd = xmalloc (sd_len);
5960 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
5962 xfree (psd);
5963 errno = EIO;
5964 psd = NULL;
5967 else if (err == ERROR_FILE_NOT_FOUND
5968 || err == ERROR_PATH_NOT_FOUND
5969 /* ERROR_INVALID_NAME is what we get if
5970 w32-unicode-filenames is nil and the file cannot
5971 be encoded in the current ANSI codepage. */
5972 || err == ERROR_INVALID_NAME)
5973 errno = ENOENT;
5974 else
5975 errno = EIO;
5977 else if (!errno)
5978 errno = e;
5980 else if (type != ACL_TYPE_DEFAULT)
5981 errno = EINVAL;
5983 return psd;
5987 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
5989 TOKEN_PRIVILEGES old1, old2;
5990 DWORD err;
5991 int st = 0, retval = -1;
5992 SECURITY_INFORMATION flags = 0;
5993 PSID psidOwner, psidGroup;
5994 PACL pacl;
5995 BOOL dflt;
5996 BOOL dacl_present;
5997 int e;
5998 const char *filename;
6000 if (acl_valid (acl) != 0
6001 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
6003 errno = EINVAL;
6004 return -1;
6007 if (type == ACL_TYPE_DEFAULT)
6009 errno = ENOSYS;
6010 return -1;
6013 filename = map_w32_filename (fname, NULL);
6014 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6015 fname = chase_symlinks (filename);
6016 else
6017 fname = filename;
6019 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
6020 &dflt)
6021 && psidOwner)
6022 flags |= OWNER_SECURITY_INFORMATION;
6023 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
6024 &dflt)
6025 && psidGroup)
6026 flags |= GROUP_SECURITY_INFORMATION;
6027 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
6028 &pacl, &dflt)
6029 && dacl_present)
6030 flags |= DACL_SECURITY_INFORMATION;
6031 if (!flags)
6032 return 0;
6034 /* According to KB-245153, setting the owner will succeed if either:
6035 (1) the caller is the user who will be the new owner, and has the
6036 SE_TAKE_OWNERSHIP privilege, or
6037 (2) the caller has the SE_RESTORE privilege, in which case she can
6038 set any valid user or group as the owner
6040 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
6041 privileges, and disregard any failures in obtaining them. If
6042 these privileges cannot be obtained, and do not already exist in
6043 the calling thread's security token, this function could fail
6044 with EPERM. */
6045 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
6046 st++;
6047 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
6048 st++;
6050 e = errno;
6051 errno = 0;
6052 /* SetFileSecurity is deprecated by MS, and sometimes fails when
6053 DACL inheritance is involved, but it seems to preserve ownership
6054 better than SetNamedSecurityInfo, which is important e.g., in
6055 copy-file. */
6056 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
6058 err = GetLastError ();
6060 if (errno != ENOTSUP)
6061 err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
6062 psidOwner, psidGroup, pacl, NULL);
6064 else
6065 err = ERROR_SUCCESS;
6066 if (err != ERROR_SUCCESS)
6068 if (errno == ENOTSUP)
6070 else if (err == ERROR_INVALID_OWNER
6071 || err == ERROR_NOT_ALL_ASSIGNED
6072 || err == ERROR_ACCESS_DENIED)
6074 /* Maybe the requested ACL and the one the file already has
6075 are identical, in which case we can silently ignore the
6076 failure. (And no, Windows doesn't.) */
6077 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
6079 errno = EPERM;
6080 if (current_acl)
6082 char *acl_from = acl_to_text (current_acl, NULL);
6083 char *acl_to = acl_to_text (acl, NULL);
6085 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
6087 retval = 0;
6088 errno = e;
6090 if (acl_from)
6091 acl_free (acl_from);
6092 if (acl_to)
6093 acl_free (acl_to);
6094 acl_free (current_acl);
6097 else if (err == ERROR_FILE_NOT_FOUND
6098 || err == ERROR_PATH_NOT_FOUND
6099 /* ERROR_INVALID_NAME is what we get if
6100 w32-unicode-filenames is nil and the file cannot be
6101 encoded in the current ANSI codepage. */
6102 || err == ERROR_INVALID_NAME)
6103 errno = ENOENT;
6104 else
6105 errno = EACCES;
6107 else
6109 retval = 0;
6110 errno = e;
6113 if (st)
6115 if (st >= 2)
6116 restore_privilege (&old2);
6117 restore_privilege (&old1);
6118 revert_to_self ();
6121 return retval;
6125 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
6126 have a fixed max size for file names, so we don't need the kind of
6127 alloc/malloc/realloc dance the gnulib version does. We also don't
6128 support FD-relative symlinks. */
6129 char *
6130 careadlinkat (int fd, char const *filename,
6131 char *buffer, size_t buffer_size,
6132 struct allocator const *alloc,
6133 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6135 char linkname[MAX_UTF8_PATH];
6136 ssize_t link_size;
6138 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6140 if (link_size > 0)
6142 char *retval = buffer;
6144 linkname[link_size++] = '\0';
6145 if (link_size > buffer_size)
6146 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6147 if (retval)
6148 memcpy (retval, linkname, link_size);
6150 return retval;
6152 return NULL;
6156 w32_copy_file (const char *from, const char *to,
6157 int keep_time, int preserve_ownership, int copy_acls)
6159 acl_t acl = NULL;
6160 BOOL copy_result;
6161 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6162 char from_a[MAX_PATH], to_a[MAX_PATH];
6164 /* We ignore preserve_ownership for now. */
6165 preserve_ownership = preserve_ownership;
6167 if (copy_acls)
6169 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6170 if (acl == NULL && acl_errno_valid (errno))
6171 return -2;
6173 if (w32_unicode_filenames)
6175 filename_to_utf16 (from, from_w);
6176 filename_to_utf16 (to, to_w);
6177 copy_result = CopyFileW (from_w, to_w, FALSE);
6179 else
6181 filename_to_ansi (from, from_a);
6182 filename_to_ansi (to, to_a);
6183 copy_result = CopyFileA (from_a, to_a, FALSE);
6185 if (!copy_result)
6187 /* CopyFile doesn't set errno when it fails. By far the most
6188 "popular" reason is that the target is read-only. */
6189 DWORD err = GetLastError ();
6191 switch (err)
6193 case ERROR_FILE_NOT_FOUND:
6194 errno = ENOENT;
6195 break;
6196 case ERROR_ACCESS_DENIED:
6197 errno = EACCES;
6198 break;
6199 case ERROR_ENCRYPTION_FAILED:
6200 errno = EIO;
6201 break;
6202 default:
6203 errno = EPERM;
6204 break;
6207 if (acl)
6208 acl_free (acl);
6209 return -1;
6211 /* CopyFile retains the timestamp by default. However, see
6212 "Community Additions" for CopyFile: it sounds like that is not
6213 entirely true. Testing on Windows XP confirms that modified time
6214 is copied, but creation and last-access times are not.
6215 FIXME? */
6216 else if (!keep_time)
6218 struct timespec now;
6219 DWORD attributes;
6221 if (w32_unicode_filenames)
6223 /* Ensure file is writable while its times are set. */
6224 attributes = GetFileAttributesW (to_w);
6225 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6226 now = current_timespec ();
6227 if (set_file_times (-1, to, now, now))
6229 /* Restore original attributes. */
6230 SetFileAttributesW (to_w, attributes);
6231 if (acl)
6232 acl_free (acl);
6233 return -3;
6235 /* Restore original attributes. */
6236 SetFileAttributesW (to_w, attributes);
6238 else
6240 attributes = GetFileAttributesA (to_a);
6241 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6242 now = current_timespec ();
6243 if (set_file_times (-1, to, now, now))
6245 SetFileAttributesA (to_a, attributes);
6246 if (acl)
6247 acl_free (acl);
6248 return -3;
6250 SetFileAttributesA (to_a, attributes);
6253 if (acl != NULL)
6255 bool fail =
6256 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6257 acl_free (acl);
6258 if (fail && acl_errno_valid (errno))
6259 return -4;
6262 return 0;
6266 /* Support for browsing other processes and their attributes. See
6267 process.c for the Lisp bindings. */
6269 /* Helper wrapper functions. */
6271 static HANDLE WINAPI
6272 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6274 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6276 if (g_b_init_create_toolhelp32_snapshot == 0)
6278 g_b_init_create_toolhelp32_snapshot = 1;
6279 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6280 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6281 "CreateToolhelp32Snapshot");
6283 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6285 return INVALID_HANDLE_VALUE;
6287 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6290 static BOOL WINAPI
6291 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6293 static Process32First_Proc s_pfn_Process32_First = NULL;
6295 if (g_b_init_process32_first == 0)
6297 g_b_init_process32_first = 1;
6298 s_pfn_Process32_First = (Process32First_Proc)
6299 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6300 "Process32First");
6302 if (s_pfn_Process32_First == NULL)
6304 return FALSE;
6306 return (s_pfn_Process32_First (hSnapshot, lppe));
6309 static BOOL WINAPI
6310 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6312 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6314 if (g_b_init_process32_next == 0)
6316 g_b_init_process32_next = 1;
6317 s_pfn_Process32_Next = (Process32Next_Proc)
6318 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6319 "Process32Next");
6321 if (s_pfn_Process32_Next == NULL)
6323 return FALSE;
6325 return (s_pfn_Process32_Next (hSnapshot, lppe));
6328 static BOOL WINAPI
6329 open_thread_token (HANDLE ThreadHandle,
6330 DWORD DesiredAccess,
6331 BOOL OpenAsSelf,
6332 PHANDLE TokenHandle)
6334 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6335 HMODULE hm_advapi32 = NULL;
6336 if (is_windows_9x () == TRUE)
6338 SetLastError (ERROR_NOT_SUPPORTED);
6339 return FALSE;
6341 if (g_b_init_open_thread_token == 0)
6343 g_b_init_open_thread_token = 1;
6344 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6345 s_pfn_Open_Thread_Token =
6346 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6348 if (s_pfn_Open_Thread_Token == NULL)
6350 SetLastError (ERROR_NOT_SUPPORTED);
6351 return FALSE;
6353 return (
6354 s_pfn_Open_Thread_Token (
6355 ThreadHandle,
6356 DesiredAccess,
6357 OpenAsSelf,
6358 TokenHandle)
6362 static BOOL WINAPI
6363 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6365 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6366 HMODULE hm_advapi32 = NULL;
6367 if (is_windows_9x () == TRUE)
6369 return FALSE;
6371 if (g_b_init_impersonate_self == 0)
6373 g_b_init_impersonate_self = 1;
6374 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6375 s_pfn_Impersonate_Self =
6376 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6378 if (s_pfn_Impersonate_Self == NULL)
6380 return FALSE;
6382 return s_pfn_Impersonate_Self (ImpersonationLevel);
6385 static BOOL WINAPI
6386 revert_to_self (void)
6388 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6389 HMODULE hm_advapi32 = NULL;
6390 if (is_windows_9x () == TRUE)
6392 return FALSE;
6394 if (g_b_init_revert_to_self == 0)
6396 g_b_init_revert_to_self = 1;
6397 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6398 s_pfn_Revert_To_Self =
6399 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6401 if (s_pfn_Revert_To_Self == NULL)
6403 return FALSE;
6405 return s_pfn_Revert_To_Self ();
6408 static BOOL WINAPI
6409 get_process_memory_info (HANDLE h_proc,
6410 PPROCESS_MEMORY_COUNTERS mem_counters,
6411 DWORD bufsize)
6413 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6414 HMODULE hm_psapi = NULL;
6415 if (is_windows_9x () == TRUE)
6417 return FALSE;
6419 if (g_b_init_get_process_memory_info == 0)
6421 g_b_init_get_process_memory_info = 1;
6422 hm_psapi = LoadLibrary ("Psapi.dll");
6423 if (hm_psapi)
6424 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6425 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6427 if (s_pfn_Get_Process_Memory_Info == NULL)
6429 return FALSE;
6431 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6434 static BOOL WINAPI
6435 get_process_working_set_size (HANDLE h_proc,
6436 PSIZE_T minrss,
6437 PSIZE_T maxrss)
6439 static GetProcessWorkingSetSize_Proc
6440 s_pfn_Get_Process_Working_Set_Size = NULL;
6442 if (is_windows_9x () == TRUE)
6444 return FALSE;
6446 if (g_b_init_get_process_working_set_size == 0)
6448 g_b_init_get_process_working_set_size = 1;
6449 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6450 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6451 "GetProcessWorkingSetSize");
6453 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6455 return FALSE;
6457 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6460 static BOOL WINAPI
6461 global_memory_status (MEMORYSTATUS *buf)
6463 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6465 if (is_windows_9x () == TRUE)
6467 return FALSE;
6469 if (g_b_init_global_memory_status == 0)
6471 g_b_init_global_memory_status = 1;
6472 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6473 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6474 "GlobalMemoryStatus");
6476 if (s_pfn_Global_Memory_Status == NULL)
6478 return FALSE;
6480 return s_pfn_Global_Memory_Status (buf);
6483 static BOOL WINAPI
6484 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6486 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6488 if (is_windows_9x () == TRUE)
6490 return FALSE;
6492 if (g_b_init_global_memory_status_ex == 0)
6494 g_b_init_global_memory_status_ex = 1;
6495 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6496 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6497 "GlobalMemoryStatusEx");
6499 if (s_pfn_Global_Memory_Status_Ex == NULL)
6501 return FALSE;
6503 return s_pfn_Global_Memory_Status_Ex (buf);
6506 Lisp_Object
6507 list_system_processes (void)
6509 struct gcpro gcpro1;
6510 Lisp_Object proclist = Qnil;
6511 HANDLE h_snapshot;
6513 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6515 if (h_snapshot != INVALID_HANDLE_VALUE)
6517 PROCESSENTRY32 proc_entry;
6518 DWORD proc_id;
6519 BOOL res;
6521 GCPRO1 (proclist);
6523 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6524 for (res = process32_first (h_snapshot, &proc_entry); res;
6525 res = process32_next (h_snapshot, &proc_entry))
6527 proc_id = proc_entry.th32ProcessID;
6528 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6531 CloseHandle (h_snapshot);
6532 UNGCPRO;
6533 proclist = Fnreverse (proclist);
6536 return proclist;
6539 static int
6540 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6542 TOKEN_PRIVILEGES priv;
6543 DWORD priv_size = sizeof (priv);
6544 DWORD opriv_size = sizeof (*old_priv);
6545 HANDLE h_token = NULL;
6546 HANDLE h_thread = GetCurrentThread ();
6547 int ret_val = 0;
6548 BOOL res;
6550 res = open_thread_token (h_thread,
6551 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6552 FALSE, &h_token);
6553 if (!res && GetLastError () == ERROR_NO_TOKEN)
6555 if (impersonate_self (SecurityImpersonation))
6556 res = open_thread_token (h_thread,
6557 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6558 FALSE, &h_token);
6560 if (res)
6562 priv.PrivilegeCount = 1;
6563 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6564 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6565 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6566 old_priv, &opriv_size)
6567 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6568 ret_val = 1;
6570 if (h_token)
6571 CloseHandle (h_token);
6573 return ret_val;
6576 static int
6577 restore_privilege (TOKEN_PRIVILEGES *priv)
6579 DWORD priv_size = sizeof (*priv);
6580 HANDLE h_token = NULL;
6581 int ret_val = 0;
6583 if (open_thread_token (GetCurrentThread (),
6584 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6585 FALSE, &h_token))
6587 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6588 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6589 ret_val = 1;
6591 if (h_token)
6592 CloseHandle (h_token);
6594 return ret_val;
6597 static Lisp_Object
6598 ltime (ULONGLONG time_100ns)
6600 ULONGLONG time_sec = time_100ns / 10000000;
6601 int subsec = time_100ns % 10000000;
6602 return list4i (time_sec >> 16, time_sec & 0xffff,
6603 subsec / 10, subsec % 10 * 100000);
6606 #define U64_TO_LISP_TIME(time) ltime (time)
6608 static int
6609 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6610 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6611 double *pcpu)
6613 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6614 ULONGLONG tem1, tem2, tem3, tem;
6616 if (!h_proc
6617 || !get_process_times_fn
6618 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6619 &ft_kernel, &ft_user))
6620 return 0;
6622 GetSystemTimeAsFileTime (&ft_current);
6624 FILETIME_TO_U64 (tem1, ft_kernel);
6625 *stime = U64_TO_LISP_TIME (tem1);
6627 FILETIME_TO_U64 (tem2, ft_user);
6628 *utime = U64_TO_LISP_TIME (tem2);
6630 tem3 = tem1 + tem2;
6631 *ttime = U64_TO_LISP_TIME (tem3);
6633 FILETIME_TO_U64 (tem, ft_creation);
6634 /* Process no 4 (System) returns zero creation time. */
6635 if (tem)
6636 tem -= utc_base;
6637 *ctime = U64_TO_LISP_TIME (tem);
6639 if (tem)
6641 FILETIME_TO_U64 (tem3, ft_current);
6642 tem = (tem3 - utc_base) - tem;
6644 *etime = U64_TO_LISP_TIME (tem);
6646 if (tem)
6648 *pcpu = 100.0 * (tem1 + tem2) / tem;
6649 if (*pcpu > 100)
6650 *pcpu = 100.0;
6652 else
6653 *pcpu = 0;
6655 return 1;
6658 Lisp_Object
6659 system_process_attributes (Lisp_Object pid)
6661 struct gcpro gcpro1, gcpro2, gcpro3;
6662 Lisp_Object attrs = Qnil;
6663 Lisp_Object cmd_str, decoded_cmd, tem;
6664 HANDLE h_snapshot, h_proc;
6665 DWORD proc_id;
6666 int found_proc = 0;
6667 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
6668 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
6669 DWORD glength = sizeof (gname);
6670 HANDLE token = NULL;
6671 SID_NAME_USE user_type;
6672 unsigned char *buf = NULL;
6673 DWORD blen = 0;
6674 TOKEN_USER user_token;
6675 TOKEN_PRIMARY_GROUP group_token;
6676 unsigned euid;
6677 unsigned egid;
6678 PROCESS_MEMORY_COUNTERS mem;
6679 PROCESS_MEMORY_COUNTERS_EX mem_ex;
6680 SIZE_T minrss, maxrss;
6681 MEMORYSTATUS memst;
6682 MEMORY_STATUS_EX memstex;
6683 double totphys = 0.0;
6684 Lisp_Object ctime, stime, utime, etime, ttime;
6685 double pcpu;
6686 BOOL result = FALSE;
6688 CHECK_NUMBER_OR_FLOAT (pid);
6689 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
6691 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6693 GCPRO3 (attrs, decoded_cmd, tem);
6695 if (h_snapshot != INVALID_HANDLE_VALUE)
6697 PROCESSENTRY32 pe;
6698 BOOL res;
6700 pe.dwSize = sizeof (PROCESSENTRY32);
6701 for (res = process32_first (h_snapshot, &pe); res;
6702 res = process32_next (h_snapshot, &pe))
6704 if (proc_id == pe.th32ProcessID)
6706 if (proc_id == 0)
6707 decoded_cmd = build_string ("Idle");
6708 else
6710 /* Decode the command name from locale-specific
6711 encoding. */
6712 cmd_str = build_unibyte_string (pe.szExeFile);
6714 decoded_cmd =
6715 code_convert_string_norecord (cmd_str,
6716 Vlocale_coding_system, 0);
6718 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
6719 attrs = Fcons (Fcons (Qppid,
6720 make_fixnum_or_float (pe.th32ParentProcessID)),
6721 attrs);
6722 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
6723 attrs);
6724 attrs = Fcons (Fcons (Qthcount,
6725 make_fixnum_or_float (pe.cntThreads)),
6726 attrs);
6727 found_proc = 1;
6728 break;
6732 CloseHandle (h_snapshot);
6735 if (!found_proc)
6737 UNGCPRO;
6738 return Qnil;
6741 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6742 FALSE, proc_id);
6743 /* If we were denied a handle to the process, try again after
6744 enabling the SeDebugPrivilege in our process. */
6745 if (!h_proc)
6747 TOKEN_PRIVILEGES priv_current;
6749 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
6751 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6752 FALSE, proc_id);
6753 restore_privilege (&priv_current);
6754 revert_to_self ();
6757 if (h_proc)
6759 result = open_process_token (h_proc, TOKEN_QUERY, &token);
6760 if (result)
6762 result = get_token_information (token, TokenUser, NULL, 0, &blen);
6763 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6765 buf = xmalloc (blen);
6766 result = get_token_information (token, TokenUser,
6767 (LPVOID)buf, blen, &needed);
6768 if (result)
6770 memcpy (&user_token, buf, sizeof (user_token));
6771 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
6773 euid = get_rid (user_token.User.Sid);
6774 result = lookup_account_sid (NULL, user_token.User.Sid,
6775 uname, &ulength,
6776 domain, &dlength,
6777 &user_type);
6778 if (result)
6779 w32_add_to_cache (user_token.User.Sid, euid, uname);
6780 else
6782 strcpy (uname, "unknown");
6783 result = TRUE;
6786 ulength = strlen (uname);
6790 if (result)
6792 /* Determine a reasonable euid and gid values. */
6793 if (xstrcasecmp ("administrator", uname) == 0)
6795 euid = 500; /* well-known Administrator uid */
6796 egid = 513; /* well-known None gid */
6798 else
6800 /* Get group id and name. */
6801 result = get_token_information (token, TokenPrimaryGroup,
6802 (LPVOID)buf, blen, &needed);
6803 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6805 buf = xrealloc (buf, blen = needed);
6806 result = get_token_information (token, TokenPrimaryGroup,
6807 (LPVOID)buf, blen, &needed);
6809 if (result)
6811 memcpy (&group_token, buf, sizeof (group_token));
6812 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
6814 egid = get_rid (group_token.PrimaryGroup);
6815 dlength = sizeof (domain);
6816 result =
6817 lookup_account_sid (NULL, group_token.PrimaryGroup,
6818 gname, &glength, NULL, &dlength,
6819 &user_type);
6820 if (result)
6821 w32_add_to_cache (group_token.PrimaryGroup,
6822 egid, gname);
6823 else
6825 strcpy (gname, "None");
6826 result = TRUE;
6829 glength = strlen (gname);
6833 xfree (buf);
6835 if (!result)
6837 if (!is_windows_9x ())
6839 /* We couldn't open the process token, presumably because of
6840 insufficient access rights. Assume this process is run
6841 by the system. */
6842 strcpy (uname, "SYSTEM");
6843 strcpy (gname, "None");
6844 euid = 18; /* SYSTEM */
6845 egid = 513; /* None */
6846 glength = strlen (gname);
6847 ulength = strlen (uname);
6849 /* If we are running under Windows 9X, where security calls are
6850 not supported, we assume all processes are run by the current
6851 user. */
6852 else if (GetUserName (uname, &ulength))
6854 if (xstrcasecmp ("administrator", uname) == 0)
6855 euid = 0;
6856 else
6857 euid = 123;
6858 egid = euid;
6859 strcpy (gname, "None");
6860 glength = strlen (gname);
6861 ulength = strlen (uname);
6863 else
6865 euid = 123;
6866 egid = 123;
6867 strcpy (uname, "administrator");
6868 ulength = strlen (uname);
6869 strcpy (gname, "None");
6870 glength = strlen (gname);
6872 if (token)
6873 CloseHandle (token);
6876 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
6877 tem = make_unibyte_string (uname, ulength);
6878 attrs = Fcons (Fcons (Quser,
6879 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6880 attrs);
6881 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
6882 tem = make_unibyte_string (gname, glength);
6883 attrs = Fcons (Fcons (Qgroup,
6884 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6885 attrs);
6887 if (global_memory_status_ex (&memstex))
6888 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
6889 totphys = memstex.ullTotalPhys / 1024.0;
6890 #else
6891 /* Visual Studio 6 cannot convert an unsigned __int64 type to
6892 double, so we need to do this for it... */
6894 DWORD tot_hi = memstex.ullTotalPhys >> 32;
6895 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
6896 DWORD tot_lo = memstex.ullTotalPhys % 1024;
6898 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
6900 #endif /* __GNUC__ || _MSC_VER >= 1300 */
6901 else if (global_memory_status (&memst))
6902 totphys = memst.dwTotalPhys / 1024.0;
6904 if (h_proc
6905 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
6906 sizeof (mem_ex)))
6908 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6910 attrs = Fcons (Fcons (Qmajflt,
6911 make_fixnum_or_float (mem_ex.PageFaultCount)),
6912 attrs);
6913 attrs = Fcons (Fcons (Qvsize,
6914 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
6915 attrs);
6916 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6917 if (totphys)
6918 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6920 else if (h_proc
6921 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
6923 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6925 attrs = Fcons (Fcons (Qmajflt,
6926 make_fixnum_or_float (mem.PageFaultCount)),
6927 attrs);
6928 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6929 if (totphys)
6930 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6932 else if (h_proc
6933 && get_process_working_set_size (h_proc, &minrss, &maxrss))
6935 DWORD rss = maxrss / 1024;
6937 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
6938 if (totphys)
6939 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6942 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
6944 attrs = Fcons (Fcons (Qutime, utime), attrs);
6945 attrs = Fcons (Fcons (Qstime, stime), attrs);
6946 attrs = Fcons (Fcons (Qtime, ttime), attrs);
6947 attrs = Fcons (Fcons (Qstart, ctime), attrs);
6948 attrs = Fcons (Fcons (Qetime, etime), attrs);
6949 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
6952 /* FIXME: Retrieve command line by walking the PEB of the process. */
6954 if (h_proc)
6955 CloseHandle (h_proc);
6956 UNGCPRO;
6957 return attrs;
6961 w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
6962 unsigned long long *totalswap, unsigned long long *freeswap)
6964 MEMORYSTATUS memst;
6965 MEMORY_STATUS_EX memstex;
6967 /* Use GlobalMemoryStatusEx if available, as it can report more than
6968 2GB of memory. */
6969 if (global_memory_status_ex (&memstex))
6971 *totalram = memstex.ullTotalPhys;
6972 *freeram = memstex.ullAvailPhys;
6973 *totalswap = memstex.ullTotalPageFile;
6974 *freeswap = memstex.ullAvailPageFile;
6975 return 0;
6977 else if (global_memory_status (&memst))
6979 *totalram = memst.dwTotalPhys;
6980 *freeram = memst.dwAvailPhys;
6981 *totalswap = memst.dwTotalPageFile;
6982 *freeswap = memst.dwAvailPageFile;
6983 return 0;
6985 else
6986 return -1;
6990 /* Wrappers for winsock functions to map between our file descriptors
6991 and winsock's handles; also set h_errno for convenience.
6993 To allow Emacs to run on systems which don't have winsock support
6994 installed, we dynamically link to winsock on startup if present, and
6995 otherwise provide the minimum necessary functionality
6996 (eg. gethostname). */
6998 /* function pointers for relevant socket functions */
6999 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
7000 void (PASCAL *pfn_WSASetLastError) (int iError);
7001 int (PASCAL *pfn_WSAGetLastError) (void);
7002 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
7003 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
7004 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
7005 int (PASCAL *pfn_socket) (int af, int type, int protocol);
7006 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
7007 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
7008 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
7009 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
7010 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
7011 int (PASCAL *pfn_closesocket) (SOCKET s);
7012 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
7013 int (PASCAL *pfn_WSACleanup) (void);
7015 u_short (PASCAL *pfn_htons) (u_short hostshort);
7016 u_short (PASCAL *pfn_ntohs) (u_short netshort);
7017 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
7018 int (PASCAL *pfn_gethostname) (char * name, int namelen);
7019 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
7020 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
7021 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
7022 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
7023 const char * optval, int optlen);
7024 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
7025 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
7026 int * namelen);
7027 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
7028 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
7029 struct sockaddr * from, int * fromlen);
7030 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
7031 const struct sockaddr * to, int tolen);
7033 /* SetHandleInformation is only needed to make sockets non-inheritable. */
7034 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7035 #ifndef HANDLE_FLAG_INHERIT
7036 #define HANDLE_FLAG_INHERIT 1
7037 #endif
7039 HANDLE winsock_lib;
7040 static int winsock_inuse;
7042 BOOL
7043 term_winsock (void)
7045 if (winsock_lib != NULL && winsock_inuse == 0)
7047 release_listen_threads ();
7048 /* Not sure what would cause WSAENETDOWN, or even if it can happen
7049 after WSAStartup returns successfully, but it seems reasonable
7050 to allow unloading winsock anyway in that case. */
7051 if (pfn_WSACleanup () == 0 ||
7052 pfn_WSAGetLastError () == WSAENETDOWN)
7054 if (FreeLibrary (winsock_lib))
7055 winsock_lib = NULL;
7056 return TRUE;
7059 return FALSE;
7062 BOOL
7063 init_winsock (int load_now)
7065 WSADATA winsockData;
7067 if (winsock_lib != NULL)
7068 return TRUE;
7070 pfn_SetHandleInformation
7071 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
7072 "SetHandleInformation");
7074 winsock_lib = LoadLibrary ("Ws2_32.dll");
7076 if (winsock_lib != NULL)
7078 /* dynamically link to socket functions */
7080 #define LOAD_PROC(fn) \
7081 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
7082 goto fail;
7084 LOAD_PROC (WSAStartup);
7085 LOAD_PROC (WSASetLastError);
7086 LOAD_PROC (WSAGetLastError);
7087 LOAD_PROC (WSAEventSelect);
7088 LOAD_PROC (WSACreateEvent);
7089 LOAD_PROC (WSACloseEvent);
7090 LOAD_PROC (socket);
7091 LOAD_PROC (bind);
7092 LOAD_PROC (connect);
7093 LOAD_PROC (ioctlsocket);
7094 LOAD_PROC (recv);
7095 LOAD_PROC (send);
7096 LOAD_PROC (closesocket);
7097 LOAD_PROC (shutdown);
7098 LOAD_PROC (htons);
7099 LOAD_PROC (ntohs);
7100 LOAD_PROC (inet_addr);
7101 LOAD_PROC (gethostname);
7102 LOAD_PROC (gethostbyname);
7103 LOAD_PROC (getservbyname);
7104 LOAD_PROC (getpeername);
7105 LOAD_PROC (WSACleanup);
7106 LOAD_PROC (setsockopt);
7107 LOAD_PROC (listen);
7108 LOAD_PROC (getsockname);
7109 LOAD_PROC (accept);
7110 LOAD_PROC (recvfrom);
7111 LOAD_PROC (sendto);
7112 #undef LOAD_PROC
7114 /* specify version 1.1 of winsock */
7115 if (pfn_WSAStartup (0x101, &winsockData) == 0)
7117 if (winsockData.wVersion != 0x101)
7118 goto fail;
7120 if (!load_now)
7122 /* Report that winsock exists and is usable, but leave
7123 socket functions disabled. I am assuming that calling
7124 WSAStartup does not require any network interaction,
7125 and in particular does not cause or require a dial-up
7126 connection to be established. */
7128 pfn_WSACleanup ();
7129 FreeLibrary (winsock_lib);
7130 winsock_lib = NULL;
7132 winsock_inuse = 0;
7133 return TRUE;
7136 fail:
7137 FreeLibrary (winsock_lib);
7138 winsock_lib = NULL;
7141 return FALSE;
7145 int h_errno = 0;
7147 /* Function to map winsock error codes to errno codes for those errno
7148 code defined in errno.h (errno values not defined by errno.h are
7149 already in nt/inc/sys/socket.h). */
7150 static void
7151 set_errno (void)
7153 int wsa_err;
7155 h_errno = 0;
7156 if (winsock_lib == NULL)
7157 wsa_err = EINVAL;
7158 else
7159 wsa_err = pfn_WSAGetLastError ();
7161 switch (wsa_err)
7163 case WSAEACCES: errno = EACCES; break;
7164 case WSAEBADF: errno = EBADF; break;
7165 case WSAEFAULT: errno = EFAULT; break;
7166 case WSAEINTR: errno = EINTR; break;
7167 case WSAEINVAL: errno = EINVAL; break;
7168 case WSAEMFILE: errno = EMFILE; break;
7169 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7170 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7171 default: errno = wsa_err; break;
7175 static void
7176 check_errno (void)
7178 h_errno = 0;
7179 if (winsock_lib != NULL)
7180 pfn_WSASetLastError (0);
7183 /* Extend strerror to handle the winsock-specific error codes. */
7184 struct {
7185 int errnum;
7186 char * msg;
7187 } _wsa_errlist[] = {
7188 {WSAEINTR , "Interrupted function call"},
7189 {WSAEBADF , "Bad file descriptor"},
7190 {WSAEACCES , "Permission denied"},
7191 {WSAEFAULT , "Bad address"},
7192 {WSAEINVAL , "Invalid argument"},
7193 {WSAEMFILE , "Too many open files"},
7195 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7196 {WSAEINPROGRESS , "Operation now in progress"},
7197 {WSAEALREADY , "Operation already in progress"},
7198 {WSAENOTSOCK , "Socket operation on non-socket"},
7199 {WSAEDESTADDRREQ , "Destination address required"},
7200 {WSAEMSGSIZE , "Message too long"},
7201 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7202 {WSAENOPROTOOPT , "Bad protocol option"},
7203 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7204 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7205 {WSAEOPNOTSUPP , "Operation not supported"},
7206 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7207 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7208 {WSAEADDRINUSE , "Address already in use"},
7209 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7210 {WSAENETDOWN , "Network is down"},
7211 {WSAENETUNREACH , "Network is unreachable"},
7212 {WSAENETRESET , "Network dropped connection on reset"},
7213 {WSAECONNABORTED , "Software caused connection abort"},
7214 {WSAECONNRESET , "Connection reset by peer"},
7215 {WSAENOBUFS , "No buffer space available"},
7216 {WSAEISCONN , "Socket is already connected"},
7217 {WSAENOTCONN , "Socket is not connected"},
7218 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7219 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7220 {WSAETIMEDOUT , "Connection timed out"},
7221 {WSAECONNREFUSED , "Connection refused"},
7222 {WSAELOOP , "Network loop"}, /* not sure */
7223 {WSAENAMETOOLONG , "Name is too long"},
7224 {WSAEHOSTDOWN , "Host is down"},
7225 {WSAEHOSTUNREACH , "No route to host"},
7226 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7227 {WSAEPROCLIM , "Too many processes"},
7228 {WSAEUSERS , "Too many users"}, /* not sure */
7229 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7230 {WSAESTALE , "Data is stale"}, /* not sure */
7231 {WSAEREMOTE , "Remote error"}, /* not sure */
7233 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7234 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7235 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7236 {WSAEDISCON , "Graceful shutdown in progress"},
7237 #ifdef WSAENOMORE
7238 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7239 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7240 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7241 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7242 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7243 {WSASYSCALLFAILURE , "System call failure"},
7244 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7245 {WSATYPE_NOT_FOUND , "Class type not found"},
7246 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7247 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7248 {WSAEREFUSED , "Operation refused"}, /* not sure */
7249 #endif
7251 {WSAHOST_NOT_FOUND , "Host not found"},
7252 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7253 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7254 {WSANO_DATA , "Valid name, no data record of requested type"},
7256 {-1, NULL}
7259 char *
7260 sys_strerror (int error_no)
7262 int i;
7263 static char unknown_msg[40];
7265 if (error_no >= 0 && error_no < sys_nerr)
7266 return sys_errlist[error_no];
7268 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7269 if (_wsa_errlist[i].errnum == error_no)
7270 return _wsa_errlist[i].msg;
7272 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7273 return unknown_msg;
7276 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7277 but I believe the method of keeping the socket handle separate (and
7278 insuring it is not inheritable) is the correct one. */
7280 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7282 static int socket_to_fd (SOCKET s);
7285 sys_socket (int af, int type, int protocol)
7287 SOCKET s;
7289 if (winsock_lib == NULL)
7291 errno = ENETDOWN;
7292 return INVALID_SOCKET;
7295 check_errno ();
7297 /* call the real socket function */
7298 s = pfn_socket (af, type, protocol);
7300 if (s != INVALID_SOCKET)
7301 return socket_to_fd (s);
7303 set_errno ();
7304 return -1;
7307 /* Convert a SOCKET to a file descriptor. */
7308 static int
7309 socket_to_fd (SOCKET s)
7311 int fd;
7312 child_process * cp;
7314 /* Although under NT 3.5 _open_osfhandle will accept a socket
7315 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7316 that does not work under NT 3.1. However, we can get the same
7317 effect by using a backdoor function to replace an existing
7318 descriptor handle with the one we want. */
7320 /* allocate a file descriptor (with appropriate flags) */
7321 fd = _open ("NUL:", _O_RDWR);
7322 if (fd >= 0)
7324 /* Make a non-inheritable copy of the socket handle. Note
7325 that it is possible that sockets aren't actually kernel
7326 handles, which appears to be the case on Windows 9x when
7327 the MS Proxy winsock client is installed. */
7329 /* Apparently there is a bug in NT 3.51 with some service
7330 packs, which prevents using DuplicateHandle to make a
7331 socket handle non-inheritable (causes WSACleanup to
7332 hang). The work-around is to use SetHandleInformation
7333 instead if it is available and implemented. */
7334 if (pfn_SetHandleInformation)
7336 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7338 else
7340 HANDLE parent = GetCurrentProcess ();
7341 HANDLE new_s = INVALID_HANDLE_VALUE;
7343 if (DuplicateHandle (parent,
7344 (HANDLE) s,
7345 parent,
7346 &new_s,
7348 FALSE,
7349 DUPLICATE_SAME_ACCESS))
7351 /* It is possible that DuplicateHandle succeeds even
7352 though the socket wasn't really a kernel handle,
7353 because a real handle has the same value. So
7354 test whether the new handle really is a socket. */
7355 long nonblocking = 0;
7356 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7358 pfn_closesocket (s);
7359 s = (SOCKET) new_s;
7361 else
7363 CloseHandle (new_s);
7368 eassert (fd < MAXDESC);
7369 fd_info[fd].hnd = (HANDLE) s;
7371 /* set our own internal flags */
7372 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7374 cp = new_child ();
7375 if (cp)
7377 cp->fd = fd;
7378 cp->status = STATUS_READ_ACKNOWLEDGED;
7380 /* attach child_process to fd_info */
7381 if (fd_info[ fd ].cp != NULL)
7383 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7384 emacs_abort ();
7387 fd_info[ fd ].cp = cp;
7389 /* success! */
7390 winsock_inuse++; /* count open sockets */
7391 return fd;
7394 /* clean up */
7395 _close (fd);
7397 else
7398 pfn_closesocket (s);
7399 errno = EMFILE;
7400 return -1;
7404 sys_bind (int s, const struct sockaddr * addr, int namelen)
7406 if (winsock_lib == NULL)
7408 errno = ENOTSOCK;
7409 return SOCKET_ERROR;
7412 check_errno ();
7413 if (fd_info[s].flags & FILE_SOCKET)
7415 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7416 if (rc == SOCKET_ERROR)
7417 set_errno ();
7418 return rc;
7420 errno = ENOTSOCK;
7421 return SOCKET_ERROR;
7425 sys_connect (int s, const struct sockaddr * name, int namelen)
7427 if (winsock_lib == NULL)
7429 errno = ENOTSOCK;
7430 return SOCKET_ERROR;
7433 check_errno ();
7434 if (fd_info[s].flags & FILE_SOCKET)
7436 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7437 if (rc == SOCKET_ERROR)
7438 set_errno ();
7439 return rc;
7441 errno = ENOTSOCK;
7442 return SOCKET_ERROR;
7445 u_short
7446 sys_htons (u_short hostshort)
7448 return (winsock_lib != NULL) ?
7449 pfn_htons (hostshort) : hostshort;
7452 u_short
7453 sys_ntohs (u_short netshort)
7455 return (winsock_lib != NULL) ?
7456 pfn_ntohs (netshort) : netshort;
7459 unsigned long
7460 sys_inet_addr (const char * cp)
7462 return (winsock_lib != NULL) ?
7463 pfn_inet_addr (cp) : INADDR_NONE;
7467 sys_gethostname (char * name, int namelen)
7469 if (winsock_lib != NULL)
7471 int retval;
7473 check_errno ();
7474 retval = pfn_gethostname (name, namelen);
7475 if (retval == SOCKET_ERROR)
7476 set_errno ();
7477 return retval;
7480 if (namelen > MAX_COMPUTERNAME_LENGTH)
7481 return !GetComputerName (name, (DWORD *)&namelen);
7483 errno = EFAULT;
7484 return SOCKET_ERROR;
7487 struct hostent *
7488 sys_gethostbyname (const char * name)
7490 struct hostent * host;
7491 int h_err = h_errno;
7493 if (winsock_lib == NULL)
7495 h_errno = NO_RECOVERY;
7496 errno = ENETDOWN;
7497 return NULL;
7500 check_errno ();
7501 host = pfn_gethostbyname (name);
7502 if (!host)
7504 set_errno ();
7505 h_errno = errno;
7507 else
7508 h_errno = h_err;
7509 return host;
7512 struct servent *
7513 sys_getservbyname (const char * name, const char * proto)
7515 struct servent * serv;
7517 if (winsock_lib == NULL)
7519 errno = ENETDOWN;
7520 return NULL;
7523 check_errno ();
7524 serv = pfn_getservbyname (name, proto);
7525 if (!serv)
7526 set_errno ();
7527 return serv;
7531 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7533 if (winsock_lib == NULL)
7535 errno = ENETDOWN;
7536 return SOCKET_ERROR;
7539 check_errno ();
7540 if (fd_info[s].flags & FILE_SOCKET)
7542 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7543 if (rc == SOCKET_ERROR)
7544 set_errno ();
7545 return rc;
7547 errno = ENOTSOCK;
7548 return SOCKET_ERROR;
7552 sys_shutdown (int s, int how)
7554 if (winsock_lib == NULL)
7556 errno = ENETDOWN;
7557 return SOCKET_ERROR;
7560 check_errno ();
7561 if (fd_info[s].flags & FILE_SOCKET)
7563 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
7564 if (rc == SOCKET_ERROR)
7565 set_errno ();
7566 return rc;
7568 errno = ENOTSOCK;
7569 return SOCKET_ERROR;
7573 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
7575 if (winsock_lib == NULL)
7577 errno = ENETDOWN;
7578 return SOCKET_ERROR;
7581 check_errno ();
7582 if (fd_info[s].flags & FILE_SOCKET)
7584 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
7585 (const char *)optval, optlen);
7586 if (rc == SOCKET_ERROR)
7587 set_errno ();
7588 return rc;
7590 errno = ENOTSOCK;
7591 return SOCKET_ERROR;
7595 sys_listen (int s, int backlog)
7597 if (winsock_lib == NULL)
7599 errno = ENETDOWN;
7600 return SOCKET_ERROR;
7603 check_errno ();
7604 if (fd_info[s].flags & FILE_SOCKET)
7606 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
7607 if (rc == SOCKET_ERROR)
7608 set_errno ();
7609 else
7610 fd_info[s].flags |= FILE_LISTEN;
7611 return rc;
7613 errno = ENOTSOCK;
7614 return SOCKET_ERROR;
7618 sys_getsockname (int s, struct sockaddr * name, int * namelen)
7620 if (winsock_lib == NULL)
7622 errno = ENETDOWN;
7623 return SOCKET_ERROR;
7626 check_errno ();
7627 if (fd_info[s].flags & FILE_SOCKET)
7629 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
7630 if (rc == SOCKET_ERROR)
7631 set_errno ();
7632 return rc;
7634 errno = ENOTSOCK;
7635 return SOCKET_ERROR;
7639 sys_accept (int s, struct sockaddr * addr, int * addrlen)
7641 if (winsock_lib == NULL)
7643 errno = ENETDOWN;
7644 return -1;
7647 check_errno ();
7648 if (fd_info[s].flags & FILE_LISTEN)
7650 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
7651 int fd = -1;
7652 if (t == INVALID_SOCKET)
7653 set_errno ();
7654 else
7655 fd = socket_to_fd (t);
7657 if (fd >= 0)
7659 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
7660 ResetEvent (fd_info[s].cp->char_avail);
7662 return fd;
7664 errno = ENOTSOCK;
7665 return -1;
7669 sys_recvfrom (int s, char * buf, int len, int flags,
7670 struct sockaddr * from, int * fromlen)
7672 if (winsock_lib == NULL)
7674 errno = ENETDOWN;
7675 return SOCKET_ERROR;
7678 check_errno ();
7679 if (fd_info[s].flags & FILE_SOCKET)
7681 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
7682 if (rc == SOCKET_ERROR)
7683 set_errno ();
7684 return rc;
7686 errno = ENOTSOCK;
7687 return SOCKET_ERROR;
7691 sys_sendto (int s, const char * buf, int len, int flags,
7692 const struct sockaddr * to, int tolen)
7694 if (winsock_lib == NULL)
7696 errno = ENETDOWN;
7697 return SOCKET_ERROR;
7700 check_errno ();
7701 if (fd_info[s].flags & FILE_SOCKET)
7703 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
7704 if (rc == SOCKET_ERROR)
7705 set_errno ();
7706 return rc;
7708 errno = ENOTSOCK;
7709 return SOCKET_ERROR;
7712 /* Windows does not have an fcntl function. Provide an implementation
7713 good enough for Emacs. */
7715 fcntl (int s, int cmd, int options)
7717 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
7718 invoked in a context where fd1 is closed and all descriptors less
7719 than fd1 are open, so sys_dup is an adequate implementation. */
7720 if (cmd == F_DUPFD_CLOEXEC)
7721 return sys_dup (s);
7723 if (winsock_lib == NULL)
7725 errno = ENETDOWN;
7726 return -1;
7729 check_errno ();
7730 if (fd_info[s].flags & FILE_SOCKET)
7732 if (cmd == F_SETFL && options == O_NONBLOCK)
7734 unsigned long nblock = 1;
7735 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
7736 if (rc == SOCKET_ERROR)
7737 set_errno ();
7738 /* Keep track of the fact that we set this to non-blocking. */
7739 fd_info[s].flags |= FILE_NDELAY;
7740 return rc;
7742 else
7744 errno = EINVAL;
7745 return SOCKET_ERROR;
7748 errno = ENOTSOCK;
7749 return SOCKET_ERROR;
7753 /* Shadow main io functions: we need to handle pipes and sockets more
7754 intelligently, and implement non-blocking mode as well. */
7757 sys_close (int fd)
7759 int rc;
7761 if (fd < 0)
7763 errno = EBADF;
7764 return -1;
7767 if (fd < MAXDESC && fd_info[fd].cp)
7769 child_process * cp = fd_info[fd].cp;
7771 fd_info[fd].cp = NULL;
7773 if (CHILD_ACTIVE (cp))
7775 /* if last descriptor to active child_process then cleanup */
7776 int i;
7777 for (i = 0; i < MAXDESC; i++)
7779 if (i == fd)
7780 continue;
7781 if (fd_info[i].cp == cp)
7782 break;
7784 if (i == MAXDESC)
7786 if (fd_info[fd].flags & FILE_SOCKET)
7788 if (winsock_lib == NULL) emacs_abort ();
7790 pfn_shutdown (SOCK_HANDLE (fd), 2);
7791 rc = pfn_closesocket (SOCK_HANDLE (fd));
7793 winsock_inuse--; /* count open sockets */
7795 /* If the process handle is NULL, it's either a socket
7796 or serial connection, or a subprocess that was
7797 already reaped by reap_subprocess, but whose
7798 resources were not yet freed, because its output was
7799 not fully read yet by the time it was reaped. (This
7800 usually happens with async subprocesses whose output
7801 is being read by Emacs.) Otherwise, this process was
7802 not reaped yet, so we set its FD to a negative value
7803 to make sure sys_select will eventually get to
7804 calling the SIGCHLD handler for it, which will then
7805 invoke waitpid and reap_subprocess. */
7806 if (cp->procinfo.hProcess == NULL)
7807 delete_child (cp);
7808 else
7809 cp->fd = -1;
7814 if (fd >= 0 && fd < MAXDESC)
7815 fd_info[fd].flags = 0;
7817 /* Note that sockets do not need special treatment here (at least on
7818 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
7819 closesocket is equivalent to CloseHandle, which is to be expected
7820 because socket handles are fully fledged kernel handles. */
7821 rc = _close (fd);
7823 return rc;
7827 sys_dup (int fd)
7829 int new_fd;
7831 new_fd = _dup (fd);
7832 if (new_fd >= 0 && new_fd < MAXDESC)
7834 /* duplicate our internal info as well */
7835 fd_info[new_fd] = fd_info[fd];
7837 return new_fd;
7841 sys_dup2 (int src, int dst)
7843 int rc;
7845 if (dst < 0 || dst >= MAXDESC)
7847 errno = EBADF;
7848 return -1;
7851 /* make sure we close the destination first if it's a pipe or socket */
7852 if (src != dst && fd_info[dst].flags != 0)
7853 sys_close (dst);
7855 rc = _dup2 (src, dst);
7856 if (rc == 0)
7858 /* duplicate our internal info as well */
7859 fd_info[dst] = fd_info[src];
7861 return rc;
7865 pipe2 (int * phandles, int pipe2_flags)
7867 int rc;
7868 unsigned flags;
7870 eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
7872 /* make pipe handles non-inheritable; when we spawn a child, we
7873 replace the relevant handle with an inheritable one. Also put
7874 pipes into binary mode; we will do text mode translation ourselves
7875 if required. */
7876 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
7878 if (rc == 0)
7880 /* Protect against overflow, since Windows can open more handles than
7881 our fd_info array has room for. */
7882 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
7884 _close (phandles[0]);
7885 _close (phandles[1]);
7886 errno = EMFILE;
7887 rc = -1;
7889 else
7891 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
7892 fd_info[phandles[0]].flags = flags;
7894 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
7895 fd_info[phandles[1]].flags = flags;
7899 return rc;
7902 /* Function to do blocking read of one byte, needed to implement
7903 select. It is only allowed on communication ports, sockets, or
7904 pipes. */
7906 _sys_read_ahead (int fd)
7908 child_process * cp;
7909 int rc;
7911 if (fd < 0 || fd >= MAXDESC)
7912 return STATUS_READ_ERROR;
7914 cp = fd_info[fd].cp;
7916 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7917 return STATUS_READ_ERROR;
7919 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
7920 || (fd_info[fd].flags & FILE_READ) == 0)
7922 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
7923 emacs_abort ();
7926 cp->status = STATUS_READ_IN_PROGRESS;
7928 if (fd_info[fd].flags & FILE_PIPE)
7930 rc = _read (fd, &cp->chr, sizeof (char));
7932 /* Give subprocess time to buffer some more output for us before
7933 reporting that input is available; we need this because Windows 95
7934 connects DOS programs to pipes by making the pipe appear to be
7935 the normal console stdout - as a result most DOS programs will
7936 write to stdout without buffering, ie. one character at a
7937 time. Even some W32 programs do this - "dir" in a command
7938 shell on NT is very slow if we don't do this. */
7939 if (rc > 0)
7941 int wait = w32_pipe_read_delay;
7943 if (wait > 0)
7944 Sleep (wait);
7945 else if (wait < 0)
7946 while (++wait <= 0)
7947 /* Yield remainder of our time slice, effectively giving a
7948 temporary priority boost to the child process. */
7949 Sleep (0);
7952 else if (fd_info[fd].flags & FILE_SERIAL)
7954 HANDLE hnd = fd_info[fd].hnd;
7955 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7956 COMMTIMEOUTS ct;
7958 /* Configure timeouts for blocking read. */
7959 if (!GetCommTimeouts (hnd, &ct))
7961 cp->status = STATUS_READ_ERROR;
7962 return STATUS_READ_ERROR;
7964 ct.ReadIntervalTimeout = 0;
7965 ct.ReadTotalTimeoutMultiplier = 0;
7966 ct.ReadTotalTimeoutConstant = 0;
7967 if (!SetCommTimeouts (hnd, &ct))
7969 cp->status = STATUS_READ_ERROR;
7970 return STATUS_READ_ERROR;
7973 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
7975 if (GetLastError () != ERROR_IO_PENDING)
7977 cp->status = STATUS_READ_ERROR;
7978 return STATUS_READ_ERROR;
7980 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
7982 cp->status = STATUS_READ_ERROR;
7983 return STATUS_READ_ERROR;
7987 else if (fd_info[fd].flags & FILE_SOCKET)
7989 unsigned long nblock = 0;
7990 /* We always want this to block, so temporarily disable NDELAY. */
7991 if (fd_info[fd].flags & FILE_NDELAY)
7992 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7994 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
7996 if (fd_info[fd].flags & FILE_NDELAY)
7998 nblock = 1;
7999 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8003 if (rc == sizeof (char))
8004 cp->status = STATUS_READ_SUCCEEDED;
8005 else
8006 cp->status = STATUS_READ_FAILED;
8008 return cp->status;
8012 _sys_wait_accept (int fd)
8014 HANDLE hEv;
8015 child_process * cp;
8016 int rc;
8018 if (fd < 0 || fd >= MAXDESC)
8019 return STATUS_READ_ERROR;
8021 cp = fd_info[fd].cp;
8023 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8024 return STATUS_READ_ERROR;
8026 cp->status = STATUS_READ_FAILED;
8028 hEv = pfn_WSACreateEvent ();
8029 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
8030 if (rc != SOCKET_ERROR)
8032 do {
8033 rc = WaitForSingleObject (hEv, 500);
8034 Sleep (5);
8035 } while (rc == WAIT_TIMEOUT
8036 && cp->status != STATUS_READ_ERROR
8037 && cp->char_avail);
8038 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8039 if (rc == WAIT_OBJECT_0)
8040 cp->status = STATUS_READ_SUCCEEDED;
8042 pfn_WSACloseEvent (hEv);
8044 return cp->status;
8048 sys_read (int fd, char * buffer, unsigned int count)
8050 int nchars;
8051 int to_read;
8052 DWORD waiting;
8053 char * orig_buffer = buffer;
8055 if (fd < 0)
8057 errno = EBADF;
8058 return -1;
8061 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8063 child_process *cp = fd_info[fd].cp;
8065 if ((fd_info[fd].flags & FILE_READ) == 0)
8067 errno = EBADF;
8068 return -1;
8071 nchars = 0;
8073 /* re-read CR carried over from last read */
8074 if (fd_info[fd].flags & FILE_LAST_CR)
8076 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
8077 *buffer++ = 0x0d;
8078 count--;
8079 nchars++;
8080 fd_info[fd].flags &= ~FILE_LAST_CR;
8083 /* presence of a child_process structure means we are operating in
8084 non-blocking mode - otherwise we just call _read directly.
8085 Note that the child_process structure might be missing because
8086 reap_subprocess has been called; in this case the pipe is
8087 already broken, so calling _read on it is okay. */
8088 if (cp)
8090 int current_status = cp->status;
8092 switch (current_status)
8094 case STATUS_READ_FAILED:
8095 case STATUS_READ_ERROR:
8096 /* report normal EOF if nothing in buffer */
8097 if (nchars <= 0)
8098 fd_info[fd].flags |= FILE_AT_EOF;
8099 return nchars;
8101 case STATUS_READ_READY:
8102 case STATUS_READ_IN_PROGRESS:
8103 DebPrint (("sys_read called when read is in progress\n"));
8104 errno = EWOULDBLOCK;
8105 return -1;
8107 case STATUS_READ_SUCCEEDED:
8108 /* consume read-ahead char */
8109 *buffer++ = cp->chr;
8110 count--;
8111 nchars++;
8112 cp->status = STATUS_READ_ACKNOWLEDGED;
8113 ResetEvent (cp->char_avail);
8115 case STATUS_READ_ACKNOWLEDGED:
8116 break;
8118 default:
8119 DebPrint (("sys_read: bad status %d\n", current_status));
8120 errno = EBADF;
8121 return -1;
8124 if (fd_info[fd].flags & FILE_PIPE)
8126 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
8127 to_read = min (waiting, (DWORD) count);
8129 if (to_read > 0)
8130 nchars += _read (fd, buffer, to_read);
8132 else if (fd_info[fd].flags & FILE_SERIAL)
8134 HANDLE hnd = fd_info[fd].hnd;
8135 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8136 int rc = 0;
8137 COMMTIMEOUTS ct;
8139 if (count > 0)
8141 /* Configure timeouts for non-blocking read. */
8142 if (!GetCommTimeouts (hnd, &ct))
8144 errno = EIO;
8145 return -1;
8147 ct.ReadIntervalTimeout = MAXDWORD;
8148 ct.ReadTotalTimeoutMultiplier = 0;
8149 ct.ReadTotalTimeoutConstant = 0;
8150 if (!SetCommTimeouts (hnd, &ct))
8152 errno = EIO;
8153 return -1;
8156 if (!ResetEvent (ovl->hEvent))
8158 errno = EIO;
8159 return -1;
8161 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8163 if (GetLastError () != ERROR_IO_PENDING)
8165 errno = EIO;
8166 return -1;
8168 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8170 errno = EIO;
8171 return -1;
8174 nchars += rc;
8177 else /* FILE_SOCKET */
8179 if (winsock_lib == NULL) emacs_abort ();
8181 /* do the equivalent of a non-blocking read */
8182 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8183 if (waiting == 0 && nchars == 0)
8185 errno = EWOULDBLOCK;
8186 return -1;
8189 if (waiting)
8191 /* always use binary mode for sockets */
8192 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8193 if (res == SOCKET_ERROR)
8195 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8196 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8197 set_errno ();
8198 return -1;
8200 nchars += res;
8204 else
8206 int nread = _read (fd, buffer, count);
8207 if (nread >= 0)
8208 nchars += nread;
8209 else if (nchars == 0)
8210 nchars = nread;
8213 if (nchars <= 0)
8214 fd_info[fd].flags |= FILE_AT_EOF;
8215 /* Perform text mode translation if required. */
8216 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8218 nchars = crlf_to_lf (nchars, orig_buffer);
8219 /* If buffer contains only CR, return that. To be absolutely
8220 sure we should attempt to read the next char, but in
8221 practice a CR to be followed by LF would not appear by
8222 itself in the buffer. */
8223 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8225 fd_info[fd].flags |= FILE_LAST_CR;
8226 nchars--;
8230 else
8231 nchars = _read (fd, buffer, count);
8233 return nchars;
8236 /* From w32xfns.c */
8237 extern HANDLE interrupt_handle;
8239 /* For now, don't bother with a non-blocking mode */
8241 sys_write (int fd, const void * buffer, unsigned int count)
8243 int nchars;
8245 if (fd < 0)
8247 errno = EBADF;
8248 return -1;
8251 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8253 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8255 errno = EBADF;
8256 return -1;
8259 /* Perform text mode translation if required. */
8260 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8262 char * tmpbuf = alloca (count * 2);
8263 unsigned char * src = (void *)buffer;
8264 unsigned char * dst = tmpbuf;
8265 int nbytes = count;
8267 while (1)
8269 unsigned char *next;
8270 /* copy next line or remaining bytes */
8271 next = _memccpy (dst, src, '\n', nbytes);
8272 if (next)
8274 /* copied one line ending with '\n' */
8275 int copied = next - dst;
8276 nbytes -= copied;
8277 src += copied;
8278 /* insert '\r' before '\n' */
8279 next[-1] = '\r';
8280 next[0] = '\n';
8281 dst = next + 1;
8282 count++;
8284 else
8285 /* copied remaining partial line -> now finished */
8286 break;
8288 buffer = tmpbuf;
8292 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8294 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8295 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8296 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8297 DWORD active = 0;
8299 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8301 if (GetLastError () != ERROR_IO_PENDING)
8303 errno = EIO;
8304 return -1;
8306 if (detect_input_pending ())
8307 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
8308 QS_ALLINPUT);
8309 else
8310 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8311 if (active == WAIT_OBJECT_0)
8312 { /* User pressed C-g, cancel write, then leave. Don't bother
8313 cleaning up as we may only get stuck in buggy drivers. */
8314 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8315 CancelIo (hnd);
8316 errno = EIO;
8317 return -1;
8319 if (active == WAIT_OBJECT_0 + 1
8320 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8322 errno = EIO;
8323 return -1;
8327 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8329 unsigned long nblock = 0;
8330 if (winsock_lib == NULL) emacs_abort ();
8332 /* TODO: implement select() properly so non-blocking I/O works. */
8333 /* For now, make sure the write blocks. */
8334 if (fd_info[fd].flags & FILE_NDELAY)
8335 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8337 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
8339 /* Set the socket back to non-blocking if it was before,
8340 for other operations that support it. */
8341 if (fd_info[fd].flags & FILE_NDELAY)
8343 nblock = 1;
8344 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8347 if (nchars == SOCKET_ERROR)
8349 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
8350 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8351 set_errno ();
8354 else
8356 /* Some networked filesystems don't like too large writes, so
8357 break them into smaller chunks. See the Comments section of
8358 the MSDN documentation of WriteFile for details behind the
8359 choice of the value of CHUNK below. See also the thread
8360 http://thread.gmane.org/gmane.comp.version-control.git/145294
8361 in the git mailing list. */
8362 const unsigned char *p = buffer;
8363 const unsigned chunk = 30 * 1024 * 1024;
8365 nchars = 0;
8366 while (count > 0)
8368 unsigned this_chunk = count < chunk ? count : chunk;
8369 int n = _write (fd, p, this_chunk);
8371 nchars += n;
8372 if (n < 0)
8374 nchars = n;
8375 break;
8377 else if (n < this_chunk)
8378 break;
8379 count -= n;
8380 p += n;
8384 return nchars;
8388 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
8390 extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
8392 /* Return information about network interface IFNAME, or about all
8393 interfaces (if IFNAME is nil). */
8394 static Lisp_Object
8395 network_interface_get_info (Lisp_Object ifname)
8397 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
8398 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
8399 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
8400 Lisp_Object res = Qnil;
8402 if (retval == ERROR_BUFFER_OVERFLOW)
8404 ainfo = xrealloc (ainfo, ainfo_len);
8405 retval = get_adapters_info (ainfo, &ainfo_len);
8408 if (retval == ERROR_SUCCESS)
8410 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
8411 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
8412 int if_num;
8413 struct sockaddr_in sa;
8415 /* For the below, we need some winsock functions, so make sure
8416 the winsock DLL is loaded. If we cannot successfully load
8417 it, they will have no use of the information we provide,
8418 anyway, so punt. */
8419 if (!winsock_lib && !init_winsock (1))
8420 goto done;
8422 for (adapter = ainfo; adapter; adapter = adapter->Next)
8424 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
8425 u_long ip_addr;
8426 /* Present Unix-compatible interface names, instead of the
8427 Windows names, which are really GUIDs not readable by
8428 humans. */
8429 static const char *ifmt[] = {
8430 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
8431 "lo", "ifx%d"
8433 enum {
8434 NONE = -1,
8435 ETHERNET = 0,
8436 TOKENRING = 1,
8437 FDDI = 2,
8438 PPP = 3,
8439 SLIP = 4,
8440 WLAN = 5,
8441 LOOPBACK = 6,
8442 OTHER_IF = 7
8443 } ifmt_idx;
8445 switch (adapter->Type)
8447 case MIB_IF_TYPE_ETHERNET:
8448 /* Windows before Vista reports wireless adapters as
8449 Ethernet. Work around by looking at the Description
8450 string. */
8451 if (strstr (adapter->Description, "Wireless "))
8453 ifmt_idx = WLAN;
8454 if_num = wlan_count++;
8456 else
8458 ifmt_idx = ETHERNET;
8459 if_num = eth_count++;
8461 break;
8462 case MIB_IF_TYPE_TOKENRING:
8463 ifmt_idx = TOKENRING;
8464 if_num = tr_count++;
8465 break;
8466 case MIB_IF_TYPE_FDDI:
8467 ifmt_idx = FDDI;
8468 if_num = fddi_count++;
8469 break;
8470 case MIB_IF_TYPE_PPP:
8471 ifmt_idx = PPP;
8472 if_num = ppp_count++;
8473 break;
8474 case MIB_IF_TYPE_SLIP:
8475 ifmt_idx = SLIP;
8476 if_num = sl_count++;
8477 break;
8478 case IF_TYPE_IEEE80211:
8479 ifmt_idx = WLAN;
8480 if_num = wlan_count++;
8481 break;
8482 case MIB_IF_TYPE_LOOPBACK:
8483 if (lo_count < 0)
8485 ifmt_idx = LOOPBACK;
8486 if_num = lo_count++;
8488 else
8489 ifmt_idx = NONE;
8490 break;
8491 default:
8492 ifmt_idx = OTHER_IF;
8493 if_num = ifx_count++;
8494 break;
8496 if (ifmt_idx == NONE)
8497 continue;
8498 sprintf (namebuf, ifmt[ifmt_idx], if_num);
8500 sa.sin_family = AF_INET;
8501 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
8502 if (ip_addr == INADDR_NONE)
8504 /* Bogus address, skip this interface. */
8505 continue;
8507 sa.sin_addr.s_addr = ip_addr;
8508 sa.sin_port = 0;
8509 if (NILP (ifname))
8510 res = Fcons (Fcons (build_string (namebuf),
8511 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
8512 sizeof (struct sockaddr))),
8513 res);
8514 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
8516 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
8517 register struct Lisp_Vector *p = XVECTOR (hwaddr);
8518 Lisp_Object flags = Qnil;
8519 int n;
8520 u_long net_mask;
8522 /* Flags. We guess most of them by type, since the
8523 Windows flags are different and hard to get by. */
8524 flags = Fcons (intern ("up"), flags);
8525 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
8527 flags = Fcons (intern ("broadcast"), flags);
8528 flags = Fcons (intern ("multicast"), flags);
8530 flags = Fcons (intern ("running"), flags);
8531 if (ifmt_idx == PPP)
8533 flags = Fcons (intern ("pointopoint"), flags);
8534 flags = Fcons (intern ("noarp"), flags);
8536 if (adapter->HaveWins)
8537 flags = Fcons (intern ("WINS"), flags);
8538 if (adapter->DhcpEnabled)
8539 flags = Fcons (intern ("dynamic"), flags);
8541 res = Fcons (flags, res);
8543 /* Hardware address and its family. */
8544 for (n = 0; n < adapter->AddressLength; n++)
8545 p->contents[n] = make_number ((int) adapter->Address[n]);
8546 /* Windows does not support AF_LINK or AF_PACKET family
8547 of addresses. Use an arbitrary family number that is
8548 identical to what GNU/Linux returns. */
8549 res = Fcons (Fcons (make_number (1), hwaddr), res);
8551 /* Network mask. */
8552 sa.sin_family = AF_INET;
8553 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
8554 if (net_mask != INADDR_NONE)
8556 sa.sin_addr.s_addr = net_mask;
8557 sa.sin_port = 0;
8558 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8559 sizeof (struct sockaddr)),
8560 res);
8562 else
8563 res = Fcons (Qnil, res);
8565 sa.sin_family = AF_INET;
8566 if (ip_addr != INADDR_NONE)
8568 /* Broadcast address is only reported by
8569 GetAdaptersAddresses, which is of limited
8570 availability. Generate it on our own. */
8571 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
8573 sa.sin_addr.s_addr = bcast_addr;
8574 sa.sin_port = 0;
8575 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8576 sizeof (struct sockaddr)),
8577 res);
8579 /* IP address. */
8580 sa.sin_addr.s_addr = ip_addr;
8581 sa.sin_port = 0;
8582 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8583 sizeof (struct sockaddr)),
8584 res);
8586 else
8587 res = Fcons (Qnil, Fcons (Qnil, res));
8590 /* GetAdaptersInfo is documented to not report loopback
8591 interfaces, so we generate one out of thin air. */
8592 if (!lo_count)
8594 sa.sin_family = AF_INET;
8595 sa.sin_port = 0;
8596 if (NILP (ifname))
8598 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
8599 res = Fcons (Fcons (build_string ("lo"),
8600 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
8601 sizeof (struct sockaddr))),
8602 res);
8604 else if (strcmp (SSDATA (ifname), "lo") == 0)
8606 res = Fcons (Fcons (intern ("running"),
8607 Fcons (intern ("loopback"),
8608 Fcons (intern ("up"), Qnil))), Qnil);
8609 /* 772 is what 3 different GNU/Linux systems report for
8610 the loopback interface. */
8611 res = Fcons (Fcons (make_number (772),
8612 Fmake_vector (make_number (6),
8613 make_number (0))),
8614 res);
8615 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
8616 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8617 sizeof (struct sockaddr)),
8618 res);
8619 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
8620 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8621 sizeof (struct sockaddr)),
8622 res);
8623 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
8624 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8625 sizeof (struct sockaddr)),
8626 res);
8632 done:
8633 xfree (ainfo);
8634 return res;
8637 Lisp_Object
8638 network_interface_list (void)
8640 return network_interface_get_info (Qnil);
8643 Lisp_Object
8644 network_interface_info (Lisp_Object ifname)
8646 CHECK_STRING (ifname);
8647 return network_interface_get_info (ifname);
8651 /* The Windows CRT functions are "optimized for speed", so they don't
8652 check for timezone and DST changes if they were last called less
8653 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
8654 all Emacs features that repeatedly call time functions (e.g.,
8655 display-time) are in real danger of missing timezone and DST
8656 changes. Calling tzset before each localtime call fixes that. */
8657 struct tm *
8658 sys_localtime (const time_t *t)
8660 tzset ();
8661 return localtime (t);
8666 /* Try loading LIBRARY_ID from the file(s) specified in
8667 Vdynamic_library_alist. If the library is loaded successfully,
8668 return the handle of the DLL, and record the filename in the
8669 property :loaded-from of LIBRARY_ID. If the library could not be
8670 found, or when it was already loaded (because the handle is not
8671 recorded anywhere, and so is lost after use), return NULL.
8673 We could also save the handle in :loaded-from, but currently
8674 there's no use case for it. */
8675 HMODULE
8676 w32_delayed_load (Lisp_Object library_id)
8678 HMODULE dll_handle = NULL;
8680 CHECK_SYMBOL (library_id);
8682 if (CONSP (Vdynamic_library_alist)
8683 && NILP (Fassq (library_id, Vlibrary_cache)))
8685 Lisp_Object found = Qnil;
8686 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
8688 if (CONSP (dlls))
8689 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
8691 Lisp_Object dll = XCAR (dlls);
8692 char name[MAX_UTF8_PATH];
8693 DWORD res = -1;
8695 CHECK_STRING (dll);
8696 dll = ENCODE_FILE (dll);
8697 if (w32_unicode_filenames)
8699 wchar_t name_w[MAX_PATH];
8701 filename_to_utf16 (SSDATA (dll), name_w);
8702 dll_handle = LoadLibraryW (name_w);
8703 if (dll_handle)
8705 res = GetModuleFileNameW (dll_handle, name_w,
8706 sizeof (name_w));
8707 if (res > 0)
8708 filename_from_utf16 (name_w, name);
8711 else
8713 char name_a[MAX_PATH];
8715 filename_to_ansi (SSDATA (dll), name_a);
8716 dll_handle = LoadLibraryA (name_a);
8717 if (dll_handle)
8719 res = GetModuleFileNameA (dll_handle, name_a,
8720 sizeof (name_a));
8721 if (res > 0)
8722 filename_from_ansi (name_a, name);
8725 if (dll_handle)
8727 ptrdiff_t len = strlen (name);
8728 found = Fcons (dll,
8729 (res > 0)
8730 /* Possibly truncated */
8731 ? make_specified_string (name, -1, len, 1)
8732 : Qnil);
8733 /* This prevents thread start and end notifications
8734 from being sent to the DLL, for every thread we
8735 start. We don't need those notifications because
8736 threads we create never use any of these DLLs, only
8737 the main thread uses them. This is supposed to
8738 speed up thread creation. */
8739 DisableThreadLibraryCalls (dll_handle);
8740 break;
8744 Fput (library_id, QCloaded_from, found);
8747 return dll_handle;
8751 void
8752 check_windows_init_file (void)
8754 /* A common indication that Emacs is not installed properly is when
8755 it cannot find the Windows installation file. If this file does
8756 not exist in the expected place, tell the user. */
8758 if (!noninteractive && !inhibit_window_system
8759 /* Vload_path is not yet initialized when we are loading
8760 loadup.el. */
8761 && NILP (Vpurify_flag))
8763 Lisp_Object init_file;
8764 int fd;
8766 /* Implementation note: this function runs early during Emacs
8767 startup, before startup.el is run. So Vload_path is still in
8768 its initial unibyte form, but it holds UTF-8 encoded file
8769 names, since init_callproc was already called. So we do not
8770 need to ENCODE_FILE here, but we do need to convert the file
8771 names from UTF-8 to ANSI. */
8772 init_file = build_string ("term/w32-win");
8773 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
8774 if (fd < 0)
8776 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
8777 char *init_file_name = SDATA (init_file);
8778 char *load_path = SDATA (load_path_print);
8779 char *buffer = alloca (1024
8780 + strlen (init_file_name)
8781 + strlen (load_path));
8782 char *msg = buffer;
8783 int needed;
8785 sprintf (buffer,
8786 "The Emacs Windows initialization file \"%s.el\" "
8787 "could not be found in your Emacs installation. "
8788 "Emacs checked the following directories for this file:\n"
8789 "\n%s\n\n"
8790 "When Emacs cannot find this file, it usually means that it "
8791 "was not installed properly, or its distribution file was "
8792 "not unpacked properly.\nSee the README.W32 file in the "
8793 "top-level Emacs directory for more information.",
8794 init_file_name, load_path);
8795 needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
8796 -1, NULL, 0);
8797 if (needed > 0)
8799 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
8801 pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
8802 msg_w, needed);
8803 needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
8804 NULL, 0, NULL, NULL);
8805 if (needed > 0)
8807 char *msg_a = alloca (needed + 1);
8809 pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
8810 NULL, NULL);
8811 msg = msg_a;
8814 MessageBox (NULL,
8815 msg,
8816 "Emacs Abort Dialog",
8817 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
8818 /* Use the low-level system abort. */
8819 abort ();
8821 else
8823 _close (fd);
8828 void
8829 term_ntproc (int ignored)
8831 (void)ignored;
8833 term_timers ();
8835 /* shutdown the socket interface if necessary */
8836 term_winsock ();
8838 term_w32select ();
8841 void
8842 init_ntproc (int dumping)
8844 sigset_t initial_mask = 0;
8846 /* Initialize the socket interface now if available and requested by
8847 the user by defining PRELOAD_WINSOCK; otherwise loading will be
8848 delayed until open-network-stream is called (w32-has-winsock can
8849 also be used to dynamically load or reload winsock).
8851 Conveniently, init_environment is called before us, so
8852 PRELOAD_WINSOCK can be set in the registry. */
8854 /* Always initialize this correctly. */
8855 winsock_lib = NULL;
8857 if (getenv ("PRELOAD_WINSOCK") != NULL)
8858 init_winsock (TRUE);
8860 /* Initial preparation for subprocess support: replace our standard
8861 handles with non-inheritable versions. */
8863 HANDLE parent;
8864 HANDLE stdin_save = INVALID_HANDLE_VALUE;
8865 HANDLE stdout_save = INVALID_HANDLE_VALUE;
8866 HANDLE stderr_save = INVALID_HANDLE_VALUE;
8868 parent = GetCurrentProcess ();
8870 /* ignore errors when duplicating and closing; typically the
8871 handles will be invalid when running as a gui program. */
8872 DuplicateHandle (parent,
8873 GetStdHandle (STD_INPUT_HANDLE),
8874 parent,
8875 &stdin_save,
8877 FALSE,
8878 DUPLICATE_SAME_ACCESS);
8880 DuplicateHandle (parent,
8881 GetStdHandle (STD_OUTPUT_HANDLE),
8882 parent,
8883 &stdout_save,
8885 FALSE,
8886 DUPLICATE_SAME_ACCESS);
8888 DuplicateHandle (parent,
8889 GetStdHandle (STD_ERROR_HANDLE),
8890 parent,
8891 &stderr_save,
8893 FALSE,
8894 DUPLICATE_SAME_ACCESS);
8896 fclose (stdin);
8897 fclose (stdout);
8898 fclose (stderr);
8900 if (stdin_save != INVALID_HANDLE_VALUE)
8901 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
8902 else
8903 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
8904 _fdopen (0, "r");
8906 if (stdout_save != INVALID_HANDLE_VALUE)
8907 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
8908 else
8909 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8910 _fdopen (1, "w");
8912 if (stderr_save != INVALID_HANDLE_VALUE)
8913 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
8914 else
8915 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8916 _fdopen (2, "w");
8919 /* unfortunately, atexit depends on implementation of malloc */
8920 /* atexit (term_ntproc); */
8921 if (!dumping)
8923 /* Make sure we start with all signals unblocked. */
8924 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
8925 signal (SIGABRT, term_ntproc);
8927 init_timers ();
8929 /* determine which drives are fixed, for GetCachedVolumeInformation */
8931 /* GetDriveType must have trailing backslash. */
8932 char drive[] = "A:\\";
8934 /* Loop over all possible drive letters */
8935 while (*drive <= 'Z')
8937 /* Record if this drive letter refers to a fixed drive. */
8938 fixed_drives[DRIVE_INDEX (*drive)] =
8939 (GetDriveType (drive) == DRIVE_FIXED);
8941 (*drive)++;
8944 /* Reset the volume info cache. */
8945 volume_cache = NULL;
8950 shutdown_handler ensures that buffers' autosave files are
8951 up to date when the user logs off, or the system shuts down.
8953 static BOOL WINAPI
8954 shutdown_handler (DWORD type)
8956 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
8957 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
8958 || type == CTRL_LOGOFF_EVENT /* User logs off. */
8959 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
8961 /* Shut down cleanly, making sure autosave files are up to date. */
8962 shut_down_emacs (0, Qnil);
8965 /* Allow other handlers to handle this signal. */
8966 return FALSE;
8969 /* On Windows 9X, load UNICOWS.DLL and return its handle, or die. On
8970 NT, return a handle to GDI32.DLL. */
8971 HANDLE
8972 maybe_load_unicows_dll (void)
8974 if (os_subtype == OS_9X)
8976 HANDLE ret = LoadLibrary ("Unicows.dll");
8977 if (ret)
8979 /* These two functions are present on Windows 9X as stubs
8980 that always fail. We need the real implementations from
8981 UNICOWS.DLL, so we must call these functions through
8982 pointers, and assign the correct addresses to these
8983 pointers at program startup (see emacs.c, which calls
8984 this function early on). */
8985 pMultiByteToWideChar = GetProcAddress (ret, "MultiByteToWideChar");
8986 pWideCharToMultiByte = GetProcAddress (ret, "WideCharToMultiByte");
8987 return ret;
8989 else
8991 int button;
8993 button = MessageBox (NULL,
8994 "Emacs cannot load the UNICOWS.DLL library.\n"
8995 "This library is essential for using Emacs\n"
8996 "on this system. You need to install it.\n\n"
8997 "Emacs will exit when you click OK.",
8998 "Emacs cannot load UNICOWS.DLL",
8999 MB_ICONERROR | MB_TASKMODAL
9000 | MB_SETFOREGROUND | MB_OK);
9001 switch (button)
9003 case IDOK:
9004 default:
9005 exit (1);
9009 else
9011 /* On NT family of Windows, these two functions are always
9012 linked in, so we just assign their addresses to the 2
9013 pointers; no need for the LoadLibrary dance. */
9014 pMultiByteToWideChar = MultiByteToWideChar;
9015 pWideCharToMultiByte = WideCharToMultiByte;
9016 return LoadLibrary ("Gdi32.dll");
9021 globals_of_w32 is used to initialize those global variables that
9022 must always be initialized on startup even when the global variable
9023 initialized is non zero (see the function main in emacs.c).
9025 void
9026 globals_of_w32 (void)
9028 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
9030 get_process_times_fn = (GetProcessTimes_Proc)
9031 GetProcAddress (kernel32, "GetProcessTimes");
9033 DEFSYM (QCloaded_from, ":loaded-from");
9035 g_b_init_is_windows_9x = 0;
9036 g_b_init_open_process_token = 0;
9037 g_b_init_get_token_information = 0;
9038 g_b_init_lookup_account_sid = 0;
9039 g_b_init_get_sid_sub_authority = 0;
9040 g_b_init_get_sid_sub_authority_count = 0;
9041 g_b_init_get_security_info = 0;
9042 g_b_init_get_file_security_w = 0;
9043 g_b_init_get_file_security_a = 0;
9044 g_b_init_get_security_descriptor_owner = 0;
9045 g_b_init_get_security_descriptor_group = 0;
9046 g_b_init_is_valid_sid = 0;
9047 g_b_init_create_toolhelp32_snapshot = 0;
9048 g_b_init_process32_first = 0;
9049 g_b_init_process32_next = 0;
9050 g_b_init_open_thread_token = 0;
9051 g_b_init_impersonate_self = 0;
9052 g_b_init_revert_to_self = 0;
9053 g_b_init_get_process_memory_info = 0;
9054 g_b_init_get_process_working_set_size = 0;
9055 g_b_init_global_memory_status = 0;
9056 g_b_init_global_memory_status_ex = 0;
9057 g_b_init_equal_sid = 0;
9058 g_b_init_copy_sid = 0;
9059 g_b_init_get_length_sid = 0;
9060 g_b_init_get_native_system_info = 0;
9061 g_b_init_get_system_times = 0;
9062 g_b_init_create_symbolic_link_w = 0;
9063 g_b_init_create_symbolic_link_a = 0;
9064 g_b_init_get_security_descriptor_dacl = 0;
9065 g_b_init_convert_sd_to_sddl = 0;
9066 g_b_init_convert_sddl_to_sd = 0;
9067 g_b_init_is_valid_security_descriptor = 0;
9068 g_b_init_set_file_security_w = 0;
9069 g_b_init_set_file_security_a = 0;
9070 g_b_init_set_named_security_info_w = 0;
9071 g_b_init_set_named_security_info_a = 0;
9072 g_b_init_get_adapters_info = 0;
9073 g_b_init_compare_string_w = 0;
9074 num_of_processors = 0;
9075 /* The following sets a handler for shutdown notifications for
9076 console apps. This actually applies to Emacs in both console and
9077 GUI modes, since we had to fool windows into thinking emacs is a
9078 console application to get console mode to work. */
9079 SetConsoleCtrlHandler (shutdown_handler, TRUE);
9081 /* "None" is the default group name on standalone workstations. */
9082 strcpy (dflt_group_name, "None");
9084 /* Reset, in case it has some value inherited from dump time. */
9085 w32_stat_get_owner_group = 0;
9087 /* If w32_unicode_filenames is non-zero, we will be using Unicode
9088 (a.k.a. "wide") APIs to invoke functions that accept file
9089 names. */
9090 if (is_windows_9x ())
9091 w32_unicode_filenames = 0;
9092 else
9093 w32_unicode_filenames = 1;
9096 /* For make-serial-process */
9098 serial_open (Lisp_Object port_obj)
9100 char *port = SSDATA (port_obj);
9101 HANDLE hnd;
9102 child_process *cp;
9103 int fd = -1;
9105 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
9106 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
9107 if (hnd == INVALID_HANDLE_VALUE)
9108 error ("Could not open %s", port);
9109 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
9110 if (fd == -1)
9111 error ("Could not open %s", port);
9113 cp = new_child ();
9114 if (!cp)
9115 error ("Could not create child process");
9116 cp->fd = fd;
9117 cp->status = STATUS_READ_ACKNOWLEDGED;
9118 fd_info[ fd ].hnd = hnd;
9119 fd_info[ fd ].flags |=
9120 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
9121 if (fd_info[ fd ].cp != NULL)
9123 error ("fd_info[fd = %d] is already in use", fd);
9125 fd_info[ fd ].cp = cp;
9126 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9127 if (cp->ovl_read.hEvent == NULL)
9128 error ("Could not create read event");
9129 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9130 if (cp->ovl_write.hEvent == NULL)
9131 error ("Could not create write event");
9133 return fd;
9136 /* For serial-process-configure */
9137 void
9138 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
9140 Lisp_Object childp2 = Qnil;
9141 Lisp_Object tem = Qnil;
9142 HANDLE hnd;
9143 DCB dcb;
9144 COMMTIMEOUTS ct;
9145 char summary[4] = "???"; /* This usually becomes "8N1". */
9147 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
9148 error ("Not a serial process");
9149 hnd = fd_info[ p->outfd ].hnd;
9151 childp2 = Fcopy_sequence (p->childp);
9153 /* Initialize timeouts for blocking read and blocking write. */
9154 if (!GetCommTimeouts (hnd, &ct))
9155 error ("GetCommTimeouts() failed");
9156 ct.ReadIntervalTimeout = 0;
9157 ct.ReadTotalTimeoutMultiplier = 0;
9158 ct.ReadTotalTimeoutConstant = 0;
9159 ct.WriteTotalTimeoutMultiplier = 0;
9160 ct.WriteTotalTimeoutConstant = 0;
9161 if (!SetCommTimeouts (hnd, &ct))
9162 error ("SetCommTimeouts() failed");
9163 /* Read port attributes and prepare default configuration. */
9164 memset (&dcb, 0, sizeof (dcb));
9165 dcb.DCBlength = sizeof (DCB);
9166 if (!GetCommState (hnd, &dcb))
9167 error ("GetCommState() failed");
9168 dcb.fBinary = TRUE;
9169 dcb.fNull = FALSE;
9170 dcb.fAbortOnError = FALSE;
9171 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
9172 dcb.ErrorChar = 0;
9173 dcb.EofChar = 0;
9174 dcb.EvtChar = 0;
9176 /* Configure speed. */
9177 if (!NILP (Fplist_member (contact, QCspeed)))
9178 tem = Fplist_get (contact, QCspeed);
9179 else
9180 tem = Fplist_get (p->childp, QCspeed);
9181 CHECK_NUMBER (tem);
9182 dcb.BaudRate = XINT (tem);
9183 childp2 = Fplist_put (childp2, QCspeed, tem);
9185 /* Configure bytesize. */
9186 if (!NILP (Fplist_member (contact, QCbytesize)))
9187 tem = Fplist_get (contact, QCbytesize);
9188 else
9189 tem = Fplist_get (p->childp, QCbytesize);
9190 if (NILP (tem))
9191 tem = make_number (8);
9192 CHECK_NUMBER (tem);
9193 if (XINT (tem) != 7 && XINT (tem) != 8)
9194 error (":bytesize must be nil (8), 7, or 8");
9195 dcb.ByteSize = XINT (tem);
9196 summary[0] = XINT (tem) + '0';
9197 childp2 = Fplist_put (childp2, QCbytesize, tem);
9199 /* Configure parity. */
9200 if (!NILP (Fplist_member (contact, QCparity)))
9201 tem = Fplist_get (contact, QCparity);
9202 else
9203 tem = Fplist_get (p->childp, QCparity);
9204 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
9205 error (":parity must be nil (no parity), `even', or `odd'");
9206 dcb.fParity = FALSE;
9207 dcb.Parity = NOPARITY;
9208 dcb.fErrorChar = FALSE;
9209 if (NILP (tem))
9211 summary[1] = 'N';
9213 else if (EQ (tem, Qeven))
9215 summary[1] = 'E';
9216 dcb.fParity = TRUE;
9217 dcb.Parity = EVENPARITY;
9218 dcb.fErrorChar = TRUE;
9220 else if (EQ (tem, Qodd))
9222 summary[1] = 'O';
9223 dcb.fParity = TRUE;
9224 dcb.Parity = ODDPARITY;
9225 dcb.fErrorChar = TRUE;
9227 childp2 = Fplist_put (childp2, QCparity, tem);
9229 /* Configure stopbits. */
9230 if (!NILP (Fplist_member (contact, QCstopbits)))
9231 tem = Fplist_get (contact, QCstopbits);
9232 else
9233 tem = Fplist_get (p->childp, QCstopbits);
9234 if (NILP (tem))
9235 tem = make_number (1);
9236 CHECK_NUMBER (tem);
9237 if (XINT (tem) != 1 && XINT (tem) != 2)
9238 error (":stopbits must be nil (1 stopbit), 1, or 2");
9239 summary[2] = XINT (tem) + '0';
9240 if (XINT (tem) == 1)
9241 dcb.StopBits = ONESTOPBIT;
9242 else if (XINT (tem) == 2)
9243 dcb.StopBits = TWOSTOPBITS;
9244 childp2 = Fplist_put (childp2, QCstopbits, tem);
9246 /* Configure flowcontrol. */
9247 if (!NILP (Fplist_member (contact, QCflowcontrol)))
9248 tem = Fplist_get (contact, QCflowcontrol);
9249 else
9250 tem = Fplist_get (p->childp, QCflowcontrol);
9251 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
9252 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
9253 dcb.fOutxCtsFlow = FALSE;
9254 dcb.fOutxDsrFlow = FALSE;
9255 dcb.fDtrControl = DTR_CONTROL_DISABLE;
9256 dcb.fDsrSensitivity = FALSE;
9257 dcb.fTXContinueOnXoff = FALSE;
9258 dcb.fOutX = FALSE;
9259 dcb.fInX = FALSE;
9260 dcb.fRtsControl = RTS_CONTROL_DISABLE;
9261 dcb.XonChar = 17; /* Control-Q */
9262 dcb.XoffChar = 19; /* Control-S */
9263 if (NILP (tem))
9265 /* Already configured. */
9267 else if (EQ (tem, Qhw))
9269 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
9270 dcb.fOutxCtsFlow = TRUE;
9272 else if (EQ (tem, Qsw))
9274 dcb.fOutX = TRUE;
9275 dcb.fInX = TRUE;
9277 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
9279 /* Activate configuration. */
9280 if (!SetCommState (hnd, &dcb))
9281 error ("SetCommState() failed");
9283 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
9284 pset_childp (p, childp2);
9287 #ifdef HAVE_GNUTLS
9289 ssize_t
9290 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
9292 int n, err;
9293 struct Lisp_Process *process = (struct Lisp_Process *)p;
9294 int fd = process->infd;
9296 n = sys_read (fd, (char*)buf, sz);
9298 if (n >= 0)
9299 return n;
9301 err = errno;
9303 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9304 if (err == EWOULDBLOCK)
9305 err = EAGAIN;
9307 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
9309 return -1;
9312 ssize_t
9313 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
9315 struct Lisp_Process *process = (struct Lisp_Process *)p;
9316 int fd = process->outfd;
9317 ssize_t n = sys_write (fd, buf, sz);
9319 /* 0 or more bytes written means everything went fine. */
9320 if (n >= 0)
9321 return n;
9323 /* Negative bytes written means we got an error in errno.
9324 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9325 emacs_gnutls_transport_set_errno (process->gnutls_state,
9326 errno == EWOULDBLOCK ? EAGAIN : errno);
9328 return -1;
9330 #endif /* HAVE_GNUTLS */
9332 /* end of w32.c */