Remove more compilation warnings in MinGW64 build
[emacs.git] / src / w32.c
blobf583d5e76c2b3e2916bb96033080afc0d2bfa6ad
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
3 Copyright (C) 1994-1995, 2000-2017 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 (at
10 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 #define DEFER_MS_W32_H
25 #include <config.h>
27 #include <mingw_time.h>
28 #include <stddef.h> /* for offsetof */
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <float.h> /* for DBL_EPSILON */
32 #include <io.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <ctype.h>
36 #include <signal.h>
37 #include <sys/file.h>
38 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
39 #include <sys/time.h>
40 #include <sys/utime.h>
41 #include <math.h>
43 /* Include (most) CRT headers *before* ms-w32.h. */
44 #include <ms-w32.h>
46 #include <string.h> /* for strerror, needed by sys_strerror */
47 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
49 #undef access
50 #undef chdir
51 #undef chmod
52 #undef creat
53 #undef ctime
54 #undef fopen
55 #undef link
56 #undef mkdir
57 #undef open
58 #undef rename
59 #undef rmdir
60 #undef unlink
62 #undef close
63 #undef dup
64 #undef dup2
65 #undef pipe
66 #undef read
67 #undef write
69 #undef strerror
71 #undef localtime
73 char *sys_ctime (const time_t *);
74 int sys_chdir (const char *);
75 int sys_creat (const char *, int);
76 FILE *sys_fopen (const char *, const char *);
77 int sys_open (const char *, int, int);
78 int sys_rename (char const *, char const *);
79 int sys_rmdir (const char *);
80 int sys_close (int);
81 int sys_dup2 (int, int);
82 int sys_read (int, char *, unsigned int);
83 int sys_write (int, const void *, unsigned int);
84 struct tm *sys_localtime (const time_t *);
86 #ifdef HAVE_MODULES
87 extern void dynlib_reset_last_error (void);
88 #endif
90 #include "lisp.h"
91 #include "epaths.h" /* for PATH_EXEC */
93 #include <pwd.h>
94 #include <grp.h>
96 #include <windows.h>
97 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
98 use a different name to avoid compilation problems. */
99 typedef struct _MEMORY_STATUS_EX {
100 DWORD dwLength;
101 DWORD dwMemoryLoad;
102 DWORDLONG ullTotalPhys;
103 DWORDLONG ullAvailPhys;
104 DWORDLONG ullTotalPageFile;
105 DWORDLONG ullAvailPageFile;
106 DWORDLONG ullTotalVirtual;
107 DWORDLONG ullAvailVirtual;
108 DWORDLONG ullAvailExtendedVirtual;
109 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
111 /* These are here so that GDB would know about these data types. This
112 allows attaching GDB to Emacs when a fatal exception is triggered
113 and Windows pops up the "application needs to be closed" dialog.
114 At that point, _gnu_exception_handler, the top-level exception
115 handler installed by the MinGW startup code, is somewhere on the
116 call-stack of the main thread, so going to that call frame and
117 looking at the argument to _gnu_exception_handler, which is a
118 PEXCEPTION_POINTERS pointer, can reveal the exception code
119 (excptr->ExceptionRecord->ExceptionCode) and the address where the
120 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
121 well as some additional information specific to the exception. */
122 PEXCEPTION_POINTERS excptr;
123 PEXCEPTION_RECORD excprec;
124 PCONTEXT ctxrec;
126 #include <lmcons.h>
127 #include <shlobj.h>
129 #include <tlhelp32.h>
130 #include <psapi.h>
131 #ifndef _MSC_VER
132 #include <w32api.h>
133 #endif
134 #if _WIN32_WINNT < 0x0500
135 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
136 /* This either is not in psapi.h or guarded by higher value of
137 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
138 defines it in psapi.h */
139 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
140 DWORD cb;
141 DWORD PageFaultCount;
142 SIZE_T PeakWorkingSetSize;
143 SIZE_T WorkingSetSize;
144 SIZE_T QuotaPeakPagedPoolUsage;
145 SIZE_T QuotaPagedPoolUsage;
146 SIZE_T QuotaPeakNonPagedPoolUsage;
147 SIZE_T QuotaNonPagedPoolUsage;
148 SIZE_T PagefileUsage;
149 SIZE_T PeakPagefileUsage;
150 SIZE_T PrivateUsage;
151 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
152 #endif
153 #endif
155 #include <winioctl.h>
156 #include <aclapi.h>
157 #include <sddl.h>
159 #include <sys/acl.h>
160 #include <acl.h>
162 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
163 define them by hand if not already defined. */
164 #ifndef SDDL_REVISION_1
165 #define SDDL_REVISION_1 1
166 #endif /* SDDL_REVISION_1 */
168 #if defined(_MSC_VER) || defined(MINGW_W64)
169 /* MSVC and MinGW64 don't provide the definition of
170 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
171 which cannot be included because it triggers conflicts with other
172 Windows API headers. So we define it here by hand. */
174 typedef struct _REPARSE_DATA_BUFFER {
175 ULONG ReparseTag;
176 USHORT ReparseDataLength;
177 USHORT Reserved;
178 union {
179 struct {
180 USHORT SubstituteNameOffset;
181 USHORT SubstituteNameLength;
182 USHORT PrintNameOffset;
183 USHORT PrintNameLength;
184 ULONG Flags;
185 WCHAR PathBuffer[1];
186 } SymbolicLinkReparseBuffer;
187 struct {
188 USHORT SubstituteNameOffset;
189 USHORT SubstituteNameLength;
190 USHORT PrintNameOffset;
191 USHORT PrintNameLength;
192 WCHAR PathBuffer[1];
193 } MountPointReparseBuffer;
194 struct {
195 UCHAR DataBuffer[1];
196 } GenericReparseBuffer;
197 } DUMMYUNIONNAME;
198 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
200 #ifndef FILE_DEVICE_FILE_SYSTEM
201 #define FILE_DEVICE_FILE_SYSTEM 9
202 #endif
203 #ifndef METHOD_BUFFERED
204 #define METHOD_BUFFERED 0
205 #endif
206 #ifndef FILE_ANY_ACCESS
207 #define FILE_ANY_ACCESS 0x00000000
208 #endif
209 #ifndef CTL_CODE
210 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
211 #endif
212 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
213 #ifndef FSCTL_GET_REPARSE_POINT
214 #define FSCTL_GET_REPARSE_POINT \
215 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
216 #endif
217 #endif
219 /* TCP connection support. */
220 #include <sys/socket.h>
221 #undef socket
222 #undef bind
223 #undef connect
224 #undef htons
225 #undef ntohs
226 #undef inet_addr
227 #undef gethostname
228 #undef gethostbyname
229 #undef getservbyname
230 #undef getpeername
231 #undef shutdown
232 #undef setsockopt
233 #undef listen
234 #undef getsockname
235 #undef accept
236 #undef recvfrom
237 #undef sendto
239 #include <iphlpapi.h> /* should be after winsock2.h */
241 #include <wincrypt.h>
243 #include <c-strcase.h>
244 #include <utimens.h> /* for fdutimens */
246 #include "w32.h"
247 #include <dirent.h>
248 #include "w32common.h"
249 #include "w32select.h"
250 #include "systime.h" /* for current_timespec, struct timespec */
251 #include "dispextern.h" /* for xstrcasecmp */
252 #include "coding.h" /* for Vlocale_coding_system */
254 #include "careadlinkat.h"
255 #include "allocator.h"
257 /* For Lisp_Process, serial_configure and serial_open. */
258 #include "process.h"
259 #include "systty.h"
261 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
262 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
264 static DWORD get_rid (PSID);
265 static int is_symlink (const char *);
266 static char * chase_symlinks (const char *);
267 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
268 static int restore_privilege (TOKEN_PRIVILEGES *);
269 static BOOL WINAPI revert_to_self (void);
271 static int sys_access (const char *, int);
272 extern void *e_malloc (size_t);
273 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
274 const struct timespec *, const sigset_t *);
275 extern int sys_dup (int);
278 /* Initialization states.
280 WARNING: If you add any more such variables for additional APIs,
281 you MUST add initialization for them to globals_of_w32
282 below. This is because these variables might get set
283 to non-NULL values during dumping, but the dumped Emacs
284 cannot reuse those values, because it could be run on a
285 different version of the OS, where API addresses are
286 different. */
287 static BOOL g_b_init_is_windows_9x;
288 static BOOL g_b_init_open_process_token;
289 static BOOL g_b_init_get_token_information;
290 static BOOL g_b_init_lookup_account_sid;
291 static BOOL g_b_init_get_sid_sub_authority;
292 static BOOL g_b_init_get_sid_sub_authority_count;
293 static BOOL g_b_init_get_security_info;
294 static BOOL g_b_init_get_file_security_w;
295 static BOOL g_b_init_get_file_security_a;
296 static BOOL g_b_init_get_security_descriptor_owner;
297 static BOOL g_b_init_get_security_descriptor_group;
298 static BOOL g_b_init_is_valid_sid;
299 static BOOL g_b_init_create_toolhelp32_snapshot;
300 static BOOL g_b_init_process32_first;
301 static BOOL g_b_init_process32_next;
302 static BOOL g_b_init_open_thread_token;
303 static BOOL g_b_init_impersonate_self;
304 static BOOL g_b_init_revert_to_self;
305 static BOOL g_b_init_get_process_memory_info;
306 static BOOL g_b_init_get_process_working_set_size;
307 static BOOL g_b_init_global_memory_status;
308 static BOOL g_b_init_global_memory_status_ex;
309 static BOOL g_b_init_get_length_sid;
310 static BOOL g_b_init_equal_sid;
311 static BOOL g_b_init_copy_sid;
312 static BOOL g_b_init_get_native_system_info;
313 static BOOL g_b_init_get_system_times;
314 static BOOL g_b_init_create_symbolic_link_w;
315 static BOOL g_b_init_create_symbolic_link_a;
316 static BOOL g_b_init_get_security_descriptor_dacl;
317 static BOOL g_b_init_convert_sd_to_sddl;
318 static BOOL g_b_init_convert_sddl_to_sd;
319 static BOOL g_b_init_is_valid_security_descriptor;
320 static BOOL g_b_init_set_file_security_w;
321 static BOOL g_b_init_set_file_security_a;
322 static BOOL g_b_init_set_named_security_info_w;
323 static BOOL g_b_init_set_named_security_info_a;
324 static BOOL g_b_init_get_adapters_info;
326 BOOL g_b_init_compare_string_w;
327 BOOL g_b_init_debug_break_process;
330 BEGIN: Wrapper functions around OpenProcessToken
331 and other functions in advapi32.dll that are only
332 supported in Windows NT / 2k / XP
334 /* ** Function pointer typedefs ** */
335 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
336 HANDLE ProcessHandle,
337 DWORD DesiredAccess,
338 PHANDLE TokenHandle);
339 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
340 HANDLE TokenHandle,
341 TOKEN_INFORMATION_CLASS TokenInformationClass,
342 LPVOID TokenInformation,
343 DWORD TokenInformationLength,
344 PDWORD ReturnLength);
345 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
346 HANDLE process_handle,
347 LPFILETIME creation_time,
348 LPFILETIME exit_time,
349 LPFILETIME kernel_time,
350 LPFILETIME user_time);
352 GetProcessTimes_Proc get_process_times_fn = NULL;
354 #ifdef _UNICODE
355 const char * const LookupAccountSid_Name = "LookupAccountSidW";
356 #else
357 const char * const LookupAccountSid_Name = "LookupAccountSidA";
358 #endif
359 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
360 LPCTSTR lpSystemName,
361 PSID Sid,
362 LPTSTR Name,
363 LPDWORD cbName,
364 LPTSTR DomainName,
365 LPDWORD cbDomainName,
366 PSID_NAME_USE peUse);
367 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
368 PSID pSid,
369 DWORD n);
370 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
371 PSID pSid);
372 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
373 HANDLE handle,
374 SE_OBJECT_TYPE ObjectType,
375 SECURITY_INFORMATION SecurityInfo,
376 PSID *ppsidOwner,
377 PSID *ppsidGroup,
378 PACL *ppDacl,
379 PACL *ppSacl,
380 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
381 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
382 LPCWSTR lpFileName,
383 SECURITY_INFORMATION RequestedInformation,
384 PSECURITY_DESCRIPTOR pSecurityDescriptor,
385 DWORD nLength,
386 LPDWORD lpnLengthNeeded);
387 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
388 LPCSTR lpFileName,
389 SECURITY_INFORMATION RequestedInformation,
390 PSECURITY_DESCRIPTOR pSecurityDescriptor,
391 DWORD nLength,
392 LPDWORD lpnLengthNeeded);
393 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
394 LPCWSTR lpFileName,
395 SECURITY_INFORMATION SecurityInformation,
396 PSECURITY_DESCRIPTOR pSecurityDescriptor);
397 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
398 LPCSTR lpFileName,
399 SECURITY_INFORMATION SecurityInformation,
400 PSECURITY_DESCRIPTOR pSecurityDescriptor);
401 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
402 LPCWSTR lpObjectName,
403 SE_OBJECT_TYPE ObjectType,
404 SECURITY_INFORMATION SecurityInformation,
405 PSID psidOwner,
406 PSID psidGroup,
407 PACL pDacl,
408 PACL pSacl);
409 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
410 LPCSTR lpObjectName,
411 SE_OBJECT_TYPE ObjectType,
412 SECURITY_INFORMATION SecurityInformation,
413 PSID psidOwner,
414 PSID psidGroup,
415 PACL pDacl,
416 PACL pSacl);
417 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
418 PSECURITY_DESCRIPTOR pSecurityDescriptor,
419 PSID *pOwner,
420 LPBOOL lpbOwnerDefaulted);
421 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
422 PSECURITY_DESCRIPTOR pSecurityDescriptor,
423 PSID *pGroup,
424 LPBOOL lpbGroupDefaulted);
425 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
426 PSECURITY_DESCRIPTOR pSecurityDescriptor,
427 LPBOOL lpbDaclPresent,
428 PACL *pDacl,
429 LPBOOL lpbDaclDefaulted);
430 typedef BOOL (WINAPI * IsValidSid_Proc) (
431 PSID sid);
432 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
433 DWORD dwFlags,
434 DWORD th32ProcessID);
435 typedef BOOL (WINAPI * Process32First_Proc) (
436 HANDLE hSnapshot,
437 LPPROCESSENTRY32 lppe);
438 typedef BOOL (WINAPI * Process32Next_Proc) (
439 HANDLE hSnapshot,
440 LPPROCESSENTRY32 lppe);
441 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
442 HANDLE ThreadHandle,
443 DWORD DesiredAccess,
444 BOOL OpenAsSelf,
445 PHANDLE TokenHandle);
446 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
447 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
448 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
449 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
450 HANDLE Process,
451 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
452 DWORD cb);
453 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
454 HANDLE hProcess,
455 PSIZE_T lpMinimumWorkingSetSize,
456 PSIZE_T lpMaximumWorkingSetSize);
457 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
458 LPMEMORYSTATUS lpBuffer);
459 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
460 LPMEMORY_STATUS_EX lpBuffer);
461 typedef BOOL (WINAPI * CopySid_Proc) (
462 DWORD nDestinationSidLength,
463 PSID pDestinationSid,
464 PSID pSourceSid);
465 typedef BOOL (WINAPI * EqualSid_Proc) (
466 PSID pSid1,
467 PSID pSid2);
468 typedef DWORD (WINAPI * GetLengthSid_Proc) (
469 PSID pSid);
470 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
471 LPSYSTEM_INFO lpSystemInfo);
472 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
473 LPFILETIME lpIdleTime,
474 LPFILETIME lpKernelTime,
475 LPFILETIME lpUserTime);
476 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
477 LPCWSTR lpSymlinkFileName,
478 LPCWSTR lpTargetFileName,
479 DWORD dwFlags);
480 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
481 LPCSTR lpSymlinkFileName,
482 LPCSTR lpTargetFileName,
483 DWORD dwFlags);
484 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
485 LPCTSTR StringSecurityDescriptor,
486 DWORD StringSDRevision,
487 PSECURITY_DESCRIPTOR *SecurityDescriptor,
488 PULONG SecurityDescriptorSize);
489 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
490 PSECURITY_DESCRIPTOR SecurityDescriptor,
491 DWORD RequestedStringSDRevision,
492 SECURITY_INFORMATION SecurityInformation,
493 LPTSTR *StringSecurityDescriptor,
494 PULONG StringSecurityDescriptorLen);
495 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
496 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
497 PIP_ADAPTER_INFO pAdapterInfo,
498 PULONG pOutBufLen);
500 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
501 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
502 DWORD multiByteToWideCharFlags;
504 /* ** A utility function ** */
505 static BOOL
506 is_windows_9x (void)
508 static BOOL s_b_ret = 0;
509 OSVERSIONINFO os_ver;
510 if (g_b_init_is_windows_9x == 0)
512 g_b_init_is_windows_9x = 1;
513 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
514 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
515 if (GetVersionEx (&os_ver))
517 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
520 return s_b_ret;
523 static Lisp_Object ltime (ULONGLONG);
525 /* Get total user and system times for get-internal-run-time.
526 Returns a list of integers if the times are provided by the OS
527 (NT derivatives), otherwise it returns the result of current-time. */
528 Lisp_Object w32_get_internal_run_time (void);
530 Lisp_Object
531 w32_get_internal_run_time (void)
533 if (get_process_times_fn)
535 FILETIME create, exit, kernel, user;
536 HANDLE proc = GetCurrentProcess ();
537 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
539 LARGE_INTEGER user_int, kernel_int, total;
540 user_int.LowPart = user.dwLowDateTime;
541 user_int.HighPart = user.dwHighDateTime;
542 kernel_int.LowPart = kernel.dwLowDateTime;
543 kernel_int.HighPart = kernel.dwHighDateTime;
544 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
545 return ltime (total.QuadPart);
549 return Fcurrent_time ();
552 /* ** The wrapper functions ** */
554 static BOOL WINAPI
555 open_process_token (HANDLE ProcessHandle,
556 DWORD DesiredAccess,
557 PHANDLE TokenHandle)
559 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
560 HMODULE hm_advapi32 = NULL;
561 if (is_windows_9x () == TRUE)
563 return FALSE;
565 if (g_b_init_open_process_token == 0)
567 g_b_init_open_process_token = 1;
568 hm_advapi32 = LoadLibrary ("Advapi32.dll");
569 s_pfn_Open_Process_Token =
570 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
572 if (s_pfn_Open_Process_Token == NULL)
574 return FALSE;
576 return (
577 s_pfn_Open_Process_Token (
578 ProcessHandle,
579 DesiredAccess,
580 TokenHandle)
584 static BOOL WINAPI
585 get_token_information (HANDLE TokenHandle,
586 TOKEN_INFORMATION_CLASS TokenInformationClass,
587 LPVOID TokenInformation,
588 DWORD TokenInformationLength,
589 PDWORD ReturnLength)
591 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
592 HMODULE hm_advapi32 = NULL;
593 if (is_windows_9x () == TRUE)
595 return FALSE;
597 if (g_b_init_get_token_information == 0)
599 g_b_init_get_token_information = 1;
600 hm_advapi32 = LoadLibrary ("Advapi32.dll");
601 s_pfn_Get_Token_Information =
602 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
604 if (s_pfn_Get_Token_Information == NULL)
606 return FALSE;
608 return (
609 s_pfn_Get_Token_Information (
610 TokenHandle,
611 TokenInformationClass,
612 TokenInformation,
613 TokenInformationLength,
614 ReturnLength)
618 static BOOL WINAPI
619 lookup_account_sid (LPCTSTR lpSystemName,
620 PSID Sid,
621 LPTSTR Name,
622 LPDWORD cbName,
623 LPTSTR DomainName,
624 LPDWORD cbDomainName,
625 PSID_NAME_USE peUse)
627 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
628 HMODULE hm_advapi32 = NULL;
629 if (is_windows_9x () == TRUE)
631 return FALSE;
633 if (g_b_init_lookup_account_sid == 0)
635 g_b_init_lookup_account_sid = 1;
636 hm_advapi32 = LoadLibrary ("Advapi32.dll");
637 s_pfn_Lookup_Account_Sid =
638 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
640 if (s_pfn_Lookup_Account_Sid == NULL)
642 return FALSE;
644 return (
645 s_pfn_Lookup_Account_Sid (
646 lpSystemName,
647 Sid,
648 Name,
649 cbName,
650 DomainName,
651 cbDomainName,
652 peUse)
656 static PDWORD WINAPI
657 get_sid_sub_authority (PSID pSid, DWORD n)
659 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
660 static DWORD zero = 0U;
661 HMODULE hm_advapi32 = NULL;
662 if (is_windows_9x () == TRUE)
664 return &zero;
666 if (g_b_init_get_sid_sub_authority == 0)
668 g_b_init_get_sid_sub_authority = 1;
669 hm_advapi32 = LoadLibrary ("Advapi32.dll");
670 s_pfn_Get_Sid_Sub_Authority =
671 (GetSidSubAuthority_Proc) GetProcAddress (
672 hm_advapi32, "GetSidSubAuthority");
674 if (s_pfn_Get_Sid_Sub_Authority == NULL)
676 return &zero;
678 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
681 static PUCHAR WINAPI
682 get_sid_sub_authority_count (PSID pSid)
684 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
685 static UCHAR zero = 0U;
686 HMODULE hm_advapi32 = NULL;
687 if (is_windows_9x () == TRUE)
689 return &zero;
691 if (g_b_init_get_sid_sub_authority_count == 0)
693 g_b_init_get_sid_sub_authority_count = 1;
694 hm_advapi32 = LoadLibrary ("Advapi32.dll");
695 s_pfn_Get_Sid_Sub_Authority_Count =
696 (GetSidSubAuthorityCount_Proc) GetProcAddress (
697 hm_advapi32, "GetSidSubAuthorityCount");
699 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
701 return &zero;
703 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
706 static DWORD WINAPI
707 get_security_info (HANDLE handle,
708 SE_OBJECT_TYPE ObjectType,
709 SECURITY_INFORMATION SecurityInfo,
710 PSID *ppsidOwner,
711 PSID *ppsidGroup,
712 PACL *ppDacl,
713 PACL *ppSacl,
714 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
716 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
717 HMODULE hm_advapi32 = NULL;
718 if (is_windows_9x () == TRUE)
720 return FALSE;
722 if (g_b_init_get_security_info == 0)
724 g_b_init_get_security_info = 1;
725 hm_advapi32 = LoadLibrary ("Advapi32.dll");
726 s_pfn_Get_Security_Info =
727 (GetSecurityInfo_Proc) GetProcAddress (
728 hm_advapi32, "GetSecurityInfo");
730 if (s_pfn_Get_Security_Info == NULL)
732 return FALSE;
734 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
735 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
736 ppSecurityDescriptor));
739 static BOOL WINAPI
740 get_file_security (const char *lpFileName,
741 SECURITY_INFORMATION RequestedInformation,
742 PSECURITY_DESCRIPTOR pSecurityDescriptor,
743 DWORD nLength,
744 LPDWORD lpnLengthNeeded)
746 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
747 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
748 HMODULE hm_advapi32 = NULL;
749 if (is_windows_9x () == TRUE)
751 errno = ENOTSUP;
752 return FALSE;
754 if (w32_unicode_filenames)
756 wchar_t filename_w[MAX_PATH];
758 if (g_b_init_get_file_security_w == 0)
760 g_b_init_get_file_security_w = 1;
761 hm_advapi32 = LoadLibrary ("Advapi32.dll");
762 s_pfn_Get_File_SecurityW =
763 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
764 "GetFileSecurityW");
766 if (s_pfn_Get_File_SecurityW == NULL)
768 errno = ENOTSUP;
769 return FALSE;
771 filename_to_utf16 (lpFileName, filename_w);
772 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
773 pSecurityDescriptor, nLength,
774 lpnLengthNeeded));
776 else
778 char filename_a[MAX_PATH];
780 if (g_b_init_get_file_security_a == 0)
782 g_b_init_get_file_security_a = 1;
783 hm_advapi32 = LoadLibrary ("Advapi32.dll");
784 s_pfn_Get_File_SecurityA =
785 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
786 "GetFileSecurityA");
788 if (s_pfn_Get_File_SecurityA == NULL)
790 errno = ENOTSUP;
791 return FALSE;
793 filename_to_ansi (lpFileName, filename_a);
794 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
795 pSecurityDescriptor, nLength,
796 lpnLengthNeeded));
800 static BOOL WINAPI
801 set_file_security (const char *lpFileName,
802 SECURITY_INFORMATION SecurityInformation,
803 PSECURITY_DESCRIPTOR pSecurityDescriptor)
805 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
806 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
807 HMODULE hm_advapi32 = NULL;
808 if (is_windows_9x () == TRUE)
810 errno = ENOTSUP;
811 return FALSE;
813 if (w32_unicode_filenames)
815 wchar_t filename_w[MAX_PATH];
817 if (g_b_init_set_file_security_w == 0)
819 g_b_init_set_file_security_w = 1;
820 hm_advapi32 = LoadLibrary ("Advapi32.dll");
821 s_pfn_Set_File_SecurityW =
822 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
823 "SetFileSecurityW");
825 if (s_pfn_Set_File_SecurityW == NULL)
827 errno = ENOTSUP;
828 return FALSE;
830 filename_to_utf16 (lpFileName, filename_w);
831 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
832 pSecurityDescriptor));
834 else
836 char filename_a[MAX_PATH];
838 if (g_b_init_set_file_security_a == 0)
840 g_b_init_set_file_security_a = 1;
841 hm_advapi32 = LoadLibrary ("Advapi32.dll");
842 s_pfn_Set_File_SecurityA =
843 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
844 "SetFileSecurityA");
846 if (s_pfn_Set_File_SecurityA == NULL)
848 errno = ENOTSUP;
849 return FALSE;
851 filename_to_ansi (lpFileName, filename_a);
852 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
853 pSecurityDescriptor));
857 static DWORD WINAPI
858 set_named_security_info (LPCTSTR lpObjectName,
859 SE_OBJECT_TYPE ObjectType,
860 SECURITY_INFORMATION SecurityInformation,
861 PSID psidOwner,
862 PSID psidGroup,
863 PACL pDacl,
864 PACL pSacl)
866 static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
867 static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
868 HMODULE hm_advapi32 = NULL;
869 if (is_windows_9x () == TRUE)
871 errno = ENOTSUP;
872 return ENOTSUP;
874 if (w32_unicode_filenames)
876 wchar_t filename_w[MAX_PATH];
878 if (g_b_init_set_named_security_info_w == 0)
880 g_b_init_set_named_security_info_w = 1;
881 hm_advapi32 = LoadLibrary ("Advapi32.dll");
882 s_pfn_Set_Named_Security_InfoW =
883 (SetNamedSecurityInfoW_Proc) GetProcAddress (hm_advapi32,
884 "SetNamedSecurityInfoW");
886 if (s_pfn_Set_Named_Security_InfoW == NULL)
888 errno = ENOTSUP;
889 return ENOTSUP;
891 filename_to_utf16 (lpObjectName, filename_w);
892 return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
893 SecurityInformation, psidOwner,
894 psidGroup, pDacl, pSacl));
896 else
898 char filename_a[MAX_PATH];
900 if (g_b_init_set_named_security_info_a == 0)
902 g_b_init_set_named_security_info_a = 1;
903 hm_advapi32 = LoadLibrary ("Advapi32.dll");
904 s_pfn_Set_Named_Security_InfoA =
905 (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
906 "SetNamedSecurityInfoA");
908 if (s_pfn_Set_Named_Security_InfoA == NULL)
910 errno = ENOTSUP;
911 return ENOTSUP;
913 filename_to_ansi (lpObjectName, filename_a);
914 return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
915 SecurityInformation, psidOwner,
916 psidGroup, pDacl, pSacl));
920 static BOOL WINAPI
921 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
922 PSID *pOwner,
923 LPBOOL lpbOwnerDefaulted)
925 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
926 HMODULE hm_advapi32 = NULL;
927 if (is_windows_9x () == TRUE)
929 errno = ENOTSUP;
930 return FALSE;
932 if (g_b_init_get_security_descriptor_owner == 0)
934 g_b_init_get_security_descriptor_owner = 1;
935 hm_advapi32 = LoadLibrary ("Advapi32.dll");
936 s_pfn_Get_Security_Descriptor_Owner =
937 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
938 hm_advapi32, "GetSecurityDescriptorOwner");
940 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
942 errno = ENOTSUP;
943 return FALSE;
945 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
946 lpbOwnerDefaulted));
949 static BOOL WINAPI
950 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
951 PSID *pGroup,
952 LPBOOL lpbGroupDefaulted)
954 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
955 HMODULE hm_advapi32 = NULL;
956 if (is_windows_9x () == TRUE)
958 errno = ENOTSUP;
959 return FALSE;
961 if (g_b_init_get_security_descriptor_group == 0)
963 g_b_init_get_security_descriptor_group = 1;
964 hm_advapi32 = LoadLibrary ("Advapi32.dll");
965 s_pfn_Get_Security_Descriptor_Group =
966 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
967 hm_advapi32, "GetSecurityDescriptorGroup");
969 if (s_pfn_Get_Security_Descriptor_Group == NULL)
971 errno = ENOTSUP;
972 return FALSE;
974 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
975 lpbGroupDefaulted));
978 static BOOL WINAPI
979 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
980 LPBOOL lpbDaclPresent,
981 PACL *pDacl,
982 LPBOOL lpbDaclDefaulted)
984 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
985 HMODULE hm_advapi32 = NULL;
986 if (is_windows_9x () == TRUE)
988 errno = ENOTSUP;
989 return FALSE;
991 if (g_b_init_get_security_descriptor_dacl == 0)
993 g_b_init_get_security_descriptor_dacl = 1;
994 hm_advapi32 = LoadLibrary ("Advapi32.dll");
995 s_pfn_Get_Security_Descriptor_Dacl =
996 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
997 hm_advapi32, "GetSecurityDescriptorDacl");
999 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
1001 errno = ENOTSUP;
1002 return FALSE;
1004 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
1005 lpbDaclPresent, pDacl,
1006 lpbDaclDefaulted));
1009 static BOOL WINAPI
1010 is_valid_sid (PSID sid)
1012 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
1013 HMODULE hm_advapi32 = NULL;
1014 if (is_windows_9x () == TRUE)
1016 return FALSE;
1018 if (g_b_init_is_valid_sid == 0)
1020 g_b_init_is_valid_sid = 1;
1021 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1022 s_pfn_Is_Valid_Sid =
1023 (IsValidSid_Proc) GetProcAddress (
1024 hm_advapi32, "IsValidSid");
1026 if (s_pfn_Is_Valid_Sid == NULL)
1028 return FALSE;
1030 return (s_pfn_Is_Valid_Sid (sid));
1033 static BOOL WINAPI
1034 equal_sid (PSID sid1, PSID sid2)
1036 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
1037 HMODULE hm_advapi32 = NULL;
1038 if (is_windows_9x () == TRUE)
1040 return FALSE;
1042 if (g_b_init_equal_sid == 0)
1044 g_b_init_equal_sid = 1;
1045 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1046 s_pfn_Equal_Sid =
1047 (EqualSid_Proc) GetProcAddress (
1048 hm_advapi32, "EqualSid");
1050 if (s_pfn_Equal_Sid == NULL)
1052 return FALSE;
1054 return (s_pfn_Equal_Sid (sid1, sid2));
1057 static DWORD WINAPI
1058 get_length_sid (PSID sid)
1060 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
1061 HMODULE hm_advapi32 = NULL;
1062 if (is_windows_9x () == TRUE)
1064 return 0;
1066 if (g_b_init_get_length_sid == 0)
1068 g_b_init_get_length_sid = 1;
1069 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1070 s_pfn_Get_Length_Sid =
1071 (GetLengthSid_Proc) GetProcAddress (
1072 hm_advapi32, "GetLengthSid");
1074 if (s_pfn_Get_Length_Sid == NULL)
1076 return 0;
1078 return (s_pfn_Get_Length_Sid (sid));
1081 static BOOL WINAPI
1082 copy_sid (DWORD destlen, PSID dest, PSID src)
1084 static CopySid_Proc s_pfn_Copy_Sid = NULL;
1085 HMODULE hm_advapi32 = NULL;
1086 if (is_windows_9x () == TRUE)
1088 return FALSE;
1090 if (g_b_init_copy_sid == 0)
1092 g_b_init_copy_sid = 1;
1093 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1094 s_pfn_Copy_Sid =
1095 (CopySid_Proc) GetProcAddress (
1096 hm_advapi32, "CopySid");
1098 if (s_pfn_Copy_Sid == NULL)
1100 return FALSE;
1102 return (s_pfn_Copy_Sid (destlen, dest, src));
1106 END: Wrapper functions around OpenProcessToken
1107 and other functions in advapi32.dll that are only
1108 supported in Windows NT / 2k / XP
1111 static void WINAPI
1112 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1114 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1115 if (is_windows_9x () != TRUE)
1117 if (g_b_init_get_native_system_info == 0)
1119 g_b_init_get_native_system_info = 1;
1120 s_pfn_Get_Native_System_Info =
1121 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1122 "GetNativeSystemInfo");
1124 if (s_pfn_Get_Native_System_Info != NULL)
1125 s_pfn_Get_Native_System_Info (lpSystemInfo);
1127 else
1128 lpSystemInfo->dwNumberOfProcessors = -1;
1131 static BOOL WINAPI
1132 get_system_times (LPFILETIME lpIdleTime,
1133 LPFILETIME lpKernelTime,
1134 LPFILETIME lpUserTime)
1136 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1137 if (is_windows_9x () == TRUE)
1139 return FALSE;
1141 if (g_b_init_get_system_times == 0)
1143 g_b_init_get_system_times = 1;
1144 s_pfn_Get_System_times =
1145 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1146 "GetSystemTimes");
1148 if (s_pfn_Get_System_times == NULL)
1149 return FALSE;
1150 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1153 static BOOLEAN WINAPI
1154 create_symbolic_link (LPCSTR lpSymlinkFilename,
1155 LPCSTR lpTargetFileName,
1156 DWORD dwFlags)
1158 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1159 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1160 BOOLEAN retval;
1162 if (is_windows_9x () == TRUE)
1164 errno = ENOSYS;
1165 return 0;
1167 if (w32_unicode_filenames)
1169 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1171 if (g_b_init_create_symbolic_link_w == 0)
1173 g_b_init_create_symbolic_link_w = 1;
1174 s_pfn_Create_Symbolic_LinkW =
1175 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1176 "CreateSymbolicLinkW");
1178 if (s_pfn_Create_Symbolic_LinkW == NULL)
1180 errno = ENOSYS;
1181 return 0;
1184 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1185 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1186 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1187 /* If we were denied creation of the symlink, try again after
1188 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1189 if (!retval)
1191 TOKEN_PRIVILEGES priv_current;
1193 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1194 &priv_current))
1196 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1197 restore_privilege (&priv_current);
1198 revert_to_self ();
1202 else
1204 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1206 if (g_b_init_create_symbolic_link_a == 0)
1208 g_b_init_create_symbolic_link_a = 1;
1209 s_pfn_Create_Symbolic_LinkA =
1210 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1211 "CreateSymbolicLinkA");
1213 if (s_pfn_Create_Symbolic_LinkA == NULL)
1215 errno = ENOSYS;
1216 return 0;
1219 filename_to_ansi (lpSymlinkFilename, symfn_a);
1220 filename_to_ansi (lpTargetFileName, tgtfn_a);
1221 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1222 /* If we were denied creation of the symlink, try again after
1223 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1224 if (!retval)
1226 TOKEN_PRIVILEGES priv_current;
1228 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1229 &priv_current))
1231 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1232 restore_privilege (&priv_current);
1233 revert_to_self ();
1237 return retval;
1240 static BOOL WINAPI
1241 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1243 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1245 if (is_windows_9x () == TRUE)
1247 errno = ENOTSUP;
1248 return FALSE;
1251 if (g_b_init_is_valid_security_descriptor == 0)
1253 g_b_init_is_valid_security_descriptor = 1;
1254 s_pfn_Is_Valid_Security_Descriptor_Proc =
1255 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1256 "IsValidSecurityDescriptor");
1258 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1260 errno = ENOTSUP;
1261 return FALSE;
1264 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1267 static BOOL WINAPI
1268 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1269 DWORD RequestedStringSDRevision,
1270 SECURITY_INFORMATION SecurityInformation,
1271 LPTSTR *StringSecurityDescriptor,
1272 PULONG StringSecurityDescriptorLen)
1274 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1275 BOOL retval;
1277 if (is_windows_9x () == TRUE)
1279 errno = ENOTSUP;
1280 return FALSE;
1283 if (g_b_init_convert_sd_to_sddl == 0)
1285 g_b_init_convert_sd_to_sddl = 1;
1286 #ifdef _UNICODE
1287 s_pfn_Convert_SD_To_SDDL =
1288 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1289 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1290 #else
1291 s_pfn_Convert_SD_To_SDDL =
1292 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1293 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1294 #endif
1296 if (s_pfn_Convert_SD_To_SDDL == NULL)
1298 errno = ENOTSUP;
1299 return FALSE;
1302 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1303 RequestedStringSDRevision,
1304 SecurityInformation,
1305 StringSecurityDescriptor,
1306 StringSecurityDescriptorLen);
1308 return retval;
1311 static BOOL WINAPI
1312 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1313 DWORD StringSDRevision,
1314 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1315 PULONG SecurityDescriptorSize)
1317 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1318 BOOL retval;
1320 if (is_windows_9x () == TRUE)
1322 errno = ENOTSUP;
1323 return FALSE;
1326 if (g_b_init_convert_sddl_to_sd == 0)
1328 g_b_init_convert_sddl_to_sd = 1;
1329 #ifdef _UNICODE
1330 s_pfn_Convert_SDDL_To_SD =
1331 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1332 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1333 #else
1334 s_pfn_Convert_SDDL_To_SD =
1335 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1336 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1337 #endif
1339 if (s_pfn_Convert_SDDL_To_SD == NULL)
1341 errno = ENOTSUP;
1342 return FALSE;
1345 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1346 StringSDRevision,
1347 SecurityDescriptor,
1348 SecurityDescriptorSize);
1350 return retval;
1353 static DWORD WINAPI
1354 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1356 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1357 HMODULE hm_iphlpapi = NULL;
1359 if (is_windows_9x () == TRUE)
1360 return ERROR_NOT_SUPPORTED;
1362 if (g_b_init_get_adapters_info == 0)
1364 g_b_init_get_adapters_info = 1;
1365 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1366 if (hm_iphlpapi)
1367 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1368 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1370 if (s_pfn_Get_Adapters_Info == NULL)
1371 return ERROR_NOT_SUPPORTED;
1372 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1377 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1378 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1380 This is called from alloc.c:valid_pointer_p. */
1382 w32_valid_pointer_p (void *p, int size)
1384 SIZE_T done;
1385 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1387 if (h)
1389 unsigned char *buf = alloca (size);
1390 int retval = ReadProcessMemory (h, p, buf, size, &done);
1392 CloseHandle (h);
1393 return retval;
1395 else
1396 return -1;
1401 /* Here's an overview of how the Windows build supports file names
1402 that cannot be encoded by the current system codepage.
1404 From the POV of Lisp and layers of C code above the functions here,
1405 Emacs on Windows pretends that its file names are encoded in UTF-8;
1406 see encode_file and decode_file on coding.c. Any file name that is
1407 passed as a unibyte string to C functions defined here is assumed
1408 to be in UTF-8 encoding. Any file name returned by functions
1409 defined here must be in UTF-8 encoding, with only a few exceptions
1410 reserved for a couple of special cases. (Be sure to use
1411 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1412 as they can be much longer than MAX_PATH!)
1414 The UTF-8 encoded file names cannot be passed to system APIs, as
1415 Windows does not support that. Therefore, they are converted
1416 either to UTF-16 or to the ANSI codepage, depending on the value of
1417 w32-unicode-filenames, before calling any system APIs or CRT library
1418 functions. The default value of that variable is determined by the
1419 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1420 user can change that default (although I don't see why would she
1421 want to).
1423 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1424 filename_from_utf16, and filename_from_ansi, are the workhorses of
1425 these conversions. They rely on Windows native APIs
1426 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1427 functions from coding.c here, because they allocate memory, which
1428 is a bad idea on the level of libc, which is what the functions
1429 here emulate. (If you worry about performance due to constant
1430 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1431 it was measured to take only a few microseconds on a not-so-fast
1432 machine, and second, that's exactly what the ANSI APIs we used
1433 before did anyway, because they are just thin wrappers around the
1434 Unicode APIs.)
1436 The variables file-name-coding-system and default-file-name-coding-system
1437 still exist, but are actually used only when a file name needs to
1438 be converted to the ANSI codepage. This happens all the time when
1439 w32-unicode-filenames is nil, but can also happen from time to time
1440 when it is t. Otherwise, these variables have no effect on file-name
1441 encoding when w32-unicode-filenames is t; this is similar to
1442 selection-coding-system.
1444 This arrangement works very well, but it has a few gotchas and
1445 limitations:
1447 . Lisp code that encodes or decodes file names manually should
1448 normally use 'utf-8' as the coding-system on Windows,
1449 disregarding file-name-coding-system. This is a somewhat
1450 unpleasant consequence, but it cannot be avoided. Fortunately,
1451 very few Lisp packages need to do that.
1453 More generally, passing to library functions (e.g., fopen or
1454 opendir) file names already encoded in the ANSI codepage is
1455 explicitly *verboten*, as all those functions, as shadowed and
1456 emulated here, assume they will receive UTF-8 encoded file names.
1458 For the same reasons, no CRT function or Win32 API can be called
1459 directly in Emacs sources, without either converting the file
1460 names from UTF-8 to UTF-16 or ANSI codepage, or going through
1461 some shadowing function defined here.
1463 . Environment variables stored in Vprocess_environment are encoded
1464 in the ANSI codepage, so if getenv/egetenv is used for a variable
1465 whose value is a file name or a list of directories, it needs to
1466 be converted to UTF-8, before it is used as argument to functions
1467 or decoded into a Lisp string.
1469 . File names passed to external libraries, like the image libraries
1470 and GnuTLS, need special handling. These libraries generally
1471 don't support UTF-16 or UTF-8 file names, so they must get file
1472 names encoded in the ANSI codepage. To facilitate using these
1473 libraries with file names that are not encodable in the ANSI
1474 codepage, use the function ansi_encode_filename, which will try
1475 to use the short 8+3 alias of a file name if that file name is
1476 not encodable in the ANSI codepage. See image.c and gnutls.c for
1477 examples of how this should be done.
1479 . Running subprocesses in non-ASCII directories and with non-ASCII
1480 file arguments is limited to the current codepage (even though
1481 Emacs is perfectly capable of finding an executable program file
1482 in a directory whose name cannot be encoded in the current
1483 codepage). This is because the command-line arguments are
1484 encoded _before_ they get to the w32-specific level, and the
1485 encoding is not known in advance (it doesn't have to be the
1486 current ANSI codepage), so w32proc.c functions cannot re-encode
1487 them in UTF-16. This should be fixed, but will also require
1488 changes in cmdproxy. The current limitation is not terribly bad
1489 anyway, since very few, if any, Windows console programs that are
1490 likely to be invoked by Emacs support UTF-16 encoded command
1491 lines.
1493 . For similar reasons, server.el and emacsclient are also limited
1494 to the current ANSI codepage for now.
1496 . Emacs itself can only handle command-line arguments encoded in
1497 the current codepage.
1499 . Turning on w32-unicode-filename on Windows 9X (if it at all
1500 works) requires UNICOWS.DLL, which is thus a requirement even in
1501 non-GUI sessions, something that we previously avoided. */
1505 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1506 codepage defined by file-name-coding-system. */
1508 /* Current codepage for encoding file names. */
1509 static int file_name_codepage;
1511 /* Initialize the codepage used for decoding file names. This is
1512 needed to undo the value recorded during dumping, which might not
1513 be correct when we run the dumped Emacs. */
1514 void
1515 w32_init_file_name_codepage (void)
1517 file_name_codepage = CP_ACP;
1518 w32_ansi_code_page = CP_ACP;
1521 /* Produce a Windows ANSI codepage suitable for encoding file names.
1522 Return the information about that codepage in CP_INFO. */
1524 codepage_for_filenames (CPINFO *cp_info)
1526 /* A simple cache to avoid calling GetCPInfo every time we need to
1527 encode/decode a file name. The file-name encoding is not
1528 supposed to be changed too frequently, if ever. */
1529 static Lisp_Object last_file_name_encoding;
1530 static CPINFO cp;
1531 Lisp_Object current_encoding;
1533 current_encoding = Vfile_name_coding_system;
1534 if (NILP (current_encoding))
1535 current_encoding = Vdefault_file_name_coding_system;
1537 if (!EQ (last_file_name_encoding, current_encoding)
1538 || NILP (last_file_name_encoding))
1540 /* Default to the current ANSI codepage. */
1541 file_name_codepage = w32_ansi_code_page;
1543 if (!NILP (current_encoding))
1545 char *cpname = SSDATA (SYMBOL_NAME (current_encoding));
1546 char *cp = NULL, *end;
1547 int cpnum;
1549 if (strncmp (cpname, "cp", 2) == 0)
1550 cp = cpname + 2;
1551 else if (strncmp (cpname, "windows-", 8) == 0)
1552 cp = cpname + 8;
1554 if (cp)
1556 end = cp;
1557 cpnum = strtol (cp, &end, 10);
1558 if (cpnum && *end == '\0' && end - cp >= 2)
1559 file_name_codepage = cpnum;
1563 if (!file_name_codepage)
1564 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1566 if (!GetCPInfo (file_name_codepage, &cp))
1568 file_name_codepage = CP_ACP;
1569 if (!GetCPInfo (file_name_codepage, &cp))
1570 emacs_abort ();
1573 /* Cache the new value. */
1574 last_file_name_encoding = current_encoding;
1576 if (cp_info)
1577 *cp_info = cp;
1579 return file_name_codepage;
1583 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1585 int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
1586 -1, fn_out, MAX_PATH);
1588 if (!result)
1590 DWORD err = GetLastError ();
1592 switch (err)
1594 case ERROR_INVALID_FLAGS:
1595 case ERROR_INVALID_PARAMETER:
1596 errno = EINVAL;
1597 break;
1598 case ERROR_INSUFFICIENT_BUFFER:
1599 case ERROR_NO_UNICODE_TRANSLATION:
1600 default:
1601 errno = ENOENT;
1602 break;
1604 return -1;
1606 return 0;
1610 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1612 int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1613 fn_out, MAX_UTF8_PATH, NULL, NULL);
1615 if (!result)
1617 DWORD err = GetLastError ();
1619 switch (err)
1621 case ERROR_INVALID_FLAGS:
1622 case ERROR_INVALID_PARAMETER:
1623 errno = EINVAL;
1624 break;
1625 case ERROR_INSUFFICIENT_BUFFER:
1626 case ERROR_NO_UNICODE_TRANSLATION:
1627 default:
1628 errno = ENOENT;
1629 break;
1631 return -1;
1633 return 0;
1637 filename_to_ansi (const char *fn_in, char *fn_out)
1639 wchar_t fn_utf16[MAX_PATH];
1641 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1643 int result;
1644 int codepage = codepage_for_filenames (NULL);
1646 result = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
1647 fn_out, MAX_PATH, NULL, NULL);
1648 if (!result)
1650 DWORD err = GetLastError ();
1652 switch (err)
1654 case ERROR_INVALID_FLAGS:
1655 case ERROR_INVALID_PARAMETER:
1656 errno = EINVAL;
1657 break;
1658 case ERROR_INSUFFICIENT_BUFFER:
1659 case ERROR_NO_UNICODE_TRANSLATION:
1660 default:
1661 errno = ENOENT;
1662 break;
1664 return -1;
1666 return 0;
1668 return -1;
1672 filename_from_ansi (const char *fn_in, char *fn_out)
1674 wchar_t fn_utf16[MAX_PATH];
1675 int codepage = codepage_for_filenames (NULL);
1676 int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
1677 -1, fn_utf16, MAX_PATH);
1679 if (!result)
1681 DWORD err = GetLastError ();
1683 switch (err)
1685 case ERROR_INVALID_FLAGS:
1686 case ERROR_INVALID_PARAMETER:
1687 errno = EINVAL;
1688 break;
1689 case ERROR_INSUFFICIENT_BUFFER:
1690 case ERROR_NO_UNICODE_TRANSLATION:
1691 default:
1692 errno = ENOENT;
1693 break;
1695 return -1;
1697 return filename_from_utf16 (fn_utf16, fn_out);
1702 /* The directory where we started, in UTF-8. */
1703 static char startup_dir[MAX_UTF8_PATH];
1705 /* Get the current working directory. */
1706 char *
1707 getcwd (char *dir, int dirsize)
1709 if (!dirsize)
1711 errno = EINVAL;
1712 return NULL;
1714 if (dirsize <= strlen (startup_dir))
1716 errno = ERANGE;
1717 return NULL;
1719 #if 0
1720 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1721 return dir;
1722 return NULL;
1723 #else
1724 /* Emacs doesn't actually change directory itself, it stays in the
1725 same directory where it was started. */
1726 strcpy (dir, startup_dir);
1727 return dir;
1728 #endif
1731 /* Emulate getloadavg. */
1733 struct load_sample {
1734 time_t sample_time;
1735 ULONGLONG idle;
1736 ULONGLONG kernel;
1737 ULONGLONG user;
1740 /* Number of processors on this machine. */
1741 static unsigned num_of_processors;
1743 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1744 static struct load_sample samples[16*60];
1745 static int first_idx = -1, last_idx = -1;
1746 static int max_idx = ARRAYELTS (samples);
1748 static int
1749 buf_next (int from)
1751 int next_idx = from + 1;
1753 if (next_idx >= max_idx)
1754 next_idx = 0;
1756 return next_idx;
1759 static int
1760 buf_prev (int from)
1762 int prev_idx = from - 1;
1764 if (prev_idx < 0)
1765 prev_idx = max_idx - 1;
1767 return prev_idx;
1770 static void
1771 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1773 SYSTEM_INFO sysinfo;
1774 FILETIME ft_idle, ft_user, ft_kernel;
1776 /* Initialize the number of processors on this machine. */
1777 if (num_of_processors <= 0)
1779 get_native_system_info (&sysinfo);
1780 num_of_processors = sysinfo.dwNumberOfProcessors;
1781 if (num_of_processors <= 0)
1783 GetSystemInfo (&sysinfo);
1784 num_of_processors = sysinfo.dwNumberOfProcessors;
1786 if (num_of_processors <= 0)
1787 num_of_processors = 1;
1790 /* TODO: Take into account threads that are ready to run, by
1791 sampling the "\System\Processor Queue Length" performance
1792 counter. The code below accounts only for threads that are
1793 actually running. */
1795 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1797 ULARGE_INTEGER uidle, ukernel, uuser;
1799 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1800 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1801 memcpy (&uuser, &ft_user, sizeof (ft_user));
1802 *idle = uidle.QuadPart;
1803 *kernel = ukernel.QuadPart;
1804 *user = uuser.QuadPart;
1806 else
1808 *idle = 0;
1809 *kernel = 0;
1810 *user = 0;
1814 /* Produce the load average for a given time interval, using the
1815 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1816 1-minute, 5-minute, or 15-minute average, respectively. */
1817 static double
1818 getavg (int which)
1820 double retval = -1.0;
1821 double tdiff;
1822 int idx;
1823 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1824 time_t now = samples[last_idx].sample_time;
1826 if (first_idx != last_idx)
1828 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1830 tdiff = difftime (now, samples[idx].sample_time);
1831 if (tdiff >= span - 2*DBL_EPSILON*now)
1833 long double sys =
1834 samples[last_idx].kernel + samples[last_idx].user
1835 - (samples[idx].kernel + samples[idx].user);
1836 long double idl = samples[last_idx].idle - samples[idx].idle;
1838 retval = (1.0 - idl / sys) * num_of_processors;
1839 break;
1841 if (idx == first_idx)
1842 break;
1846 return retval;
1850 getloadavg (double loadavg[], int nelem)
1852 int elem;
1853 ULONGLONG idle, kernel, user;
1854 time_t now = time (NULL);
1856 /* If system time jumped back for some reason, delete all samples
1857 whose time is later than the current wall-clock time. This
1858 prevents load average figures from becoming frozen for prolonged
1859 periods of time, when system time is reset backwards. */
1860 if (last_idx >= 0)
1862 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1864 if (last_idx == first_idx)
1866 first_idx = last_idx = -1;
1867 break;
1869 last_idx = buf_prev (last_idx);
1873 /* Store another sample. We ignore samples that are less than 1 sec
1874 apart. */
1875 if (last_idx < 0
1876 || (difftime (now, samples[last_idx].sample_time)
1877 >= 1.0 - 2*DBL_EPSILON*now))
1879 sample_system_load (&idle, &kernel, &user);
1880 last_idx = buf_next (last_idx);
1881 samples[last_idx].sample_time = now;
1882 samples[last_idx].idle = idle;
1883 samples[last_idx].kernel = kernel;
1884 samples[last_idx].user = user;
1885 /* If the buffer has more that 15 min worth of samples, discard
1886 the old ones. */
1887 if (first_idx == -1)
1888 first_idx = last_idx;
1889 while (first_idx != last_idx
1890 && (difftime (now, samples[first_idx].sample_time)
1891 >= 15.0*60 + 2*DBL_EPSILON*now))
1892 first_idx = buf_next (first_idx);
1895 for (elem = 0; elem < nelem; elem++)
1897 double avg = getavg (elem);
1899 if (avg < 0)
1900 break;
1901 loadavg[elem] = avg;
1904 return elem;
1907 /* Emulate getpwuid, getpwnam and others. */
1909 #define PASSWD_FIELD_SIZE 256
1911 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1912 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1913 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1914 static char dflt_passwd_dir[MAX_UTF8_PATH];
1915 static char dflt_passwd_shell[MAX_UTF8_PATH];
1917 static struct passwd dflt_passwd =
1919 dflt_passwd_name,
1920 dflt_passwd_passwd,
1924 dflt_passwd_gecos,
1925 dflt_passwd_dir,
1926 dflt_passwd_shell,
1929 static char dflt_group_name[GNLEN+1];
1931 static struct group dflt_group =
1933 /* When group information is not available, we return this as the
1934 group for all files. */
1935 dflt_group_name,
1939 unsigned
1940 getuid (void)
1942 return dflt_passwd.pw_uid;
1945 unsigned
1946 geteuid (void)
1948 /* I could imagine arguing for checking to see whether the user is
1949 in the Administrators group and returning a UID of 0 for that
1950 case, but I don't know how wise that would be in the long run. */
1951 return getuid ();
1954 unsigned
1955 getgid (void)
1957 return dflt_passwd.pw_gid;
1960 unsigned
1961 getegid (void)
1963 return getgid ();
1966 struct passwd *
1967 getpwuid (unsigned uid)
1969 if (uid == dflt_passwd.pw_uid)
1970 return &dflt_passwd;
1971 return NULL;
1974 struct group *
1975 getgrgid (gid_t gid)
1977 return &dflt_group;
1980 struct passwd *
1981 getpwnam (char *name)
1983 struct passwd *pw;
1985 pw = getpwuid (getuid ());
1986 if (!pw)
1987 return pw;
1989 if (xstrcasecmp (name, pw->pw_name))
1990 return NULL;
1992 return pw;
1995 static void
1996 init_user_info (void)
1998 /* Find the user's real name by opening the process token and
1999 looking up the name associated with the user-sid in that token.
2001 Use the relative portion of the identifier authority value from
2002 the user-sid as the user id value (same for group id using the
2003 primary group sid from the process token). */
2005 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
2006 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
2007 DWORD glength = sizeof (gname);
2008 HANDLE token = NULL;
2009 SID_NAME_USE user_type;
2010 unsigned char *buf = NULL;
2011 DWORD blen = 0;
2012 TOKEN_USER user_token;
2013 TOKEN_PRIMARY_GROUP group_token;
2014 BOOL result;
2016 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
2017 if (result)
2019 result = get_token_information (token, TokenUser, NULL, 0, &blen);
2020 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2022 buf = xmalloc (blen);
2023 result = get_token_information (token, TokenUser,
2024 (LPVOID)buf, blen, &needed);
2025 if (result)
2027 memcpy (&user_token, buf, sizeof (user_token));
2028 result = lookup_account_sid (NULL, user_token.User.Sid,
2029 uname, &ulength,
2030 domain, &dlength, &user_type);
2033 else
2034 result = FALSE;
2036 if (result)
2038 strcpy (dflt_passwd.pw_name, uname);
2039 /* Determine a reasonable uid value. */
2040 if (xstrcasecmp ("administrator", uname) == 0)
2042 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
2043 dflt_passwd.pw_gid = 513; /* well-known None gid */
2045 else
2047 /* Use the last sub-authority value of the RID, the relative
2048 portion of the SID, as user/group ID. */
2049 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
2051 /* Get group id and name. */
2052 result = get_token_information (token, TokenPrimaryGroup,
2053 (LPVOID)buf, blen, &needed);
2054 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2056 buf = xrealloc (buf, blen = needed);
2057 result = get_token_information (token, TokenPrimaryGroup,
2058 (LPVOID)buf, blen, &needed);
2060 if (result)
2062 memcpy (&group_token, buf, sizeof (group_token));
2063 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
2064 dlength = sizeof (domain);
2065 /* If we can get at the real Primary Group name, use that.
2066 Otherwise, the default group name was already set to
2067 "None" in globals_of_w32. */
2068 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
2069 gname, &glength, NULL, &dlength,
2070 &user_type))
2071 strcpy (dflt_group_name, gname);
2073 else
2074 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2077 /* If security calls are not supported (presumably because we
2078 are running under Windows 9X), fallback to this: */
2079 else if (GetUserName (uname, &ulength))
2081 strcpy (dflt_passwd.pw_name, uname);
2082 if (xstrcasecmp ("administrator", uname) == 0)
2083 dflt_passwd.pw_uid = 0;
2084 else
2085 dflt_passwd.pw_uid = 123;
2086 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2088 else
2090 strcpy (dflt_passwd.pw_name, "unknown");
2091 dflt_passwd.pw_uid = 123;
2092 dflt_passwd.pw_gid = 123;
2094 dflt_group.gr_gid = dflt_passwd.pw_gid;
2096 /* Set dir and shell from environment variables. */
2097 if (w32_unicode_filenames)
2099 wchar_t *home = _wgetenv (L"HOME");
2100 wchar_t *shell = _wgetenv (L"SHELL");
2102 /* Ensure HOME and SHELL are defined. */
2103 if (home == NULL)
2104 emacs_abort ();
2105 if (shell == NULL)
2106 emacs_abort ();
2107 filename_from_utf16 (home, dflt_passwd.pw_dir);
2108 filename_from_utf16 (shell, dflt_passwd.pw_shell);
2110 else
2112 char *home = getenv ("HOME");
2113 char *shell = getenv ("SHELL");
2115 if (home == NULL)
2116 emacs_abort ();
2117 if (shell == NULL)
2118 emacs_abort ();
2119 filename_from_ansi (home, dflt_passwd.pw_dir);
2120 filename_from_ansi (shell, dflt_passwd.pw_shell);
2123 xfree (buf);
2124 if (token)
2125 CloseHandle (token);
2128 static HCRYPTPROV w32_crypto_hprov;
2129 static int
2130 w32_init_crypt_random (void)
2132 if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL,
2133 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2135 DebPrint (("CryptAcquireContext failed with error %x\n",
2136 GetLastError ()));
2137 w32_crypto_hprov = 0;
2138 return -1;
2140 return 0;
2144 w32_init_random (void *buf, ptrdiff_t buflen)
2146 if (!w32_crypto_hprov)
2147 w32_init_crypt_random ();
2148 if (w32_crypto_hprov)
2150 if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf))
2151 return 0;
2153 return -1;
2156 /* MS-Windows 'rand' produces separate identical series for each
2157 thread, so we replace it with our version. */
2159 /* Algorithm AS183: An Efficient and Portable Pseudo-random Number
2160 Generator, by B.A. Wichmann, I.D. Hill. AS, v31, No. 2 (1982). */
2161 static int ix = 3172, iy = 9814, iz = 20125;
2162 #define RAND_MAX_X 30269
2163 #define RAND_MAX_Y 30307
2164 #define RAND_MAX_Z 30323
2166 static int
2167 rand_as183 (void)
2169 ix = (171 * ix) % RAND_MAX_X;
2170 iy = (172 * iy) % RAND_MAX_Y;
2171 iz = (170 * iz) % RAND_MAX_Z;
2173 return (ix + iy + iz) & 0x7fff;
2177 random (void)
2179 /* rand_as183 () gives us 15 random bits...hack together 30 bits. */
2180 return ((rand_as183 () << 15) | rand_as183 ());
2183 void
2184 srandom (int seed)
2186 srand (seed);
2187 ix = rand () % RAND_MAX_X;
2188 iy = rand () % RAND_MAX_Y;
2189 iz = rand () % RAND_MAX_Z;
2192 /* Return the maximum length in bytes of a multibyte character
2193 sequence encoded in the current ANSI codepage. This is required to
2194 correctly walk the encoded file names one character at a time. */
2195 static int
2196 max_filename_mbslen (void)
2198 CPINFO cp_info;
2200 codepage_for_filenames (&cp_info);
2201 return cp_info.MaxCharSize;
2204 /* Normalize filename by converting in-place all of its path
2205 separators to the separator specified by PATH_SEP. */
2207 static void
2208 normalize_filename (register char *fp, char path_sep)
2210 char *p2;
2212 /* Always lower-case drive letters a-z, even if the filesystem
2213 preserves case in filenames.
2214 This is so filenames can be compared by string comparison
2215 functions that are case-sensitive. Even case-preserving filesystems
2216 do not distinguish case in drive letters. */
2217 p2 = fp + 1;
2219 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2221 *fp += 'a' - 'A';
2222 fp += 2;
2225 while (*fp)
2227 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2228 *fp = path_sep;
2229 fp++;
2233 /* Destructively turn backslashes into slashes. */
2234 void
2235 dostounix_filename (register char *p)
2237 normalize_filename (p, '/');
2240 /* Destructively turn slashes into backslashes. */
2241 void
2242 unixtodos_filename (register char *p)
2244 normalize_filename (p, '\\');
2247 /* Remove all CR's that are followed by a LF.
2248 (From msdos.c...probably should figure out a way to share it,
2249 although this code isn't going to ever change.) */
2250 static int
2251 crlf_to_lf (register int n, register char *buf)
2253 unsigned char *np = (unsigned char *)buf;
2254 unsigned char *startp = np;
2255 char *endp = buf + n;
2257 if (n == 0)
2258 return n;
2259 while (buf < endp - 1)
2261 if (*buf == 0x0d)
2263 if (*(++buf) != 0x0a)
2264 *np++ = 0x0d;
2266 else
2267 *np++ = *buf++;
2269 if (buf < endp)
2270 *np++ = *buf++;
2271 return np - startp;
2274 /* Parse the root part of file name, if present. Return length and
2275 optionally store pointer to char after root. */
2276 static int
2277 parse_root (const char * name, const char ** pPath)
2279 const char * start = name;
2281 if (name == NULL)
2282 return 0;
2284 /* find the root name of the volume if given */
2285 if (isalpha (name[0]) && name[1] == ':')
2287 /* skip past drive specifier */
2288 name += 2;
2289 if (IS_DIRECTORY_SEP (name[0]))
2290 name++;
2292 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2294 int slashes = 2;
2296 name += 2;
2299 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2300 break;
2301 name++;
2303 while ( *name );
2304 if (IS_DIRECTORY_SEP (name[0]))
2305 name++;
2308 if (pPath)
2309 *pPath = name;
2311 return name - start;
2314 /* Get long base name for name; name is assumed to be absolute. */
2315 static int
2316 get_long_basename (char * name, char * buf, int size)
2318 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2319 char fname_utf8[MAX_UTF8_PATH];
2320 int len = 0;
2321 int cstatus = -1;
2323 /* Must be valid filename, no wild cards or other invalid characters. */
2324 if (strpbrk (name, "*?|<>\""))
2325 return 0;
2327 if (w32_unicode_filenames)
2329 wchar_t fname_utf16[MAX_PATH];
2330 WIN32_FIND_DATAW find_data_wide;
2332 filename_to_utf16 (name, fname_utf16);
2333 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2334 if (dir_handle != INVALID_HANDLE_VALUE)
2335 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2337 else
2339 char fname_ansi[MAX_PATH];
2340 WIN32_FIND_DATAA find_data_ansi;
2342 filename_to_ansi (name, fname_ansi);
2343 /* If the ANSI name includes ? characters, it is not encodable
2344 in the ANSI codepage. In that case, we deliver the question
2345 marks to the caller; calling FindFirstFileA in this case
2346 could return some unrelated file name in the same
2347 directory. */
2348 if (_mbspbrk (fname_ansi, "?"))
2350 /* Find the basename of fname_ansi. */
2351 char *p = strrchr (fname_ansi, '\\');
2353 if (!p)
2354 p = fname_ansi;
2355 else
2356 p++;
2357 cstatus = filename_from_ansi (p, fname_utf8);
2359 else
2361 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2362 if (dir_handle != INVALID_HANDLE_VALUE)
2363 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2367 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2368 memcpy (buf, fname_utf8, len + 1);
2369 else
2370 len = 0;
2372 if (dir_handle != INVALID_HANDLE_VALUE)
2373 FindClose (dir_handle);
2375 return len;
2378 /* Get long name for file, if possible (assumed to be absolute). */
2379 BOOL
2380 w32_get_long_filename (const char * name, char * buf, int size)
2382 char * o = buf;
2383 char * p;
2384 const char * q;
2385 char full[ MAX_UTF8_PATH ];
2386 int len;
2388 len = strlen (name);
2389 if (len >= MAX_UTF8_PATH)
2390 return FALSE;
2392 /* Use local copy for destructive modification. */
2393 memcpy (full, name, len+1);
2394 unixtodos_filename (full);
2396 /* Copy root part verbatim. */
2397 len = parse_root (full, (const char **)&p);
2398 memcpy (o, full, len);
2399 o += len;
2400 *o = '\0';
2401 size -= len;
2403 while (p != NULL && *p)
2405 q = p;
2406 p = strchr (q, '\\');
2407 if (p) *p = '\0';
2408 len = get_long_basename (full, o, size);
2409 if (len > 0)
2411 o += len;
2412 size -= len;
2413 if (p != NULL)
2415 *p++ = '\\';
2416 if (size < 2)
2417 return FALSE;
2418 *o++ = '\\';
2419 size--;
2420 *o = '\0';
2423 else
2424 return FALSE;
2427 return TRUE;
2430 unsigned int
2431 w32_get_short_filename (const char * name, char * buf, int size)
2433 if (w32_unicode_filenames)
2435 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2436 unsigned int retval;
2438 filename_to_utf16 (name, name_utf16);
2439 retval = GetShortPathNameW (name_utf16, short_name, size);
2440 if (retval && retval < size)
2441 filename_from_utf16 (short_name, buf);
2442 return retval;
2444 else
2446 char name_ansi[MAX_PATH];
2448 filename_to_ansi (name, name_ansi);
2449 return GetShortPathNameA (name_ansi, buf, size);
2453 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2454 MS-Windows ANSI codepage. If FILENAME includes characters not
2455 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2456 if it exists. This is needed because the w32 build wants to
2457 support file names outside of the system locale, but image
2458 libraries typically don't support wide (a.k.a. "Unicode") APIs
2459 required for that. */
2461 Lisp_Object
2462 ansi_encode_filename (Lisp_Object filename)
2464 Lisp_Object encoded_filename;
2465 char fname[MAX_PATH];
2467 filename_to_ansi (SSDATA (filename), fname);
2468 if (_mbspbrk (fname, "?"))
2470 char shortname[MAX_PATH];
2472 if (w32_get_short_filename (SSDATA (filename), shortname, MAX_PATH))
2474 dostounix_filename (shortname);
2475 encoded_filename = build_string (shortname);
2477 else
2478 encoded_filename = build_unibyte_string (fname);
2480 else
2481 encoded_filename = build_unibyte_string (fname);
2482 return encoded_filename;
2485 static int
2486 is_unc_volume (const char *filename)
2488 const char *ptr = filename;
2490 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2491 return 0;
2493 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2494 return 0;
2496 return 1;
2499 /* Emulate the Posix unsetenv. */
2501 unsetenv (const char *name)
2503 char *var;
2504 size_t name_len;
2506 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2508 errno = EINVAL;
2509 return -1;
2511 name_len = strlen (name);
2512 /* MS docs says an environment variable cannot be longer than 32K. */
2513 if (name_len > 32767)
2515 errno = ENOMEM;
2516 return 0;
2518 /* It is safe to use 'alloca' with 32K size, since the stack is at
2519 least 2MB, and we set it to 8MB in the link command line. */
2520 var = alloca (name_len + 2);
2521 strncpy (var, name, name_len);
2522 var[name_len++] = '=';
2523 var[name_len] = '\0';
2524 return _putenv (var);
2527 /* MS _putenv doesn't support removing a variable when the argument
2528 does not include the '=' character, so we fix that here. */
2530 sys_putenv (char *str)
2532 const char *const name_end = strchr (str, '=');
2534 if (name_end == NULL)
2536 /* Remove the variable from the environment. */
2537 return unsetenv (str);
2540 if (strncmp (str, "TZ=<", 4) == 0)
2542 /* MS-Windows does not support POSIX.1-2001 angle-bracket TZ
2543 abbreviation syntax. Convert to POSIX.1-1988 syntax if possible,
2544 and to the undocumented placeholder "ZZZ" otherwise. */
2545 bool supported_abbr = true;
2546 for (char *p = str + 4; *p; p++)
2548 if (('0' <= *p && *p <= '9') || *p == '-' || *p == '+')
2549 supported_abbr = false;
2550 else if (*p == '>')
2552 ptrdiff_t abbrlen;
2553 if (supported_abbr)
2555 abbrlen = p - (str + 4);
2556 memmove (str + 3, str + 4, abbrlen);
2558 else
2560 abbrlen = 3;
2561 memset (str + 3, 'Z', abbrlen);
2563 memmove (str + 3 + abbrlen, p + 1, strlen (p));
2564 break;
2569 return _putenv (str);
2572 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2574 LPBYTE
2575 w32_get_resource (const char *key, LPDWORD lpdwtype)
2577 LPBYTE lpvalue;
2578 HKEY hrootkey = NULL;
2579 DWORD cbData;
2581 /* Check both the current user and the local machine to see if
2582 we have any resources. */
2584 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2586 lpvalue = NULL;
2588 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2589 && (lpvalue = xmalloc (cbData)) != NULL
2590 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2592 RegCloseKey (hrootkey);
2593 return (lpvalue);
2596 xfree (lpvalue);
2598 RegCloseKey (hrootkey);
2601 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2603 lpvalue = NULL;
2605 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2606 && (lpvalue = xmalloc (cbData)) != NULL
2607 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2609 RegCloseKey (hrootkey);
2610 return (lpvalue);
2613 xfree (lpvalue);
2615 RegCloseKey (hrootkey);
2618 return (NULL);
2621 /* The argv[] array holds ANSI-encoded strings, and so this function
2622 works with ANS_encoded strings. */
2623 void
2624 init_environment (char ** argv)
2626 static const char * const tempdirs[] = {
2627 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2630 int i;
2632 const int imax = ARRAYELTS (tempdirs);
2634 /* Implementation note: This function explicitly works with ANSI
2635 file names, not with UTF-8 encoded file names. This is because
2636 this function pushes variables into the Emacs's environment, and
2637 the environment variables are always assumed to be in the
2638 locale-specific encoding. Do NOT call any functions that accept
2639 UTF-8 file names from this function! */
2641 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2642 temporary files and assume "/tmp" if $TMPDIR is unset, which
2643 will break on DOS/Windows. Refuse to work if we cannot find
2644 a directory, not even "c:/", usable for that purpose. */
2645 for (i = 0; i < imax ; i++)
2647 const char *tmp = tempdirs[i];
2649 if (*tmp == '$')
2650 tmp = getenv (tmp + 1);
2651 /* Note that `access' can lie to us if the directory resides on a
2652 read-only filesystem, like CD-ROM or a write-protected floppy.
2653 The only way to be really sure is to actually create a file and
2654 see if it succeeds. But I think that's too much to ask. */
2656 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2657 if (tmp && sys_access (tmp, D_OK) == 0)
2659 char * var = alloca (strlen (tmp) + 8);
2660 sprintf (var, "TMPDIR=%s", tmp);
2661 _putenv (strdup (var));
2662 break;
2665 if (i >= imax)
2666 cmd_error_internal
2667 (Fcons (Qerror,
2668 Fcons (build_string ("no usable temporary directories found!!"),
2669 Qnil)),
2670 "While setting TMPDIR: ");
2672 /* Check for environment variables and use registry settings if they
2673 don't exist. Fallback on default values where applicable. */
2675 int i;
2676 LPBYTE lpval;
2677 DWORD dwType;
2678 char locale_name[32];
2679 char default_home[MAX_PATH];
2680 int appdata = 0;
2682 static const struct env_entry
2684 const char * name;
2685 const char * def_value;
2686 } dflt_envvars[] =
2688 /* If the default value is NULL, we will use the value from the
2689 outside environment or the Registry, but will not push the
2690 variable into the Emacs environment if it is defined neither
2691 in the Registry nor in the outside environment. */
2692 {"HOME", "C:/"},
2693 {"PRELOAD_WINSOCK", NULL},
2694 {"emacs_dir", "C:/emacs"},
2695 {"EMACSLOADPATH", NULL},
2696 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2697 {"EMACSDATA", NULL},
2698 {"EMACSPATH", NULL},
2699 {"INFOPATH", NULL},
2700 {"EMACSDOC", NULL},
2701 {"TERM", "cmd"},
2702 {"LANG", NULL},
2705 #define N_ENV_VARS ARRAYELTS (dflt_envvars)
2707 /* We need to copy dflt_envvars[] and work on the copy because we
2708 don't want the dumped Emacs to inherit the values of
2709 environment variables we saw during dumping (which could be on
2710 a different system). The defaults above must be left intact. */
2711 struct env_entry env_vars[N_ENV_VARS];
2713 for (i = 0; i < N_ENV_VARS; i++)
2714 env_vars[i] = dflt_envvars[i];
2716 /* For backwards compatibility, check if a .emacs file exists in C:/
2717 If not, then we can try to default to the appdata directory under the
2718 user's profile, which is more likely to be writable. */
2719 if (sys_access ("C:/.emacs", F_OK) != 0)
2721 HRESULT profile_result;
2722 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2723 of Windows 95 and NT4 that have not been updated to include
2724 MSIE 5. */
2725 ShGetFolderPath_fn get_folder_path;
2726 get_folder_path = (ShGetFolderPath_fn)
2727 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2729 if (get_folder_path != NULL)
2731 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2732 0, default_home);
2734 /* If we can't get the appdata dir, revert to old behavior. */
2735 if (profile_result == S_OK)
2737 env_vars[0].def_value = default_home;
2738 appdata = 1;
2743 /* Get default locale info and use it for LANG. */
2744 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2745 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2746 locale_name, sizeof (locale_name)))
2748 for (i = 0; i < N_ENV_VARS; i++)
2750 if (strcmp (env_vars[i].name, "LANG") == 0)
2752 env_vars[i].def_value = locale_name;
2753 break;
2758 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2760 /* Treat emacs_dir specially: set it unconditionally based on our
2761 location. */
2763 char *p;
2764 char modname[MAX_PATH];
2766 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2767 emacs_abort ();
2768 if ((p = _mbsrchr (modname, '\\')) == NULL)
2769 emacs_abort ();
2770 *p = 0;
2772 if ((p = _mbsrchr (modname, '\\'))
2773 /* From bin means installed Emacs, from src means uninstalled. */
2774 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2776 char buf[SET_ENV_BUF_SIZE];
2777 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2779 *p = 0;
2780 for (p = modname; *p; p = CharNext (p))
2781 if (*p == '\\') *p = '/';
2783 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2784 _putenv (strdup (buf));
2785 /* If we are running from the Posix-like build tree, define
2786 SHELL to point to our own cmdproxy. The loop below will
2787 then disregard PATH_EXEC and the default value. */
2788 if (within_build_tree)
2790 _snprintf (buf, sizeof (buf) - 1,
2791 "SHELL=%s/nt/cmdproxy.exe", modname);
2792 _putenv (strdup (buf));
2797 for (i = 0; i < N_ENV_VARS; i++)
2799 if (!getenv (env_vars[i].name))
2801 int dont_free = 0;
2802 char bufc[SET_ENV_BUF_SIZE];
2804 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2805 /* Also ignore empty environment variables. */
2806 || *lpval == 0)
2808 xfree (lpval);
2809 dont_free = 1;
2810 if (strcmp (env_vars[i].name, "SHELL") == 0)
2812 /* Look for cmdproxy.exe in every directory in
2813 PATH_EXEC. FIXME: This does not find cmdproxy
2814 in nt/ when we run uninstalled. */
2815 char fname[MAX_PATH];
2816 const char *pstart = PATH_EXEC, *pend;
2818 do {
2819 pend = _mbschr (pstart, ';');
2820 if (!pend)
2821 pend = pstart + strlen (pstart);
2822 /* Be defensive against series of ;;; characters. */
2823 if (pend > pstart)
2825 strncpy (fname, pstart, pend - pstart);
2826 fname[pend - pstart] = '/';
2827 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2828 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2829 sizeof (bufc));
2830 if (sys_access (bufc, F_OK) == 0)
2832 lpval = bufc;
2833 dwType = REG_SZ;
2834 break;
2837 if (*pend)
2838 pstart = pend + 1;
2839 else
2840 pstart = pend;
2841 if (!*pstart)
2843 /* If not found in any directory, use the
2844 default as the last resort. */
2845 lpval = (char *)env_vars[i].def_value;
2846 dwType = REG_EXPAND_SZ;
2848 } while (*pstart);
2850 else
2852 lpval = (char *)env_vars[i].def_value;
2853 dwType = REG_EXPAND_SZ;
2855 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2856 Vdelayed_warnings_list
2857 = Fcons
2858 (listn (CONSTYPE_HEAP, 2,
2859 intern ("initialization"), build_string
2860 ("Use of `C:\\.emacs' without defining `HOME'\n"
2861 "in the environment is deprecated, "
2862 "see `Windows HOME' in the Emacs manual.")),
2863 Vdelayed_warnings_list);
2866 if (lpval)
2868 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2870 if (dwType == REG_EXPAND_SZ)
2871 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2872 else if (dwType == REG_SZ)
2873 strcpy (buf1, (char *)lpval);
2874 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2876 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2877 buf1);
2878 _putenv (strdup (buf2));
2881 if (!dont_free)
2882 xfree (lpval);
2888 /* Rebuild system configuration to reflect invoking system. */
2889 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2891 /* Another special case: on NT, the PATH variable is actually named
2892 "Path" although cmd.exe (perhaps NT itself) arranges for
2893 environment variable lookup and setting to be case insensitive.
2894 However, Emacs assumes a fully case sensitive environment, so we
2895 need to change "Path" to "PATH" to match the expectations of
2896 various elisp packages. We do this by the sneaky method of
2897 modifying the string in the C runtime environ entry.
2899 The same applies to COMSPEC. */
2901 char ** envp;
2902 const char *path = "PATH=";
2903 int path_len = strlen (path);
2904 const char *comspec = "COMSPEC=";
2905 int comspec_len = strlen (comspec);
2907 for (envp = environ; *envp; envp++)
2908 if (_strnicmp (*envp, path, path_len) == 0)
2909 memcpy (*envp, path, path_len);
2910 else if (_strnicmp (*envp, comspec, comspec_len) == 0)
2911 memcpy (*envp, comspec, comspec_len);
2913 /* Make the same modification to `process-environment' which has
2914 already been initialized in set_initial_environment. */
2915 for (Lisp_Object env = Vprocess_environment; CONSP (env); env = XCDR (env))
2917 Lisp_Object entry = XCAR (env);
2918 if (_strnicmp (SDATA (entry), path, path_len) == 0)
2919 for (int i = 0; i < path_len; i++)
2920 SSET (entry, i, path[i]);
2921 else if (_strnicmp (SDATA (entry), comspec, comspec_len) == 0)
2922 for (int i = 0; i < comspec_len; i++)
2923 SSET (entry, i, comspec[i]);
2927 /* Remember the initial working directory for getcwd. */
2928 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2929 Does it matter anywhere in Emacs? */
2930 if (w32_unicode_filenames)
2932 wchar_t wstartup_dir[MAX_PATH];
2934 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2935 emacs_abort ();
2936 filename_from_utf16 (wstartup_dir, startup_dir);
2938 else
2940 char astartup_dir[MAX_PATH];
2942 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2943 emacs_abort ();
2944 filename_from_ansi (astartup_dir, startup_dir);
2948 static char modname[MAX_PATH];
2950 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2951 emacs_abort ();
2952 argv[0] = modname;
2955 /* Determine if there is a middle mouse button, to allow parse_button
2956 to decide whether right mouse events should be mouse-2 or
2957 mouse-3. */
2958 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2960 init_user_info ();
2963 /* Called from expand-file-name when default-directory is not a string. */
2965 char *
2966 emacs_root_dir (void)
2968 static char root_dir[MAX_UTF8_PATH];
2969 const char *p;
2971 p = getenv ("emacs_dir");
2972 if (p == NULL)
2973 emacs_abort ();
2974 filename_from_ansi (p, root_dir);
2975 root_dir[parse_root (root_dir, NULL)] = '\0';
2976 dostounix_filename (root_dir);
2977 return root_dir;
2980 /* Emulate fdutimens. */
2982 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2983 TIMESPEC[0] and TIMESPEC[1], respectively.
2984 FD must be either negative -- in which case it is ignored --
2985 or a file descriptor that is open on FILE.
2986 If FD is nonnegative, then FILE can be NULL, which means
2987 use just futimes instead of utimes.
2988 If TIMESPEC is null, FAIL.
2989 Return 0 on success, -1 (setting errno) on failure. */
2992 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2994 if (!timespec)
2996 errno = ENOSYS;
2997 return -1;
2999 if (fd < 0 && !file)
3001 errno = EBADF;
3002 return -1;
3004 /* _futime's prototype defines 2nd arg as having the type 'struct
3005 _utimbuf', while utime needs to accept 'struct utimbuf' for
3006 compatibility with Posix. So we need to use 2 different (but
3007 equivalent) types to avoid compiler warnings, sigh. */
3008 if (fd >= 0)
3010 struct _utimbuf _ut;
3012 _ut.actime = timespec[0].tv_sec;
3013 _ut.modtime = timespec[1].tv_sec;
3014 return _futime (fd, &_ut);
3016 else
3018 struct utimbuf ut;
3020 ut.actime = timespec[0].tv_sec;
3021 ut.modtime = timespec[1].tv_sec;
3022 /* Call 'utime', which is implemented below, not the MS library
3023 function, which fails on directories. */
3024 return utime (file, &ut);
3029 /* ------------------------------------------------------------------------- */
3030 /* IO support and wrapper functions for the Windows API. */
3031 /* ------------------------------------------------------------------------- */
3033 /* Place a wrapper around the MSVC version of ctime. It returns NULL
3034 on network directories, so we handle that case here.
3035 (Ulrich Leodolter, 1/11/95). */
3036 char *
3037 sys_ctime (const time_t *t)
3039 char *str = (char *) ctime (t);
3040 return (str ? str : (char *)"Sun Jan 01 00:00:00 1970");
3043 /* Emulate sleep...we could have done this with a define, but that
3044 would necessitate including windows.h in the files that used it.
3045 This is much easier. */
3046 void
3047 sys_sleep (int seconds)
3049 Sleep (seconds * 1000);
3052 /* Internal MSVC functions for low-level descriptor munging */
3053 extern int __cdecl _set_osfhnd (int fd, long h);
3054 extern int __cdecl _free_osfhnd (int fd);
3056 /* parallel array of private info on file handles */
3057 filedesc fd_info [ MAXDESC ];
3059 typedef struct volume_info_data {
3060 struct volume_info_data * next;
3062 /* time when info was obtained */
3063 DWORD timestamp;
3065 /* actual volume info */
3066 char * root_dir;
3067 DWORD serialnum;
3068 DWORD maxcomp;
3069 DWORD flags;
3070 char * name;
3071 char * type;
3072 } volume_info_data;
3074 /* Global referenced by various functions. */
3075 static volume_info_data volume_info;
3077 /* Vector to indicate which drives are local and fixed (for which cached
3078 data never expires). */
3079 static BOOL fixed_drives[26];
3081 /* Consider cached volume information to be stale if older than 10s,
3082 at least for non-local drives. Info for fixed drives is never stale. */
3083 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
3084 #define VOLINFO_STILL_VALID( root_dir, info ) \
3085 ( ( isalpha (root_dir[0]) && \
3086 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
3087 || GetTickCount () - info->timestamp < 10000 )
3089 /* Cache support functions. */
3091 /* Simple linked list with linear search is sufficient. */
3092 static volume_info_data *volume_cache = NULL;
3094 static volume_info_data *
3095 lookup_volume_info (char * root_dir)
3097 volume_info_data * info;
3099 for (info = volume_cache; info; info = info->next)
3100 if (xstrcasecmp (info->root_dir, root_dir) == 0)
3101 break;
3102 return info;
3105 static void
3106 add_volume_info (char * root_dir, volume_info_data * info)
3108 info->root_dir = xstrdup (root_dir);
3109 unixtodos_filename (info->root_dir);
3110 info->next = volume_cache;
3111 volume_cache = info;
3115 /* Wrapper for GetVolumeInformation, which uses caching to avoid
3116 performance penalty (~2ms on 486 for local drives, 7.5ms for local
3117 cdrom drive, ~5-10ms or more for remote drives on LAN). */
3118 static volume_info_data *
3119 GetCachedVolumeInformation (char * root_dir)
3121 volume_info_data * info;
3122 char default_root[ MAX_UTF8_PATH ];
3123 char name[MAX_PATH+1];
3124 char type[MAX_PATH+1];
3126 /* NULL for root_dir means use root from current directory. */
3127 if (root_dir == NULL)
3129 if (w32_unicode_filenames)
3131 wchar_t curdirw[MAX_PATH];
3133 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
3134 return NULL;
3135 filename_from_utf16 (curdirw, default_root);
3137 else
3139 char curdira[MAX_PATH];
3141 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
3142 return NULL;
3143 filename_from_ansi (curdira, default_root);
3145 parse_root (default_root, (const char **)&root_dir);
3146 *root_dir = 0;
3147 root_dir = default_root;
3150 /* Local fixed drives can be cached permanently. Removable drives
3151 cannot be cached permanently, since the volume name and serial
3152 number (if nothing else) can change. Remote drives should be
3153 treated as if they are removable, since there is no sure way to
3154 tell whether they are or not. Also, the UNC association of drive
3155 letters mapped to remote volumes can be changed at any time (even
3156 by other processes) without notice.
3158 As a compromise, so we can benefit from caching info for remote
3159 volumes, we use a simple expiry mechanism to invalidate cache
3160 entries that are more than ten seconds old. */
3162 #if 0
3163 /* No point doing this, because WNetGetConnection is even slower than
3164 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
3165 GetDriveType is about the only call of this type which does not
3166 involve network access, and so is extremely quick). */
3168 /* Map drive letter to UNC if remote. */
3169 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
3171 char remote_name[ 256 ];
3172 char drive[3] = { root_dir[0], ':' };
3174 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
3175 == NO_ERROR)
3176 /* do something */ ;
3178 #endif
3180 info = lookup_volume_info (root_dir);
3182 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
3184 DWORD serialnum;
3185 DWORD maxcomp;
3186 DWORD flags;
3188 /* Info is not cached, or is stale. */
3189 if (w32_unicode_filenames)
3191 wchar_t root_w[MAX_PATH];
3192 wchar_t name_w[MAX_PATH+1];
3193 wchar_t type_w[MAX_PATH+1];
3195 filename_to_utf16 (root_dir, root_w);
3196 if (!GetVolumeInformationW (root_w,
3197 name_w, sizeof (name_w),
3198 &serialnum,
3199 &maxcomp,
3200 &flags,
3201 type_w, sizeof (type_w)))
3202 return NULL;
3203 /* Hmm... not really 100% correct, as these 2 are not file
3204 names... */
3205 filename_from_utf16 (name_w, name);
3206 filename_from_utf16 (type_w, type);
3208 else
3210 char root_a[MAX_PATH];
3211 char name_a[MAX_PATH+1];
3212 char type_a[MAX_PATH+1];
3214 filename_to_ansi (root_dir, root_a);
3215 if (!GetVolumeInformationA (root_a,
3216 name_a, sizeof (name_a),
3217 &serialnum,
3218 &maxcomp,
3219 &flags,
3220 type_a, sizeof (type_a)))
3221 return NULL;
3222 filename_from_ansi (name_a, name);
3223 filename_from_ansi (type_a, type);
3226 /* Cache the volume information for future use, overwriting existing
3227 entry if present. */
3228 if (info == NULL)
3230 info = xmalloc (sizeof (volume_info_data));
3231 add_volume_info (root_dir, info);
3233 else
3235 xfree (info->name);
3236 xfree (info->type);
3239 info->name = xstrdup (name);
3240 unixtodos_filename (info->name);
3241 info->serialnum = serialnum;
3242 info->maxcomp = maxcomp;
3243 info->flags = flags;
3244 info->type = xstrdup (type);
3245 info->timestamp = GetTickCount ();
3248 return info;
3251 /* Get information on the volume where NAME is held; set path pointer to
3252 start of pathname in NAME (past UNC header\volume header if present),
3253 if pPath is non-NULL.
3255 Note: if NAME includes symlinks, the information is for the volume
3256 of the symlink, not of its target. That's because, even though
3257 GetVolumeInformation returns information about the symlink target
3258 of its argument, we only pass the root directory to
3259 GetVolumeInformation, not the full NAME. */
3260 static int
3261 get_volume_info (const char * name, const char ** pPath)
3263 char temp[MAX_UTF8_PATH];
3264 char *rootname = NULL; /* default to current volume */
3265 volume_info_data * info;
3266 int root_len = parse_root (name, pPath);
3268 if (name == NULL)
3269 return FALSE;
3271 /* Copy the root name of the volume, if given. */
3272 if (root_len)
3274 strncpy (temp, name, root_len);
3275 temp[root_len] = '\0';
3276 unixtodos_filename (temp);
3277 rootname = temp;
3280 info = GetCachedVolumeInformation (rootname);
3281 if (info != NULL)
3283 /* Set global referenced by other functions. */
3284 volume_info = *info;
3285 return TRUE;
3287 return FALSE;
3290 /* Determine if volume is FAT format (ie. only supports short 8.3
3291 names); also set path pointer to start of pathname in name, if
3292 pPath is non-NULL. */
3293 static int
3294 is_fat_volume (const char * name, const char ** pPath)
3296 if (get_volume_info (name, pPath))
3297 return (volume_info.maxcomp == 12);
3298 return FALSE;
3301 /* Convert all slashes in a filename to backslashes, and map filename
3302 to a valid 8.3 name if necessary. The result is a pointer to a
3303 static buffer, so CAVEAT EMPTOR! */
3304 const char *map_w32_filename (const char *, const char **);
3306 const char *
3307 map_w32_filename (const char * name, const char ** pPath)
3309 static char shortname[MAX_UTF8_PATH];
3310 char * str = shortname;
3311 char c;
3312 char * path;
3313 const char * save_name = name;
3315 if (strlen (name) >= sizeof (shortname))
3317 /* Return a filename which will cause callers to fail. */
3318 strcpy (shortname, "?");
3319 return shortname;
3322 if (!fatal_error_in_progress /* disable fancy processing during crash */
3323 && is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3325 register int left = 8; /* maximum number of chars in part */
3326 register int extn = 0; /* extension added? */
3327 register int dots = 2; /* maximum number of dots allowed */
3329 while (name < path)
3330 *str++ = *name++; /* skip past UNC header */
3332 while ((c = *name++))
3334 switch ( c )
3336 case ':':
3337 case '\\':
3338 case '/':
3339 *str++ = (c == ':' ? ':' : '\\');
3340 extn = 0; /* reset extension flags */
3341 dots = 2; /* max 2 dots */
3342 left = 8; /* max length 8 for main part */
3343 break;
3344 case '.':
3345 if ( dots )
3347 /* Convert path components of the form .xxx to _xxx,
3348 but leave . and .. as they are. This allows .emacs
3349 to be read as _emacs, for example. */
3351 if (! *name ||
3352 *name == '.' ||
3353 IS_DIRECTORY_SEP (*name))
3355 *str++ = '.';
3356 dots--;
3358 else
3360 *str++ = '_';
3361 left--;
3362 dots = 0;
3365 else if ( !extn )
3367 *str++ = '.';
3368 extn = 1; /* we've got an extension */
3369 left = 3; /* 3 chars in extension */
3371 else
3373 /* any embedded dots after the first are converted to _ */
3374 *str++ = '_';
3376 break;
3377 case '~':
3378 case '#': /* don't lose these, they're important */
3379 if ( ! left )
3380 str[-1] = c; /* replace last character of part */
3381 /* FALLTHRU */
3382 FALLTHROUGH;
3383 default:
3384 if ( left && 'A' <= c && c <= 'Z' )
3386 *str++ = tolower (c); /* map to lower case (looks nicer) */
3387 left--;
3388 dots = 0; /* started a path component */
3390 break;
3393 *str = '\0';
3395 else
3397 strcpy (shortname, name);
3398 unixtodos_filename (shortname);
3401 if (pPath)
3402 *pPath = shortname + (path - save_name);
3404 return shortname;
3407 static int
3408 is_exec (const char * name)
3410 char * p = strrchr (name, '.');
3411 return
3412 (p != NULL
3413 && (xstrcasecmp (p, ".exe") == 0 ||
3414 xstrcasecmp (p, ".com") == 0 ||
3415 xstrcasecmp (p, ".bat") == 0 ||
3416 xstrcasecmp (p, ".cmd") == 0));
3419 /* Emulate the Unix directory procedures opendir, closedir, and
3420 readdir. We rename them to sys_* names because some versions of
3421 MinGW startup code call opendir and readdir to glob wildcards, and
3422 the code that calls them doesn't grok UTF-8 encoded file names we
3423 produce in dirent->d_name[]. */
3425 struct dirent dir_static; /* simulated directory contents */
3426 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3427 static int dir_is_fat;
3428 static char dir_pathname[MAX_UTF8_PATH];
3429 static WIN32_FIND_DATAW dir_find_data_w;
3430 static WIN32_FIND_DATAA dir_find_data_a;
3431 #define DIR_FIND_DATA_W 1
3432 #define DIR_FIND_DATA_A 2
3433 static int last_dir_find_data = -1;
3435 /* Support shares on a network resource as subdirectories of a read-only
3436 root directory. */
3437 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3438 static HANDLE open_unc_volume (const char *);
3439 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3440 static void close_unc_volume (HANDLE);
3442 DIR *
3443 sys_opendir (const char *filename)
3445 DIR *dirp;
3447 /* Opening is done by FindFirstFile. However, a read is inherent to
3448 this operation, so we defer the open until read time. */
3450 if (dir_find_handle != INVALID_HANDLE_VALUE)
3451 return NULL;
3452 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3453 return NULL;
3455 /* Note: We don't support traversal of UNC volumes via symlinks.
3456 Doing so would mean punishing 99.99% of use cases by resolving
3457 all the possible symlinks in FILENAME, recursively. */
3458 if (is_unc_volume (filename))
3460 wnet_enum_handle = open_unc_volume (filename);
3461 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3462 return NULL;
3465 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3466 return NULL;
3468 dirp->dd_fd = 0;
3469 dirp->dd_loc = 0;
3470 dirp->dd_size = 0;
3472 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3473 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3474 /* Note: We don't support symlinks to file names on FAT volumes.
3475 Doing so would mean punishing 99.99% of use cases by resolving
3476 all the possible symlinks in FILENAME, recursively. */
3477 dir_is_fat = is_fat_volume (filename, NULL);
3479 return dirp;
3482 void
3483 sys_closedir (DIR *dirp)
3485 /* If we have a find-handle open, close it. */
3486 if (dir_find_handle != INVALID_HANDLE_VALUE)
3488 FindClose (dir_find_handle);
3489 dir_find_handle = INVALID_HANDLE_VALUE;
3491 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3493 close_unc_volume (wnet_enum_handle);
3494 wnet_enum_handle = INVALID_HANDLE_VALUE;
3496 xfree ((char *) dirp);
3499 struct dirent *
3500 sys_readdir (DIR *dirp)
3502 int downcase = !NILP (Vw32_downcase_file_names);
3504 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3506 if (!read_unc_volume (wnet_enum_handle,
3507 dir_find_data_w.cFileName,
3508 dir_find_data_a.cFileName,
3509 MAX_PATH))
3510 return NULL;
3512 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3513 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3515 char filename[MAX_UTF8_PATH];
3516 int ln;
3517 bool last_slash = true;
3519 /* Note: We don't need to worry about dir_pathname being longer
3520 than MAX_UTF8_PATH, as sys_opendir already took care of that
3521 when it called map_w32_filename: that function will put a "?"
3522 in its return value in that case, thus failing all the calls
3523 below. */
3524 strcpy (filename, dir_pathname);
3525 ln = strlen (filename);
3526 if (!IS_DIRECTORY_SEP (filename[ln - 1]))
3527 last_slash = false;
3529 /* Note: No need to resolve symlinks in FILENAME, because
3530 FindFirst opens the directory that is the target of a
3531 symlink. */
3532 if (w32_unicode_filenames)
3534 wchar_t fnw[MAX_PATH + 2];
3536 filename_to_utf16 (filename, fnw);
3537 if (!last_slash)
3538 wcscat (fnw, L"\\");
3539 wcscat (fnw, L"*");
3540 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3542 else
3544 char fna[MAX_PATH + 2];
3546 filename_to_ansi (filename, fna);
3547 if (!last_slash)
3548 strcat (fna, "\\");
3549 strcat (fna, "*");
3550 /* If FILENAME is not representable by the current ANSI
3551 codepage, we don't want FindFirstFileA to interpret the
3552 '?' characters as a wildcard. */
3553 if (_mbspbrk (fna, "?"))
3554 dir_find_handle = INVALID_HANDLE_VALUE;
3555 else
3556 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3559 if (dir_find_handle == INVALID_HANDLE_VALUE)
3561 /* Any changes in the value of errno here should be in sync
3562 with what directory_files_internal does when it calls
3563 readdir. */
3564 switch (GetLastError ())
3566 /* Windows uses this value when FindFirstFile finds no
3567 files that match the wildcard. This is not supposed
3568 to happen, since our wildcard is "*", but just in
3569 case, if there's some weird empty directory with not
3570 even "." and ".." entries... */
3571 case ERROR_FILE_NOT_FOUND:
3572 errno = 0;
3573 /* FALLTHRU */
3574 default:
3575 break;
3576 case ERROR_ACCESS_DENIED:
3577 case ERROR_NETWORK_ACCESS_DENIED:
3578 errno = EACCES;
3579 break;
3580 case ERROR_PATH_NOT_FOUND:
3581 case ERROR_INVALID_DRIVE:
3582 case ERROR_NOT_READY:
3583 case ERROR_BAD_NETPATH:
3584 case ERROR_BAD_NET_NAME:
3585 errno = ENOENT;
3586 break;
3588 return NULL;
3591 else if (w32_unicode_filenames)
3593 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3595 errno = 0;
3596 return NULL;
3599 else
3601 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3603 errno = 0;
3604 return NULL;
3608 /* Emacs never uses this value, so don't bother making it match
3609 value returned by stat(). */
3610 dir_static.d_ino = 1;
3612 if (w32_unicode_filenames)
3614 if (downcase || dir_is_fat)
3616 wchar_t tem[MAX_PATH];
3618 wcscpy (tem, dir_find_data_w.cFileName);
3619 CharLowerW (tem);
3620 filename_from_utf16 (tem, dir_static.d_name);
3622 else
3623 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3624 last_dir_find_data = DIR_FIND_DATA_W;
3626 else
3628 char tem[MAX_PATH];
3630 /* If the file name in cFileName[] includes `?' characters, it
3631 means the original file name used characters that cannot be
3632 represented by the current ANSI codepage. To avoid total
3633 lossage, retrieve the short 8+3 alias of the long file
3634 name. */
3635 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3637 strcpy (tem, dir_find_data_a.cAlternateFileName);
3638 /* 8+3 aliases are returned in all caps, which could break
3639 various alists that look at filenames' extensions. */
3640 downcase = 1;
3642 else if (downcase || dir_is_fat)
3643 strcpy (tem, dir_find_data_a.cFileName);
3644 else
3645 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3646 if (downcase || dir_is_fat)
3648 _mbslwr (tem);
3649 filename_from_ansi (tem, dir_static.d_name);
3651 last_dir_find_data = DIR_FIND_DATA_A;
3654 dir_static.d_namlen = strlen (dir_static.d_name);
3655 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3656 dir_static.d_namlen - dir_static.d_namlen % 4;
3658 return &dir_static;
3661 static HANDLE
3662 open_unc_volume (const char *path)
3664 const char *fn = map_w32_filename (path, NULL);
3665 DWORD result;
3666 HANDLE henum;
3668 if (w32_unicode_filenames)
3670 NETRESOURCEW nrw;
3671 wchar_t fnw[MAX_PATH];
3673 nrw.dwScope = RESOURCE_GLOBALNET;
3674 nrw.dwType = RESOURCETYPE_DISK;
3675 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3676 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3677 nrw.lpLocalName = NULL;
3678 filename_to_utf16 (fn, fnw);
3679 nrw.lpRemoteName = fnw;
3680 nrw.lpComment = NULL;
3681 nrw.lpProvider = NULL;
3683 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3684 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3686 else
3688 NETRESOURCEA nra;
3689 char fna[MAX_PATH];
3691 nra.dwScope = RESOURCE_GLOBALNET;
3692 nra.dwType = RESOURCETYPE_DISK;
3693 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3694 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3695 nra.lpLocalName = NULL;
3696 filename_to_ansi (fn, fna);
3697 nra.lpRemoteName = fna;
3698 nra.lpComment = NULL;
3699 nra.lpProvider = NULL;
3701 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3702 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3704 if (result == NO_ERROR)
3705 return henum;
3706 else
3708 /* Make sure directory_files_internal reports a sensible error. */
3709 errno = ENOENT;
3710 return INVALID_HANDLE_VALUE;
3714 static void *
3715 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3717 DWORD count;
3718 int result;
3719 char *buffer;
3720 DWORD bufsize = 512;
3721 void *retval;
3723 count = 1;
3724 if (w32_unicode_filenames)
3726 wchar_t *ptrw;
3728 bufsize *= 2;
3729 buffer = alloca (bufsize);
3730 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3731 if (result != NO_ERROR)
3732 return NULL;
3733 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3734 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3735 ptrw += 2;
3736 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3737 ptrw++;
3738 wcsncpy (fname_w, ptrw, size);
3739 retval = fname_w;
3741 else
3743 int dbcs_p = max_filename_mbslen () > 1;
3744 char *ptra;
3746 buffer = alloca (bufsize);
3747 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3748 if (result != NO_ERROR)
3749 return NULL;
3750 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3751 ptra += 2;
3752 if (!dbcs_p)
3753 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3754 else
3756 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3757 ptra = CharNextExA (file_name_codepage, ptra, 0);
3759 ptra++;
3760 strncpy (fname_a, ptra, size);
3761 retval = fname_a;
3764 return retval;
3767 static void
3768 close_unc_volume (HANDLE henum)
3770 if (henum != INVALID_HANDLE_VALUE)
3771 WNetCloseEnum (henum);
3774 static DWORD
3775 unc_volume_file_attributes (const char *path)
3777 HANDLE henum;
3778 DWORD attrs;
3780 henum = open_unc_volume (path);
3781 if (henum == INVALID_HANDLE_VALUE)
3782 return -1;
3784 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3786 close_unc_volume (henum);
3788 return attrs;
3791 /* Ensure a network connection is authenticated. */
3792 static void
3793 logon_network_drive (const char *path)
3795 char share[MAX_UTF8_PATH];
3796 int n_slashes;
3797 char drive[4];
3798 UINT drvtype;
3799 char *p;
3800 DWORD val;
3802 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3803 drvtype = DRIVE_REMOTE;
3804 else if (path[0] == '\0' || path[1] != ':')
3805 drvtype = GetDriveType (NULL);
3806 else
3808 drive[0] = path[0];
3809 drive[1] = ':';
3810 drive[2] = '\\';
3811 drive[3] = '\0';
3812 drvtype = GetDriveType (drive);
3815 /* Only logon to networked drives. */
3816 if (drvtype != DRIVE_REMOTE)
3817 return;
3819 n_slashes = 2;
3820 strncpy (share, path, MAX_UTF8_PATH);
3821 /* Truncate to just server and share name. */
3822 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3824 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3826 *p = '\0';
3827 break;
3831 if (w32_unicode_filenames)
3833 NETRESOURCEW resourcew;
3834 wchar_t share_w[MAX_PATH];
3836 resourcew.dwScope = RESOURCE_GLOBALNET;
3837 resourcew.dwType = RESOURCETYPE_DISK;
3838 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3839 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3840 resourcew.lpLocalName = NULL;
3841 filename_to_utf16 (share, share_w);
3842 resourcew.lpRemoteName = share_w;
3843 resourcew.lpProvider = NULL;
3845 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3847 else
3849 NETRESOURCEA resourcea;
3850 char share_a[MAX_PATH];
3852 resourcea.dwScope = RESOURCE_GLOBALNET;
3853 resourcea.dwType = RESOURCETYPE_DISK;
3854 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3855 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3856 resourcea.lpLocalName = NULL;
3857 filename_to_ansi (share, share_a);
3858 resourcea.lpRemoteName = share_a;
3859 resourcea.lpProvider = NULL;
3861 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3864 switch (val)
3866 case NO_ERROR:
3867 case ERROR_ALREADY_ASSIGNED:
3868 break;
3869 case ERROR_ACCESS_DENIED:
3870 case ERROR_LOGON_FAILURE:
3871 errno = EACCES;
3872 break;
3873 case ERROR_BUSY:
3874 errno = EAGAIN;
3875 break;
3876 case ERROR_BAD_NET_NAME:
3877 case ERROR_NO_NET_OR_BAD_PATH:
3878 case ERROR_NO_NETWORK:
3879 case ERROR_CANCELLED:
3880 default:
3881 errno = ENOENT;
3882 break;
3886 /* Emulate faccessat(2). */
3888 faccessat (int dirfd, const char * path, int mode, int flags)
3890 DWORD attributes;
3891 char fullname[MAX_UTF8_PATH];
3893 /* Rely on a hack: an open directory is modeled as file descriptor 0,
3894 and its actual file name is stored in dir_pathname by opendir.
3895 This is good enough for the current usage in Emacs, but is fragile. */
3896 if (dirfd != AT_FDCWD
3897 && !(IS_DIRECTORY_SEP (path[0])
3898 || IS_DEVICE_SEP (path[1])))
3900 char lastc = dir_pathname[strlen (dir_pathname) - 1];
3902 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
3903 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", path)
3904 < 0)
3906 errno = ENAMETOOLONG;
3907 return -1;
3909 path = fullname;
3912 /* When dired.c calls us with F_OK and a trailing slash, it actually
3913 wants to know whether PATH is a directory. */
3914 if (IS_DIRECTORY_SEP (path[strlen (path) - 1]) && mode == F_OK)
3915 mode |= D_OK;
3917 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3918 newer versions blow up when passed D_OK. */
3919 path = map_w32_filename (path, NULL);
3920 /* If the last element of PATH is a symlink, we need to resolve it
3921 to get the attributes of its target file. Note: any symlinks in
3922 PATH elements other than the last one are transparently resolved
3923 by GetFileAttributes below. */
3924 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3925 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3926 path = chase_symlinks (path);
3928 if (w32_unicode_filenames)
3930 wchar_t path_w[MAX_PATH];
3932 filename_to_utf16 (path, path_w);
3933 attributes = GetFileAttributesW (path_w);
3935 else
3937 char path_a[MAX_PATH];
3939 filename_to_ansi (path, path_a);
3940 attributes = GetFileAttributesA (path_a);
3943 if (attributes == -1)
3945 DWORD w32err = GetLastError ();
3947 switch (w32err)
3949 case ERROR_INVALID_NAME:
3950 case ERROR_BAD_PATHNAME:
3951 if (is_unc_volume (path))
3953 attributes = unc_volume_file_attributes (path);
3954 if (attributes == -1)
3956 errno = EACCES;
3957 return -1;
3959 goto check_attrs;
3961 /* FALLTHROUGH */
3962 FALLTHROUGH;
3963 case ERROR_FILE_NOT_FOUND:
3964 case ERROR_BAD_NETPATH:
3965 errno = ENOENT;
3966 break;
3967 default:
3968 errno = EACCES;
3969 break;
3971 return -1;
3974 check_attrs:
3975 if ((mode & X_OK) != 0
3976 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3978 errno = EACCES;
3979 return -1;
3981 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3983 errno = EACCES;
3984 return -1;
3986 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3988 errno = EACCES;
3989 return -1;
3991 return 0;
3994 /* A special test for DIRNAME being a directory accessible by the
3995 current user. This is needed because the security permissions in
3996 directory's ACLs are not visible in the Posix-style mode bits
3997 returned by 'stat' and in attributes returned by GetFileAttributes.
3998 So a directory would seem like it's readable by the current user,
3999 but will in fact error out with EACCES when they actually try. */
4001 w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
4003 char pattern[MAX_UTF8_PATH];
4004 bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
4005 HANDLE dh;
4007 /* Network volumes need a different reading method. */
4008 if (is_unc_volume (dirname))
4010 void *read_result = NULL;
4011 wchar_t fnw[MAX_PATH];
4012 char fna[MAX_PATH];
4014 dh = open_unc_volume (dirname);
4015 if (dh != INVALID_HANDLE_VALUE)
4017 read_result = read_unc_volume (dh, fnw, fna, MAX_PATH);
4018 close_unc_volume (dh);
4020 /* Treat empty volumes as accessible. */
4021 return read_result != NULL || GetLastError () == ERROR_NO_MORE_ITEMS;
4024 /* Note: map_w32_filename makes sure DIRNAME is not longer than
4025 MAX_UTF8_PATH. */
4026 strcpy (pattern, map_w32_filename (dirname, NULL));
4028 /* Note: No need to resolve symlinks in FILENAME, because FindFirst
4029 opens the directory that is the target of a symlink. */
4030 if (w32_unicode_filenames)
4032 wchar_t pat_w[MAX_PATH + 2];
4033 WIN32_FIND_DATAW dfd_w;
4035 filename_to_utf16 (pattern, pat_w);
4036 if (!last_slash)
4037 wcscat (pat_w, L"\\");
4038 wcscat (pat_w, L"*");
4039 dh = FindFirstFileW (pat_w, &dfd_w);
4041 else
4043 char pat_a[MAX_PATH + 2];
4044 WIN32_FIND_DATAA dfd_a;
4046 filename_to_ansi (pattern, pat_a);
4047 if (!last_slash)
4048 strcpy (pat_a, "\\");
4049 strcat (pat_a, "*");
4050 /* In case DIRNAME cannot be expressed in characters from the
4051 current ANSI codepage. */
4052 if (_mbspbrk (pat_a, "?"))
4053 dh = INVALID_HANDLE_VALUE;
4054 else
4055 dh = FindFirstFileA (pat_a, &dfd_a);
4058 if (dh == INVALID_HANDLE_VALUE)
4059 return 0;
4060 FindClose (dh);
4061 return 1;
4064 /* A version of 'access' to be used locally with file names in
4065 locale-specific encoding. Does not resolve symlinks and does not
4066 support file names on FAT12 and FAT16 volumes, but that's OK, since
4067 we only invoke this function for files inside the Emacs source or
4068 installation tree, on directories (so any symlinks should have the
4069 directory bit set), and on short file names such as "C:/.emacs". */
4070 static int
4071 sys_access (const char *fname, int mode)
4073 char fname_copy[MAX_PATH], *p;
4074 DWORD attributes;
4076 strcpy (fname_copy, fname);
4077 /* Do the equivalent of unixtodos_filename. */
4078 for (p = fname_copy; *p; p = CharNext (p))
4079 if (*p == '/')
4080 *p = '\\';
4082 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
4084 DWORD w32err = GetLastError ();
4086 switch (w32err)
4088 case ERROR_INVALID_NAME:
4089 case ERROR_BAD_PATHNAME:
4090 case ERROR_FILE_NOT_FOUND:
4091 case ERROR_BAD_NETPATH:
4092 errno = ENOENT;
4093 break;
4094 default:
4095 errno = EACCES;
4096 break;
4098 return -1;
4100 if ((mode & X_OK) != 0
4101 && !(is_exec (fname_copy)
4102 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
4104 errno = EACCES;
4105 return -1;
4107 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
4109 errno = EACCES;
4110 return -1;
4112 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
4114 errno = EACCES;
4115 return -1;
4117 return 0;
4120 /* Shadow some MSVC runtime functions to map requests for long filenames
4121 to reasonable short names if necessary. This was originally added to
4122 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
4123 long file names. */
4126 sys_chdir (const char * path)
4128 path = map_w32_filename (path, NULL);
4129 if (w32_unicode_filenames)
4131 wchar_t newdir_w[MAX_PATH];
4133 if (filename_to_utf16 (path, newdir_w) == 0)
4134 return _wchdir (newdir_w);
4135 return -1;
4137 else
4139 char newdir_a[MAX_PATH];
4141 if (filename_to_ansi (path, newdir_a) == 0)
4142 return _chdir (newdir_a);
4143 return -1;
4148 sys_chmod (const char * path, int mode)
4150 path = chase_symlinks (map_w32_filename (path, NULL));
4151 if (w32_unicode_filenames)
4153 wchar_t path_w[MAX_PATH];
4155 filename_to_utf16 (path, path_w);
4156 return _wchmod (path_w, mode);
4158 else
4160 char path_a[MAX_PATH];
4162 filename_to_ansi (path, path_a);
4163 return _chmod (path_a, mode);
4168 sys_creat (const char * path, int mode)
4170 path = map_w32_filename (path, NULL);
4171 if (w32_unicode_filenames)
4173 wchar_t path_w[MAX_PATH];
4175 filename_to_utf16 (path, path_w);
4176 return _wcreat (path_w, mode);
4178 else
4180 char path_a[MAX_PATH];
4182 filename_to_ansi (path, path_a);
4183 return _creat (path_a, mode);
4187 FILE *
4188 sys_fopen (const char * path, const char * mode)
4190 int fd;
4191 int oflag;
4192 const char * mode_save = mode;
4194 /* Force all file handles to be non-inheritable. This is necessary to
4195 ensure child processes don't unwittingly inherit handles that might
4196 prevent future file access. */
4198 if (mode[0] == 'r')
4199 oflag = O_RDONLY;
4200 else if (mode[0] == 'w' || mode[0] == 'a')
4201 oflag = O_WRONLY | O_CREAT | O_TRUNC;
4202 else
4203 return NULL;
4205 /* Only do simplistic option parsing. */
4206 while (*++mode)
4207 if (mode[0] == '+')
4209 oflag &= ~(O_RDONLY | O_WRONLY);
4210 oflag |= O_RDWR;
4212 else if (mode[0] == 'b')
4214 oflag &= ~O_TEXT;
4215 oflag |= O_BINARY;
4217 else if (mode[0] == 't')
4219 oflag &= ~O_BINARY;
4220 oflag |= O_TEXT;
4222 else break;
4224 path = map_w32_filename (path, NULL);
4225 if (w32_unicode_filenames)
4227 wchar_t path_w[MAX_PATH];
4229 filename_to_utf16 (path, path_w);
4230 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
4232 else
4234 char path_a[MAX_PATH];
4236 filename_to_ansi (path, path_a);
4237 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
4239 if (fd < 0)
4240 return NULL;
4242 return _fdopen (fd, mode_save);
4245 /* This only works on NTFS volumes, but is useful to have. */
4247 sys_link (const char * old, const char * new)
4249 HANDLE fileh;
4250 int result = -1;
4251 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
4252 wchar_t oldname_w[MAX_PATH];
4253 char oldname_a[MAX_PATH];
4255 if (old == NULL || new == NULL)
4257 errno = ENOENT;
4258 return -1;
4261 strcpy (oldname, map_w32_filename (old, NULL));
4262 strcpy (newname, map_w32_filename (new, NULL));
4264 if (w32_unicode_filenames)
4266 filename_to_utf16 (oldname, oldname_w);
4267 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
4268 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4270 else
4272 filename_to_ansi (oldname, oldname_a);
4273 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
4274 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4276 if (fileh != INVALID_HANDLE_VALUE)
4278 int wlen;
4280 /* Confusingly, the "alternate" stream name field does not apply
4281 when restoring a hard link, and instead contains the actual
4282 stream data for the link (ie. the name of the link to create).
4283 The WIN32_STREAM_ID structure before the cStreamName field is
4284 the stream header, which is then immediately followed by the
4285 stream data. */
4287 struct {
4288 WIN32_STREAM_ID wid;
4289 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
4290 } data;
4292 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
4293 indicates that flag is unsupported for CP_UTF8, and OTOH says
4294 it is the default anyway. */
4295 wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
4296 data.wid.cStreamName, MAX_PATH);
4297 if (wlen > 0)
4299 LPVOID context = NULL;
4300 DWORD wbytes = 0;
4302 data.wid.dwStreamId = BACKUP_LINK;
4303 data.wid.dwStreamAttributes = 0;
4304 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
4305 data.wid.Size.HighPart = 0;
4306 data.wid.dwStreamNameSize = 0;
4308 if (BackupWrite (fileh, (LPBYTE)&data,
4309 offsetof (WIN32_STREAM_ID, cStreamName)
4310 + data.wid.Size.LowPart,
4311 &wbytes, FALSE, FALSE, &context)
4312 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
4314 /* succeeded */
4315 result = 0;
4317 else
4319 DWORD err = GetLastError ();
4320 DWORD attributes;
4322 switch (err)
4324 case ERROR_ACCESS_DENIED:
4325 /* This is what happens when OLDNAME is a directory,
4326 since Windows doesn't support hard links to
4327 directories. Posix says to set errno to EPERM in
4328 that case. */
4329 if (w32_unicode_filenames)
4330 attributes = GetFileAttributesW (oldname_w);
4331 else
4332 attributes = GetFileAttributesA (oldname_a);
4333 if (attributes != -1
4334 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
4335 errno = EPERM;
4336 else if (attributes == -1
4337 && is_unc_volume (oldname)
4338 && unc_volume_file_attributes (oldname) != -1)
4339 errno = EPERM;
4340 else
4341 errno = EACCES;
4342 break;
4343 case ERROR_TOO_MANY_LINKS:
4344 errno = EMLINK;
4345 break;
4346 case ERROR_NOT_SAME_DEVICE:
4347 errno = EXDEV;
4348 break;
4349 default:
4350 errno = EINVAL;
4351 break;
4356 CloseHandle (fileh);
4358 else
4359 errno = ENOENT;
4361 return result;
4365 sys_mkdir (const char * path, mode_t mode)
4367 path = map_w32_filename (path, NULL);
4369 if (w32_unicode_filenames)
4371 wchar_t path_w[MAX_PATH];
4373 filename_to_utf16 (path, path_w);
4374 return _wmkdir (path_w);
4376 else
4378 char path_a[MAX_PATH];
4380 filename_to_ansi (path, path_a);
4381 return _mkdir (path_a);
4386 sys_open (const char * path, int oflag, int mode)
4388 const char* mpath = map_w32_filename (path, NULL);
4389 int res = -1;
4391 if (w32_unicode_filenames)
4393 wchar_t mpath_w[MAX_PATH];
4395 filename_to_utf16 (mpath, mpath_w);
4396 /* If possible, try to open file without _O_CREAT, to be able to
4397 write to existing hidden and system files. Force all file
4398 handles to be non-inheritable. */
4399 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4400 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4401 if (res < 0)
4402 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4404 else
4406 char mpath_a[MAX_PATH];
4408 filename_to_ansi (mpath, mpath_a);
4409 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4410 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4411 if (res < 0)
4412 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4415 return res;
4419 fchmod (int fd, mode_t mode)
4421 return 0;
4425 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4427 BOOL result;
4428 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4429 int newname_dev;
4430 int oldname_dev;
4431 bool have_temp_a = false;
4433 /* MoveFile on Windows 95 doesn't correctly change the short file name
4434 alias in a number of circumstances (it is not easy to predict when
4435 just by looking at oldname and newname, unfortunately). In these
4436 cases, renaming through a temporary name avoids the problem.
4438 A second problem on Windows 95 is that renaming through a temp name when
4439 newname is uppercase fails (the final long name ends up in
4440 lowercase, although the short alias might be uppercase) UNLESS the
4441 long temp name is not 8.3.
4443 So, on Windows 95 we always rename through a temp name, and we make sure
4444 the temp name has a long extension to ensure correct renaming. */
4446 strcpy (temp, map_w32_filename (oldname, NULL));
4448 /* volume_info is set indirectly by map_w32_filename. */
4449 oldname_dev = volume_info.serialnum;
4451 if (os_subtype == OS_9X)
4453 char * o;
4454 char * p;
4455 int i = 0;
4456 char oldname_a[MAX_PATH];
4458 oldname = map_w32_filename (oldname, NULL);
4459 filename_to_ansi (oldname, oldname_a);
4460 filename_to_ansi (temp, temp_a);
4461 if ((o = strrchr (oldname_a, '\\')))
4462 o++;
4463 else
4464 o = (char *) oldname_a;
4466 if ((p = strrchr (temp_a, '\\')))
4467 p++;
4468 else
4469 p = temp_a;
4473 /* Force temp name to require a manufactured 8.3 alias - this
4474 seems to make the second rename work properly. */
4475 sprintf (p, "_.%s.%d", o, i);
4476 i++;
4477 result = rename (oldname_a, temp_a);
4479 /* This loop must surely terminate! */
4480 while (result < 0 && errno == EEXIST);
4481 if (result < 0)
4482 return -1;
4483 have_temp_a = true;
4486 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4487 (at least if it is a file; don't do this for directories).
4489 Since we mustn't do this if we are just changing the case of the
4490 file name (we would end up deleting the file we are trying to
4491 rename!), we let rename detect if the destination file already
4492 exists - that way we avoid the possible pitfalls of trying to
4493 determine ourselves whether two names really refer to the same
4494 file, which is not always possible in the general case. (Consider
4495 all the permutations of shared or subst'd drives, etc.) */
4497 newname = map_w32_filename (newname, NULL);
4499 /* volume_info is set indirectly by map_w32_filename. */
4500 newname_dev = volume_info.serialnum;
4502 if (w32_unicode_filenames)
4504 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4506 filename_to_utf16 (temp, temp_w);
4507 filename_to_utf16 (newname, newname_w);
4508 result = _wrename (temp_w, newname_w);
4509 if (result < 0)
4511 DWORD w32err = GetLastError ();
4513 if (errno == EACCES
4514 && newname_dev != oldname_dev)
4516 DWORD attributes;
4517 /* The implementation of `rename' on Windows does not return
4518 errno = EXDEV when you are moving a directory to a
4519 different storage device (ex. logical disk). It returns
4520 EACCES instead. So here we handle such situations and
4521 return EXDEV. */
4522 if ((attributes = GetFileAttributesW (temp_w)) != -1
4523 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4524 errno = EXDEV;
4526 else if (errno == EEXIST && force)
4528 DWORD attributes_old;
4529 DWORD attributes_new;
4531 if (_wchmod (newname_w, 0666) != 0)
4532 return result;
4533 attributes_old = GetFileAttributesW (temp_w);
4534 attributes_new = GetFileAttributesW (newname_w);
4535 if (attributes_old != -1 && attributes_new != -1
4536 && ((attributes_old & FILE_ATTRIBUTE_DIRECTORY)
4537 != (attributes_new & FILE_ATTRIBUTE_DIRECTORY)))
4539 if ((attributes_old & FILE_ATTRIBUTE_DIRECTORY) != 0)
4540 errno = ENOTDIR;
4541 else
4542 errno = EISDIR;
4543 return -1;
4545 if ((attributes_new & FILE_ATTRIBUTE_DIRECTORY) != 0)
4547 if (_wrmdir (newname_w) != 0)
4548 return result;
4550 else if (_wunlink (newname_w) != 0)
4551 return result;
4552 result = _wrename (temp_w, newname_w);
4554 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4555 && is_symlink (temp))
4557 /* This is Windows prohibiting the user from creating a
4558 symlink in another place, since that requires
4559 privileges. */
4560 errno = EPERM;
4564 else
4566 char newname_a[MAX_PATH];
4568 if (!have_temp_a)
4569 filename_to_ansi (temp, temp_a);
4570 filename_to_ansi (newname, newname_a);
4571 result = rename (temp_a, newname_a);
4572 if (result < 0)
4574 DWORD w32err = GetLastError ();
4576 if (errno == EACCES
4577 && newname_dev != oldname_dev)
4579 DWORD attributes;
4580 if ((attributes = GetFileAttributesA (temp_a)) != -1
4581 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4582 errno = EXDEV;
4584 else if (errno == EEXIST && force)
4586 DWORD attributes_old;
4587 DWORD attributes_new;
4589 if (_chmod (newname_a, 0666) != 0)
4590 return result;
4591 attributes_old = GetFileAttributesA (temp_a);
4592 attributes_new = GetFileAttributesA (newname_a);
4593 if (attributes_old != -1 && attributes_new != -1
4594 && ((attributes_old & FILE_ATTRIBUTE_DIRECTORY)
4595 != (attributes_new & FILE_ATTRIBUTE_DIRECTORY)))
4597 if ((attributes_old & FILE_ATTRIBUTE_DIRECTORY) != 0)
4598 errno = ENOTDIR;
4599 else
4600 errno = EISDIR;
4601 return -1;
4603 if ((attributes_new & FILE_ATTRIBUTE_DIRECTORY) != 0)
4605 if (_rmdir (newname_a) != 0)
4606 return result;
4608 else if (_unlink (newname_a) != 0)
4609 return result;
4610 result = rename (temp_a, newname_a);
4612 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4613 && is_symlink (temp))
4614 errno = EPERM;
4618 return result;
4622 sys_rename (char const *old, char const *new)
4624 return sys_rename_replace (old, new, TRUE);
4628 sys_rmdir (const char * path)
4630 path = map_w32_filename (path, NULL);
4632 if (w32_unicode_filenames)
4634 wchar_t path_w[MAX_PATH];
4636 filename_to_utf16 (path, path_w);
4637 return _wrmdir (path_w);
4639 else
4641 char path_a[MAX_PATH];
4643 filename_to_ansi (path, path_a);
4644 return _rmdir (path_a);
4649 sys_unlink (const char * path)
4651 int rmstatus, e;
4653 path = map_w32_filename (path, NULL);
4655 if (w32_unicode_filenames)
4657 wchar_t path_w[MAX_PATH];
4659 filename_to_utf16 (path, path_w);
4660 /* On Unix, unlink works without write permission. */
4661 _wchmod (path_w, 0666);
4662 rmstatus = _wunlink (path_w);
4663 e = errno;
4664 /* Symlinks to directories can only be deleted by _rmdir;
4665 _unlink returns EACCES. */
4666 if (rmstatus != 0
4667 && errno == EACCES
4668 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4669 rmstatus = _wrmdir (path_w);
4670 else
4671 errno = e;
4673 else
4675 char path_a[MAX_PATH];
4677 filename_to_ansi (path, path_a);
4678 _chmod (path_a, 0666);
4679 rmstatus = _unlink (path_a);
4680 e = errno;
4681 if (rmstatus != 0
4682 && errno == EACCES
4683 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4684 rmstatus = _rmdir (path_a);
4685 else
4686 errno = e;
4689 return rmstatus;
4692 static FILETIME utc_base_ft;
4693 static ULONGLONG utc_base; /* In 100ns units */
4694 static int init = 0;
4696 #define FILETIME_TO_U64(result, ft) \
4697 do { \
4698 ULARGE_INTEGER uiTemp; \
4699 uiTemp.LowPart = (ft).dwLowDateTime; \
4700 uiTemp.HighPart = (ft).dwHighDateTime; \
4701 result = uiTemp.QuadPart; \
4702 } while (0)
4704 static void
4705 initialize_utc_base (void)
4707 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4708 SYSTEMTIME st;
4710 st.wYear = 1970;
4711 st.wMonth = 1;
4712 st.wDay = 1;
4713 st.wHour = 0;
4714 st.wMinute = 0;
4715 st.wSecond = 0;
4716 st.wMilliseconds = 0;
4718 SystemTimeToFileTime (&st, &utc_base_ft);
4719 FILETIME_TO_U64 (utc_base, utc_base_ft);
4722 static time_t
4723 convert_time (FILETIME ft)
4725 ULONGLONG tmp;
4727 if (!init)
4729 initialize_utc_base ();
4730 init = 1;
4733 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4734 return 0;
4736 FILETIME_TO_U64 (tmp, ft);
4737 return (time_t) ((tmp - utc_base) / 10000000L);
4740 static void
4741 convert_from_time_t (time_t time, FILETIME * pft)
4743 ULARGE_INTEGER tmp;
4745 if (!init)
4747 initialize_utc_base ();
4748 init = 1;
4751 /* time in 100ns units since 1-Jan-1601 */
4752 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4753 pft->dwHighDateTime = tmp.HighPart;
4754 pft->dwLowDateTime = tmp.LowPart;
4757 static PSECURITY_DESCRIPTOR
4758 get_file_security_desc_by_handle (HANDLE h)
4760 PSECURITY_DESCRIPTOR psd = NULL;
4761 DWORD err;
4762 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4763 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4765 err = get_security_info (h, SE_FILE_OBJECT, si,
4766 NULL, NULL, NULL, NULL, &psd);
4767 if (err != ERROR_SUCCESS)
4768 return NULL;
4770 return psd;
4773 static PSECURITY_DESCRIPTOR
4774 get_file_security_desc_by_name (const char *fname)
4776 PSECURITY_DESCRIPTOR psd = NULL;
4777 DWORD sd_len, err;
4778 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4779 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4781 if (!get_file_security (fname, si, psd, 0, &sd_len))
4783 err = GetLastError ();
4784 if (err != ERROR_INSUFFICIENT_BUFFER)
4785 return NULL;
4788 psd = xmalloc (sd_len);
4789 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4791 xfree (psd);
4792 return NULL;
4795 return psd;
4798 static DWORD
4799 get_rid (PSID sid)
4801 unsigned n_subauthorities;
4803 /* Use the last sub-authority value of the RID, the relative
4804 portion of the SID, as user/group ID. */
4805 n_subauthorities = *get_sid_sub_authority_count (sid);
4806 if (n_subauthorities < 1)
4807 return 0; /* the "World" RID */
4808 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4811 /* Caching SID and account values for faster lokup. */
4813 struct w32_id {
4814 unsigned rid;
4815 struct w32_id *next;
4816 char name[GNLEN+1];
4817 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4820 static struct w32_id *w32_idlist;
4822 static int
4823 w32_cached_id (PSID sid, unsigned *id, char *name)
4825 struct w32_id *tail, *found;
4827 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4829 if (equal_sid ((PSID)tail->sid, sid))
4831 found = tail;
4832 break;
4835 if (found)
4837 *id = found->rid;
4838 strcpy (name, found->name);
4839 return 1;
4841 else
4842 return 0;
4845 static void
4846 w32_add_to_cache (PSID sid, unsigned id, char *name)
4848 DWORD sid_len;
4849 struct w32_id *new_entry;
4851 /* We don't want to leave behind stale cache from when Emacs was
4852 dumped. */
4853 if (initialized)
4855 sid_len = get_length_sid (sid);
4856 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4857 if (new_entry)
4859 new_entry->rid = id;
4860 strcpy (new_entry->name, name);
4861 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4862 new_entry->next = w32_idlist;
4863 w32_idlist = new_entry;
4868 #define UID 1
4869 #define GID 2
4871 static int
4872 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4874 PSID sid = NULL;
4875 BOOL dflt;
4876 SID_NAME_USE ignore;
4877 char name[UNLEN+1];
4878 DWORD name_len = sizeof (name);
4879 char domain[1024];
4880 DWORD domain_len = sizeof (domain);
4881 int use_dflt = 0;
4882 int result;
4884 if (what == UID)
4885 result = get_security_descriptor_owner (psd, &sid, &dflt);
4886 else if (what == GID)
4887 result = get_security_descriptor_group (psd, &sid, &dflt);
4888 else
4889 result = 0;
4891 if (!result || !is_valid_sid (sid))
4892 use_dflt = 1;
4893 else if (!w32_cached_id (sid, id, nm))
4895 if (!lookup_account_sid (NULL, sid, name, &name_len,
4896 domain, &domain_len, &ignore)
4897 || name_len > UNLEN+1)
4898 use_dflt = 1;
4899 else
4901 *id = get_rid (sid);
4902 strcpy (nm, name);
4903 w32_add_to_cache (sid, *id, name);
4906 return use_dflt;
4909 static void
4910 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4912 int dflt_usr = 0, dflt_grp = 0;
4914 if (!psd)
4916 dflt_usr = 1;
4917 dflt_grp = 1;
4919 else
4921 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4922 dflt_usr = 1;
4923 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4924 dflt_grp = 1;
4926 /* Consider files to belong to current user/group, if we cannot get
4927 more accurate information. */
4928 if (dflt_usr)
4930 st->st_uid = dflt_passwd.pw_uid;
4931 strcpy (st->st_uname, dflt_passwd.pw_name);
4933 if (dflt_grp)
4935 st->st_gid = dflt_passwd.pw_gid;
4936 strcpy (st->st_gname, dflt_group.gr_name);
4940 /* Return non-zero if NAME is a potentially slow filesystem. */
4941 int is_slow_fs (const char *);
4944 is_slow_fs (const char *name)
4946 char drive_root[4];
4947 UINT devtype;
4949 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4950 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4951 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4952 devtype = GetDriveType (NULL); /* use root of current drive */
4953 else
4955 /* GetDriveType needs the root directory of the drive. */
4956 strncpy (drive_root, name, 2);
4957 drive_root[2] = '\\';
4958 drive_root[3] = '\0';
4959 devtype = GetDriveType (drive_root);
4961 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4964 /* If this is non-zero, the caller wants accurate information about
4965 file's owner and group, which could be expensive to get. dired.c
4966 uses this flag when needed for the job at hand. */
4967 int w32_stat_get_owner_group;
4969 /* MSVC stat function can't cope with UNC names and has other bugs, so
4970 replace it with our own. This also allows us to calculate consistent
4971 inode values and owner/group without hacks in the main Emacs code,
4972 and support file names encoded in UTF-8. */
4974 static int
4975 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4977 char *name, *save_name, *r;
4978 WIN32_FIND_DATAW wfd_w;
4979 WIN32_FIND_DATAA wfd_a;
4980 HANDLE fh;
4981 unsigned __int64 fake_inode = 0;
4982 int permission;
4983 int len;
4984 int rootdir = FALSE;
4985 PSECURITY_DESCRIPTOR psd = NULL;
4986 int is_a_symlink = 0;
4987 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4988 DWORD access_rights = 0;
4989 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4990 FILETIME ctime, atime, wtime;
4991 wchar_t name_w[MAX_PATH];
4992 char name_a[MAX_PATH];
4994 if (path == NULL || buf == NULL)
4996 errno = EFAULT;
4997 return -1;
5000 save_name = name = (char *) map_w32_filename (path, &path);
5001 /* Must be valid filename, no wild cards or other invalid
5002 characters. */
5003 if (strpbrk (name, "*?|<>\""))
5005 errno = ENOENT;
5006 return -1;
5009 len = strlen (name);
5010 /* Allocate 1 extra byte so that we could append a slash to a root
5011 directory, down below. */
5012 name = strcpy (alloca (len + 2), name);
5014 /* Avoid a somewhat costly call to is_symlink if the filesystem
5015 doesn't support symlinks. */
5016 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5017 is_a_symlink = is_symlink (name);
5019 /* Plan A: Open the file and get all the necessary information via
5020 the resulting handle. This solves several issues in one blow:
5022 . retrieves attributes for the target of a symlink, if needed
5023 . gets attributes of root directories and symlinks pointing to
5024 root directories, thus avoiding the need for special-casing
5025 these and detecting them by examining the file-name format
5026 . retrieves more accurate attributes (e.g., non-zero size for
5027 some directories, esp. directories that are junction points)
5028 . correctly resolves "c:/..", "/.." and similar file names
5029 . avoids run-time penalties for 99% of use cases
5031 Plan A is always tried first, unless the user asked not to (but
5032 if the file is a symlink and we need to follow links, we try Plan
5033 A even if the user asked not to).
5035 If Plan A fails, we go to Plan B (below), where various
5036 potentially expensive techniques must be used to handle "special"
5037 files such as UNC volumes etc. */
5038 if (!(NILP (Vw32_get_true_file_attributes)
5039 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
5040 /* Following symlinks requires getting the info by handle. */
5041 || (is_a_symlink && follow_symlinks))
5043 BY_HANDLE_FILE_INFORMATION info;
5045 if (is_a_symlink && !follow_symlinks)
5046 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
5047 /* READ_CONTROL access rights are required to get security info
5048 by handle. But if the OS doesn't support security in the
5049 first place, we don't need to try. */
5050 if (is_windows_9x () != TRUE)
5051 access_rights |= READ_CONTROL;
5053 if (w32_unicode_filenames)
5055 filename_to_utf16 (name, name_w);
5056 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
5057 file_flags, NULL);
5058 /* If CreateFile fails with READ_CONTROL, try again with
5059 zero as access rights. */
5060 if (fh == INVALID_HANDLE_VALUE && access_rights)
5061 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
5062 file_flags, NULL);
5064 else
5066 filename_to_ansi (name, name_a);
5067 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
5068 file_flags, NULL);
5069 if (fh == INVALID_HANDLE_VALUE && access_rights)
5070 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
5071 file_flags, NULL);
5073 if (fh == INVALID_HANDLE_VALUE)
5074 goto no_true_file_attributes;
5076 /* This is more accurate in terms of getting the correct number
5077 of links, but is quite slow (it is noticeable when Emacs is
5078 making a list of file name completions). */
5079 if (GetFileInformationByHandle (fh, &info))
5081 nlinks = info.nNumberOfLinks;
5082 /* Might as well use file index to fake inode values, but this
5083 is not guaranteed to be unique unless we keep a handle open
5084 all the time (even then there are situations where it is
5085 not unique). Reputedly, there are at most 48 bits of info
5086 (on NTFS, presumably less on FAT). */
5087 fake_inode = info.nFileIndexHigh;
5088 fake_inode <<= 32;
5089 fake_inode += info.nFileIndexLow;
5090 serialnum = info.dwVolumeSerialNumber;
5091 fs_high = info.nFileSizeHigh;
5092 fs_low = info.nFileSizeLow;
5093 ctime = info.ftCreationTime;
5094 atime = info.ftLastAccessTime;
5095 wtime = info.ftLastWriteTime;
5096 fattrs = info.dwFileAttributes;
5098 else
5100 /* We don't go to Plan B here, because it's not clear that
5101 it's a good idea. The only known use case where
5102 CreateFile succeeds, but GetFileInformationByHandle fails
5103 (with ERROR_INVALID_FUNCTION) is for character devices
5104 such as NUL, PRN, etc. For these, switching to Plan B is
5105 a net loss, because we lose the character device
5106 attribute returned by GetFileType below (FindFirstFile
5107 doesn't set that bit in the attributes), and the other
5108 fields don't make sense for character devices anyway.
5109 Emacs doesn't really care for non-file entities in the
5110 context of l?stat, so neither do we. */
5112 /* w32err is assigned so one could put a breakpoint here and
5113 examine its value, when GetFileInformationByHandle
5114 fails. */
5115 DWORD w32err = GetLastError ();
5117 switch (w32err)
5119 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
5120 errno = ENOENT;
5121 return -1;
5125 /* Test for a symlink before testing for a directory, since
5126 symlinks to directories have the directory bit set, but we
5127 don't want them to appear as directories. */
5128 if (is_a_symlink && !follow_symlinks)
5129 buf->st_mode = S_IFLNK;
5130 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5131 buf->st_mode = S_IFDIR;
5132 else
5134 DWORD ftype = GetFileType (fh);
5136 switch (ftype)
5138 case FILE_TYPE_DISK:
5139 buf->st_mode = S_IFREG;
5140 break;
5141 case FILE_TYPE_PIPE:
5142 buf->st_mode = S_IFIFO;
5143 break;
5144 case FILE_TYPE_CHAR:
5145 case FILE_TYPE_UNKNOWN:
5146 default:
5147 buf->st_mode = S_IFCHR;
5150 /* We produce the fallback owner and group data, based on the
5151 current user that runs Emacs, in the following cases:
5153 . caller didn't request owner and group info
5154 . this is Windows 9X
5155 . getting security by handle failed, and we need to produce
5156 information for the target of a symlink (this is better
5157 than producing a potentially misleading info about the
5158 symlink itself)
5160 If getting security by handle fails, and we don't need to
5161 resolve symlinks, we try getting security by name. */
5162 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5163 get_file_owner_and_group (NULL, buf);
5164 else
5166 psd = get_file_security_desc_by_handle (fh);
5167 if (psd)
5169 get_file_owner_and_group (psd, buf);
5170 LocalFree (psd);
5172 else if (!(is_a_symlink && follow_symlinks))
5174 psd = get_file_security_desc_by_name (name);
5175 get_file_owner_and_group (psd, buf);
5176 xfree (psd);
5178 else
5179 get_file_owner_and_group (NULL, buf);
5181 CloseHandle (fh);
5183 else
5185 no_true_file_attributes:
5186 /* Plan B: Either getting a handle on the file failed, or the
5187 caller explicitly asked us to not bother making this
5188 information more accurate.
5190 Implementation note: In Plan B, we never bother to resolve
5191 symlinks, even if we got here because we tried Plan A and
5192 failed. That's because, even if the caller asked for extra
5193 precision by setting Vw32_get_true_file_attributes to t,
5194 resolving symlinks requires acquiring a file handle to the
5195 symlink, which we already know will fail. And if the user
5196 did not ask for extra precision, resolving symlinks will fly
5197 in the face of that request, since the user then wants the
5198 lightweight version of the code. */
5199 rootdir = (path >= save_name + len - 1
5200 && (IS_DIRECTORY_SEP (*path) || *path == 0));
5202 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
5203 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
5204 if (IS_DIRECTORY_SEP (r[0])
5205 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
5206 r[1] = r[2] = '\0';
5208 /* Note: If NAME is a symlink to the root of a UNC volume
5209 (i.e. "\\SERVER"), we will not detect that here, and we will
5210 return data about the symlink as result of FindFirst below.
5211 This is unfortunate, but that marginal use case does not
5212 justify a call to chase_symlinks which would impose a penalty
5213 on all the other use cases. (We get here for symlinks to
5214 roots of UNC volumes because CreateFile above fails for them,
5215 unlike with symlinks to root directories X:\ of drives.) */
5216 if (is_unc_volume (name))
5218 fattrs = unc_volume_file_attributes (name);
5219 if (fattrs == -1)
5220 return -1;
5222 ctime = atime = wtime = utc_base_ft;
5224 else if (rootdir)
5226 /* Make sure root directories end in a slash. */
5227 if (!IS_DIRECTORY_SEP (name[len-1]))
5228 strcpy (name + len, "\\");
5229 if (GetDriveType (name) < 2)
5231 errno = ENOENT;
5232 return -1;
5235 fattrs = FILE_ATTRIBUTE_DIRECTORY;
5236 ctime = atime = wtime = utc_base_ft;
5238 else
5240 int have_wfd = -1;
5242 /* Make sure non-root directories do NOT end in a slash,
5243 otherwise FindFirstFile might fail. */
5244 if (IS_DIRECTORY_SEP (name[len-1]))
5245 name[len - 1] = 0;
5247 /* (This is hacky, but helps when doing file completions on
5248 network drives.) Optimize by using information available from
5249 active readdir if possible. */
5250 len = strlen (dir_pathname);
5251 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
5252 len--;
5253 if (dir_find_handle != INVALID_HANDLE_VALUE
5254 && last_dir_find_data != -1
5255 && !(is_a_symlink && follow_symlinks)
5256 /* The 2 file-name comparisons below support only ASCII
5257 characters, and will lose (compare not equal) when
5258 the file names include non-ASCII characters that are
5259 the same but for the case. However, doing this
5260 properly involves: (a) converting both file names to
5261 UTF-16, (b) lower-casing both names using CharLowerW,
5262 and (c) comparing the results; this would be quite a
5263 bit slower, whereas Plan B is for users who want
5264 lightweight albeit inaccurate version of 'stat'. */
5265 && c_strncasecmp (save_name, dir_pathname, len) == 0
5266 && IS_DIRECTORY_SEP (name[len])
5267 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
5269 have_wfd = last_dir_find_data;
5270 /* This was the last entry returned by readdir. */
5271 if (last_dir_find_data == DIR_FIND_DATA_W)
5272 wfd_w = dir_find_data_w;
5273 else
5274 wfd_a = dir_find_data_a;
5276 else
5278 logon_network_drive (name);
5280 if (w32_unicode_filenames)
5282 filename_to_utf16 (name, name_w);
5283 fh = FindFirstFileW (name_w, &wfd_w);
5284 have_wfd = DIR_FIND_DATA_W;
5286 else
5288 filename_to_ansi (name, name_a);
5289 /* If NAME includes characters not representable by
5290 the current ANSI codepage, filename_to_ansi
5291 usually replaces them with a '?'. We don't want
5292 to let FindFirstFileA interpret those as wildcards,
5293 and "succeed", returning us data from some random
5294 file in the same directory. */
5295 if (_mbspbrk (name_a, "?"))
5296 fh = INVALID_HANDLE_VALUE;
5297 else
5298 fh = FindFirstFileA (name_a, &wfd_a);
5299 have_wfd = DIR_FIND_DATA_A;
5301 if (fh == INVALID_HANDLE_VALUE)
5303 errno = ENOENT;
5304 return -1;
5306 FindClose (fh);
5308 /* Note: if NAME is a symlink, the information we get from
5309 FindFirstFile is for the symlink, not its target. */
5310 if (have_wfd == DIR_FIND_DATA_W)
5312 fattrs = wfd_w.dwFileAttributes;
5313 ctime = wfd_w.ftCreationTime;
5314 atime = wfd_w.ftLastAccessTime;
5315 wtime = wfd_w.ftLastWriteTime;
5316 fs_high = wfd_w.nFileSizeHigh;
5317 fs_low = wfd_w.nFileSizeLow;
5319 else
5321 fattrs = wfd_a.dwFileAttributes;
5322 ctime = wfd_a.ftCreationTime;
5323 atime = wfd_a.ftLastAccessTime;
5324 wtime = wfd_a.ftLastWriteTime;
5325 fs_high = wfd_a.nFileSizeHigh;
5326 fs_low = wfd_a.nFileSizeLow;
5328 fake_inode = 0;
5329 nlinks = 1;
5330 serialnum = volume_info.serialnum;
5332 if (is_a_symlink && !follow_symlinks)
5333 buf->st_mode = S_IFLNK;
5334 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5335 buf->st_mode = S_IFDIR;
5336 else
5337 buf->st_mode = S_IFREG;
5339 get_file_owner_and_group (NULL, buf);
5342 buf->st_ino = fake_inode;
5344 buf->st_dev = serialnum;
5345 buf->st_rdev = serialnum;
5347 buf->st_size = fs_high;
5348 buf->st_size <<= 32;
5349 buf->st_size += fs_low;
5350 buf->st_nlink = nlinks;
5352 /* Convert timestamps to Unix format. */
5353 buf->st_mtime = convert_time (wtime);
5354 buf->st_atime = convert_time (atime);
5355 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5356 buf->st_ctime = convert_time (ctime);
5357 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5359 /* determine rwx permissions */
5360 if (is_a_symlink && !follow_symlinks)
5361 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5362 else
5364 if (fattrs & FILE_ATTRIBUTE_READONLY)
5365 permission = S_IREAD;
5366 else
5367 permission = S_IREAD | S_IWRITE;
5369 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5370 permission |= S_IEXEC;
5371 else if (is_exec (name))
5372 permission |= S_IEXEC;
5375 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5377 return 0;
5381 stat (const char * path, struct stat * buf)
5383 return stat_worker (path, buf, 1);
5387 lstat (const char * path, struct stat * buf)
5389 return stat_worker (path, buf, 0);
5393 fstatat (int fd, char const *name, struct stat *st, int flags)
5395 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5396 This is good enough for the current usage in Emacs, but is fragile.
5398 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5399 Gnulib does this and can serve as a model. */
5400 char fullname[MAX_UTF8_PATH];
5402 if (fd != AT_FDCWD)
5404 char lastc = dir_pathname[strlen (dir_pathname) - 1];
5406 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
5407 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
5408 < 0)
5410 errno = ENAMETOOLONG;
5411 return -1;
5413 name = fullname;
5416 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5419 /* Provide fstat and utime as well as stat for consistent handling of
5420 file timestamps. */
5422 fstat (int desc, struct stat * buf)
5424 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5425 BY_HANDLE_FILE_INFORMATION info;
5426 unsigned __int64 fake_inode;
5427 int permission;
5429 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5431 case FILE_TYPE_DISK:
5432 buf->st_mode = S_IFREG;
5433 if (!GetFileInformationByHandle (fh, &info))
5435 errno = EACCES;
5436 return -1;
5438 break;
5439 case FILE_TYPE_PIPE:
5440 buf->st_mode = S_IFIFO;
5441 goto non_disk;
5442 case FILE_TYPE_CHAR:
5443 case FILE_TYPE_UNKNOWN:
5444 default:
5445 buf->st_mode = S_IFCHR;
5446 non_disk:
5447 memset (&info, 0, sizeof (info));
5448 info.dwFileAttributes = 0;
5449 info.ftCreationTime = utc_base_ft;
5450 info.ftLastAccessTime = utc_base_ft;
5451 info.ftLastWriteTime = utc_base_ft;
5454 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5455 buf->st_mode = S_IFDIR;
5457 buf->st_nlink = info.nNumberOfLinks;
5458 /* Might as well use file index to fake inode values, but this
5459 is not guaranteed to be unique unless we keep a handle open
5460 all the time (even then there are situations where it is
5461 not unique). Reputedly, there are at most 48 bits of info
5462 (on NTFS, presumably less on FAT). */
5463 fake_inode = info.nFileIndexHigh;
5464 fake_inode <<= 32;
5465 fake_inode += info.nFileIndexLow;
5467 /* MSVC defines _ino_t to be short; other libc's might not. */
5468 if (sizeof (buf->st_ino) == 2)
5469 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5470 else
5471 buf->st_ino = fake_inode;
5473 /* If the caller so requested, get the true file owner and group.
5474 Otherwise, consider the file to belong to the current user. */
5475 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5476 get_file_owner_and_group (NULL, buf);
5477 else
5479 PSECURITY_DESCRIPTOR psd = NULL;
5481 psd = get_file_security_desc_by_handle (fh);
5482 if (psd)
5484 get_file_owner_and_group (psd, buf);
5485 LocalFree (psd);
5487 else
5488 get_file_owner_and_group (NULL, buf);
5491 buf->st_dev = info.dwVolumeSerialNumber;
5492 buf->st_rdev = info.dwVolumeSerialNumber;
5494 buf->st_size = info.nFileSizeHigh;
5495 buf->st_size <<= 32;
5496 buf->st_size += info.nFileSizeLow;
5498 /* Convert timestamps to Unix format. */
5499 buf->st_mtime = convert_time (info.ftLastWriteTime);
5500 buf->st_atime = convert_time (info.ftLastAccessTime);
5501 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5502 buf->st_ctime = convert_time (info.ftCreationTime);
5503 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5505 /* determine rwx permissions */
5506 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5507 permission = S_IREAD;
5508 else
5509 permission = S_IREAD | S_IWRITE;
5511 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5512 permission |= S_IEXEC;
5513 else
5515 #if 0 /* no way of knowing the filename */
5516 char * p = strrchr (name, '.');
5517 if (p != NULL &&
5518 (xstrcasecmp (p, ".exe") == 0 ||
5519 xstrcasecmp (p, ".com") == 0 ||
5520 xstrcasecmp (p, ".bat") == 0 ||
5521 xstrcasecmp (p, ".cmd") == 0))
5522 permission |= S_IEXEC;
5523 #endif
5526 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5528 return 0;
5531 /* A version of 'utime' which handles directories as well as
5532 files. */
5535 utime (const char *name, struct utimbuf *times)
5537 struct utimbuf deftime;
5538 HANDLE fh;
5539 FILETIME mtime;
5540 FILETIME atime;
5542 if (times == NULL)
5544 deftime.modtime = deftime.actime = time (NULL);
5545 times = &deftime;
5548 if (w32_unicode_filenames)
5550 wchar_t name_utf16[MAX_PATH];
5552 if (filename_to_utf16 (name, name_utf16) != 0)
5553 return -1; /* errno set by filename_to_utf16 */
5555 /* Need write access to set times. */
5556 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5557 /* If NAME specifies a directory, FILE_SHARE_DELETE
5558 allows other processes to delete files inside it,
5559 while we have the directory open. */
5560 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5561 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5563 else
5565 char name_ansi[MAX_PATH];
5567 if (filename_to_ansi (name, name_ansi) != 0)
5568 return -1; /* errno set by filename_to_ansi */
5570 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5571 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5572 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5574 if (fh != INVALID_HANDLE_VALUE)
5576 convert_from_time_t (times->actime, &atime);
5577 convert_from_time_t (times->modtime, &mtime);
5578 if (!SetFileTime (fh, NULL, &atime, &mtime))
5580 CloseHandle (fh);
5581 errno = EACCES;
5582 return -1;
5584 CloseHandle (fh);
5586 else
5588 DWORD err = GetLastError ();
5590 switch (err)
5592 case ERROR_FILE_NOT_FOUND:
5593 case ERROR_PATH_NOT_FOUND:
5594 case ERROR_INVALID_DRIVE:
5595 case ERROR_BAD_NETPATH:
5596 case ERROR_DEV_NOT_EXIST:
5597 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5598 file name includes ?s, i.e. translation to ANSI failed. */
5599 case ERROR_INVALID_NAME:
5600 errno = ENOENT;
5601 break;
5602 case ERROR_TOO_MANY_OPEN_FILES:
5603 errno = ENFILE;
5604 break;
5605 case ERROR_ACCESS_DENIED:
5606 case ERROR_SHARING_VIOLATION:
5607 errno = EACCES;
5608 break;
5609 default:
5610 errno = EINVAL;
5611 break;
5613 return -1;
5615 return 0;
5619 sys_umask (int mode)
5621 static int current_mask;
5622 int retval, arg = 0;
5624 /* The only bit we really support is the write bit. Files are
5625 always readable on MS-Windows, and the execute bit does not exist
5626 at all. */
5627 /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
5628 to prevent access by other users on NTFS. */
5629 if ((mode & S_IWRITE) != 0)
5630 arg |= S_IWRITE;
5632 retval = _umask (arg);
5633 /* Merge into the return value the bits they've set the last time,
5634 which msvcrt.dll ignores and never returns. Emacs insists on its
5635 notion of mask being identical to what we return. */
5636 retval |= (current_mask & ~S_IWRITE);
5637 current_mask = mode;
5639 return retval;
5643 /* Symlink-related functions. */
5644 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5645 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5646 #endif
5649 symlink (char const *filename, char const *linkname)
5651 char linkfn[MAX_UTF8_PATH], *tgtfn;
5652 DWORD flags = 0;
5653 int dir_access, filename_ends_in_slash;
5655 /* Diagnostics follows Posix as much as possible. */
5656 if (filename == NULL || linkname == NULL)
5658 errno = EFAULT;
5659 return -1;
5661 if (!*filename)
5663 errno = ENOENT;
5664 return -1;
5666 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5668 errno = ENAMETOOLONG;
5669 return -1;
5672 strcpy (linkfn, map_w32_filename (linkname, NULL));
5673 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5675 errno = EPERM;
5676 return -1;
5679 /* Note: since empty FILENAME was already rejected, we can safely
5680 refer to FILENAME[1]. */
5681 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5683 /* Non-absolute FILENAME is understood as being relative to
5684 LINKNAME's directory. We need to prepend that directory to
5685 FILENAME to get correct results from faccessat below, since
5686 otherwise it will interpret FILENAME relative to the
5687 directory where the Emacs process runs. Note that
5688 make-symbolic-link always makes sure LINKNAME is a fully
5689 expanded file name. */
5690 char tem[MAX_UTF8_PATH];
5691 char *p = linkfn + strlen (linkfn);
5693 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5694 p--;
5695 if (p > linkfn)
5696 strncpy (tem, linkfn, p - linkfn);
5697 strcpy (tem + (p - linkfn), filename);
5698 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5700 else
5701 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5703 /* Since Windows distinguishes between symlinks to directories and
5704 to files, we provide a kludgy feature: if FILENAME doesn't
5705 exist, but ends in a slash, we create a symlink to directory. If
5706 FILENAME exists and is a directory, we always create a symlink to
5707 directory. */
5708 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5709 if (dir_access == 0 || filename_ends_in_slash)
5710 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5712 tgtfn = (char *)map_w32_filename (filename, NULL);
5713 if (filename_ends_in_slash)
5714 tgtfn[strlen (tgtfn) - 1] = '\0';
5716 errno = 0;
5717 if (!create_symbolic_link (linkfn, tgtfn, flags))
5719 /* ENOSYS is set by create_symbolic_link, when it detects that
5720 the OS doesn't support the CreateSymbolicLink API. */
5721 if (errno != ENOSYS)
5723 DWORD w32err = GetLastError ();
5725 switch (w32err)
5727 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5728 TGTFN point to the same file name, go figure. */
5729 case ERROR_SUCCESS:
5730 case ERROR_FILE_EXISTS:
5731 errno = EEXIST;
5732 break;
5733 case ERROR_ACCESS_DENIED:
5734 errno = EACCES;
5735 break;
5736 case ERROR_FILE_NOT_FOUND:
5737 case ERROR_PATH_NOT_FOUND:
5738 case ERROR_BAD_NETPATH:
5739 case ERROR_INVALID_REPARSE_DATA:
5740 errno = ENOENT;
5741 break;
5742 case ERROR_DIRECTORY:
5743 errno = EISDIR;
5744 break;
5745 case ERROR_PRIVILEGE_NOT_HELD:
5746 case ERROR_NOT_ALL_ASSIGNED:
5747 errno = EPERM;
5748 break;
5749 case ERROR_DISK_FULL:
5750 errno = ENOSPC;
5751 break;
5752 default:
5753 errno = EINVAL;
5754 break;
5757 return -1;
5759 return 0;
5762 /* A quick inexpensive test of whether FILENAME identifies a file that
5763 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5764 must already be in the normalized form returned by
5765 map_w32_filename. If the symlink is to a directory, the
5766 FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
5768 Note: for repeated operations on many files, it is best to test
5769 whether the underlying volume actually supports symlinks, by
5770 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5771 avoid the call to this function if it doesn't. That's because the
5772 call to GetFileAttributes takes a non-negligible time, especially
5773 on non-local or removable filesystems. See stat_worker for an
5774 example of how to do that. */
5775 static int
5776 is_symlink (const char *filename)
5778 DWORD attrs;
5779 wchar_t filename_w[MAX_PATH];
5780 char filename_a[MAX_PATH];
5781 WIN32_FIND_DATAW wfdw;
5782 WIN32_FIND_DATAA wfda;
5783 HANDLE fh;
5784 int attrs_mean_symlink;
5786 if (w32_unicode_filenames)
5788 filename_to_utf16 (filename, filename_w);
5789 attrs = GetFileAttributesW (filename_w);
5791 else
5793 filename_to_ansi (filename, filename_a);
5794 attrs = GetFileAttributesA (filename_a);
5796 if (attrs == -1)
5798 DWORD w32err = GetLastError ();
5800 switch (w32err)
5802 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5803 break;
5804 case ERROR_ACCESS_DENIED:
5805 errno = EACCES;
5806 break;
5807 case ERROR_FILE_NOT_FOUND:
5808 case ERROR_PATH_NOT_FOUND:
5809 default:
5810 errno = ENOENT;
5811 break;
5813 return 0;
5815 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5816 return 0;
5817 logon_network_drive (filename);
5818 if (w32_unicode_filenames)
5820 fh = FindFirstFileW (filename_w, &wfdw);
5821 attrs_mean_symlink =
5822 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5823 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5824 if (attrs_mean_symlink)
5825 attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5827 else if (_mbspbrk (filename_a, "?"))
5829 /* filename_to_ansi failed to convert the file name. */
5830 errno = ENOENT;
5831 return 0;
5833 else
5835 fh = FindFirstFileA (filename_a, &wfda);
5836 attrs_mean_symlink =
5837 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5838 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5839 if (attrs_mean_symlink)
5840 attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5842 if (fh == INVALID_HANDLE_VALUE)
5843 return 0;
5844 FindClose (fh);
5845 return attrs_mean_symlink;
5848 /* If NAME identifies a symbolic link, copy into BUF the file name of
5849 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5850 null-terminate the target name, even if it fits. Return the number
5851 of bytes copied, or -1 if NAME is not a symlink or any error was
5852 encountered while resolving it. The file name copied into BUF is
5853 encoded in the current ANSI codepage. */
5854 ssize_t
5855 readlink (const char *name, char *buf, size_t buf_size)
5857 const char *path;
5858 TOKEN_PRIVILEGES privs;
5859 int restore_privs = 0;
5860 HANDLE sh;
5861 ssize_t retval;
5862 char resolved[MAX_UTF8_PATH];
5864 if (name == NULL)
5866 errno = EFAULT;
5867 return -1;
5869 if (!*name)
5871 errno = ENOENT;
5872 return -1;
5875 path = map_w32_filename (name, NULL);
5877 if (strlen (path) > MAX_UTF8_PATH)
5879 errno = ENAMETOOLONG;
5880 return -1;
5883 errno = 0;
5884 if (is_windows_9x () == TRUE
5885 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5886 || !is_symlink (path))
5888 if (!errno)
5889 errno = EINVAL; /* not a symlink */
5890 return -1;
5893 /* Done with simple tests, now we're in for some _real_ work. */
5894 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5895 restore_privs = 1;
5896 /* Implementation note: From here and onward, don't return early,
5897 since that will fail to restore the original set of privileges of
5898 the calling thread. */
5900 retval = -1; /* not too optimistic, are we? */
5902 /* Note: In the next call to CreateFile, we use zero as the 2nd
5903 argument because, when the symlink is a hidden/system file,
5904 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5905 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5906 and directory symlinks. */
5907 if (w32_unicode_filenames)
5909 wchar_t path_w[MAX_PATH];
5911 filename_to_utf16 (path, path_w);
5912 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5913 FILE_FLAG_OPEN_REPARSE_POINT
5914 | FILE_FLAG_BACKUP_SEMANTICS,
5915 NULL);
5917 else
5919 char path_a[MAX_PATH];
5921 filename_to_ansi (path, path_a);
5922 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5923 FILE_FLAG_OPEN_REPARSE_POINT
5924 | FILE_FLAG_BACKUP_SEMANTICS,
5925 NULL);
5927 if (sh != INVALID_HANDLE_VALUE)
5929 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5930 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5931 DWORD retbytes;
5933 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5934 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5935 &retbytes, NULL))
5936 errno = EIO;
5937 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5938 errno = EINVAL;
5939 else
5941 /* Copy the link target name, in wide characters, from
5942 reparse_data, then convert it to multibyte encoding in
5943 the current locale's codepage. */
5944 WCHAR *lwname;
5945 size_t lname_size;
5946 USHORT lwname_len =
5947 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5948 WCHAR *lwname_src =
5949 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5950 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5951 size_t size_to_copy = buf_size;
5953 /* According to MSDN, PrintNameLength does not include the
5954 terminating null character. */
5955 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5956 memcpy (lwname, lwname_src, lwname_len);
5957 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5958 filename_from_utf16 (lwname, resolved);
5959 dostounix_filename (resolved);
5960 lname_size = strlen (resolved) + 1;
5961 if (lname_size <= buf_size)
5962 size_to_copy = lname_size;
5963 strncpy (buf, resolved, size_to_copy);
5964 /* Success! */
5965 retval = size_to_copy;
5967 CloseHandle (sh);
5969 else
5971 /* CreateFile failed. */
5972 DWORD w32err2 = GetLastError ();
5974 switch (w32err2)
5976 case ERROR_FILE_NOT_FOUND:
5977 case ERROR_PATH_NOT_FOUND:
5978 errno = ENOENT;
5979 break;
5980 case ERROR_ACCESS_DENIED:
5981 case ERROR_TOO_MANY_OPEN_FILES:
5982 errno = EACCES;
5983 break;
5984 default:
5985 errno = EPERM;
5986 break;
5989 if (restore_privs)
5991 restore_privilege (&privs);
5992 revert_to_self ();
5995 return retval;
5998 ssize_t
5999 readlinkat (int fd, char const *name, char *buffer,
6000 size_t buffer_size)
6002 /* Rely on a hack: an open directory is modeled as file descriptor 0,
6003 as in fstatat. FIXME: Add proper support for readlinkat. */
6004 char fullname[MAX_UTF8_PATH];
6006 if (fd != AT_FDCWD)
6008 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
6009 < 0)
6011 errno = ENAMETOOLONG;
6012 return -1;
6014 name = fullname;
6017 return readlink (name, buffer, buffer_size);
6020 /* If FILE is a symlink, return its target (stored in a static
6021 buffer); otherwise return FILE.
6023 This function repeatedly resolves symlinks in the last component of
6024 a chain of symlink file names, as in foo -> bar -> baz -> ...,
6025 until it arrives at a file whose last component is not a symlink,
6026 or some error occurs. It returns the target of the last
6027 successfully resolved symlink in the chain. If it succeeds to
6028 resolve even a single symlink, the value returned is an absolute
6029 file name with backslashes (result of GetFullPathName). By
6030 contrast, if the original FILE is returned, it is unaltered.
6032 Note: This function can set errno even if it succeeds.
6034 Implementation note: we only resolve the last portion ("basename")
6035 of the argument FILE and of each following file in the chain,
6036 disregarding any possible symlinks in its leading directories.
6037 This is because Windows system calls and library functions
6038 transparently resolve symlinks in leading directories and return
6039 correct information, as long as the basename is not a symlink. */
6040 static char *
6041 chase_symlinks (const char *file)
6043 static char target[MAX_UTF8_PATH];
6044 char link[MAX_UTF8_PATH];
6045 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
6046 char target_a[MAX_PATH], link_a[MAX_PATH];
6047 ssize_t res, link_len;
6048 int loop_count = 0;
6050 if (is_windows_9x () == TRUE || !is_symlink (file))
6051 return (char *)file;
6053 if (w32_unicode_filenames)
6055 wchar_t file_w[MAX_PATH];
6057 filename_to_utf16 (file, file_w);
6058 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
6059 return (char *)file;
6060 filename_from_utf16 (link_w, link);
6062 else
6064 char file_a[MAX_PATH];
6066 filename_to_ansi (file, file_a);
6067 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
6068 return (char *)file;
6069 filename_from_ansi (link_a, link);
6071 link_len = strlen (link);
6073 target[0] = '\0';
6074 do {
6076 /* Remove trailing slashes, as we want to resolve the last
6077 non-trivial part of the link name. */
6078 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
6079 link[link_len--] = '\0';
6081 res = readlink (link, target, MAX_UTF8_PATH);
6082 if (res > 0)
6084 target[res] = '\0';
6085 if (!(IS_DEVICE_SEP (target[1])
6086 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
6088 /* Target is relative. Append it to the directory part of
6089 the symlink, then copy the result back to target. */
6090 char *p = link + link_len;
6092 while (p > link && !IS_ANY_SEP (p[-1]))
6093 p--;
6094 strcpy (p, target);
6095 strcpy (target, link);
6097 /* Resolve any "." and ".." to get a fully-qualified file name
6098 in link[] again. */
6099 if (w32_unicode_filenames)
6101 filename_to_utf16 (target, target_w);
6102 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
6103 if (link_len > 0)
6104 filename_from_utf16 (link_w, link);
6106 else
6108 filename_to_ansi (target, target_a);
6109 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
6110 if (link_len > 0)
6111 filename_from_ansi (link_a, link);
6113 link_len = strlen (link);
6115 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
6117 if (loop_count > 100)
6118 errno = ELOOP;
6120 if (target[0] == '\0') /* not a single call to readlink succeeded */
6121 return (char *)file;
6122 return target;
6126 /* Posix ACL emulation. */
6129 acl_valid (acl_t acl)
6131 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
6134 char *
6135 acl_to_text (acl_t acl, ssize_t *size)
6137 LPTSTR str_acl;
6138 SECURITY_INFORMATION flags =
6139 OWNER_SECURITY_INFORMATION |
6140 GROUP_SECURITY_INFORMATION |
6141 DACL_SECURITY_INFORMATION;
6142 char *retval = NULL;
6143 ULONG local_size;
6144 int e = errno;
6146 errno = 0;
6148 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
6150 errno = e;
6151 /* We don't want to mix heaps, so we duplicate the string in our
6152 heap and free the one allocated by the API. */
6153 retval = xstrdup (str_acl);
6154 if (size)
6155 *size = local_size;
6156 LocalFree (str_acl);
6158 else if (errno != ENOTSUP)
6159 errno = EINVAL;
6161 return retval;
6164 acl_t
6165 acl_from_text (const char *acl_str)
6167 PSECURITY_DESCRIPTOR psd, retval = NULL;
6168 ULONG sd_size;
6169 int e = errno;
6171 errno = 0;
6173 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
6175 errno = e;
6176 retval = xmalloc (sd_size);
6177 memcpy (retval, psd, sd_size);
6178 LocalFree (psd);
6180 else if (errno != ENOTSUP)
6181 errno = EINVAL;
6183 return retval;
6187 acl_free (void *ptr)
6189 xfree (ptr);
6190 return 0;
6193 acl_t
6194 acl_get_file (const char *fname, acl_type_t type)
6196 PSECURITY_DESCRIPTOR psd = NULL;
6197 const char *filename;
6199 if (type == ACL_TYPE_ACCESS)
6201 DWORD sd_len, err;
6202 SECURITY_INFORMATION si =
6203 OWNER_SECURITY_INFORMATION |
6204 GROUP_SECURITY_INFORMATION |
6205 DACL_SECURITY_INFORMATION ;
6206 int e = errno;
6208 filename = map_w32_filename (fname, NULL);
6209 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6210 fname = chase_symlinks (filename);
6211 else
6212 fname = filename;
6214 errno = 0;
6215 if (!get_file_security (fname, si, psd, 0, &sd_len)
6216 && errno != ENOTSUP)
6218 err = GetLastError ();
6219 if (err == ERROR_INSUFFICIENT_BUFFER)
6221 psd = xmalloc (sd_len);
6222 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
6224 xfree (psd);
6225 errno = EIO;
6226 psd = NULL;
6229 else if (err == ERROR_FILE_NOT_FOUND
6230 || err == ERROR_PATH_NOT_FOUND
6231 /* ERROR_INVALID_NAME is what we get if
6232 w32-unicode-filenames is nil and the file cannot
6233 be encoded in the current ANSI codepage. */
6234 || err == ERROR_INVALID_NAME)
6235 errno = ENOENT;
6236 else
6237 errno = EIO;
6239 else if (!errno)
6240 errno = e;
6242 else if (type != ACL_TYPE_DEFAULT)
6243 errno = EINVAL;
6245 return psd;
6249 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
6251 TOKEN_PRIVILEGES old1, old2;
6252 DWORD err;
6253 int st = 0, retval = -1;
6254 SECURITY_INFORMATION flags = 0;
6255 PSID psidOwner, psidGroup;
6256 PACL pacl;
6257 BOOL dflt;
6258 BOOL dacl_present;
6259 int e;
6260 const char *filename;
6262 if (acl_valid (acl) != 0
6263 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
6265 errno = EINVAL;
6266 return -1;
6269 if (type == ACL_TYPE_DEFAULT)
6271 errno = ENOSYS;
6272 return -1;
6275 filename = map_w32_filename (fname, NULL);
6276 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6277 fname = chase_symlinks (filename);
6278 else
6279 fname = filename;
6281 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
6282 &dflt)
6283 && psidOwner)
6284 flags |= OWNER_SECURITY_INFORMATION;
6285 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
6286 &dflt)
6287 && psidGroup)
6288 flags |= GROUP_SECURITY_INFORMATION;
6289 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
6290 &pacl, &dflt)
6291 && dacl_present)
6292 flags |= DACL_SECURITY_INFORMATION;
6293 if (!flags)
6294 return 0;
6296 /* According to KB-245153, setting the owner will succeed if either:
6297 (1) the caller is the user who will be the new owner, and has the
6298 SE_TAKE_OWNERSHIP privilege, or
6299 (2) the caller has the SE_RESTORE privilege, in which case she can
6300 set any valid user or group as the owner
6302 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
6303 privileges, and disregard any failures in obtaining them. If
6304 these privileges cannot be obtained, and do not already exist in
6305 the calling thread's security token, this function could fail
6306 with EPERM. */
6307 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
6308 st++;
6309 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
6310 st++;
6312 e = errno;
6313 errno = 0;
6314 /* SetFileSecurity is deprecated by MS, and sometimes fails when
6315 DACL inheritance is involved, but it seems to preserve ownership
6316 better than SetNamedSecurityInfo, which is important e.g., in
6317 copy-file. */
6318 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
6320 err = GetLastError ();
6322 if (errno != ENOTSUP)
6323 err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
6324 psidOwner, psidGroup, pacl, NULL);
6326 else
6327 err = ERROR_SUCCESS;
6328 if (err != ERROR_SUCCESS)
6330 if (errno == ENOTSUP)
6332 else if (err == ERROR_INVALID_OWNER
6333 || err == ERROR_NOT_ALL_ASSIGNED
6334 || err == ERROR_ACCESS_DENIED)
6336 /* Maybe the requested ACL and the one the file already has
6337 are identical, in which case we can silently ignore the
6338 failure. (And no, Windows doesn't.) */
6339 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
6341 errno = EPERM;
6342 if (current_acl)
6344 char *acl_from = acl_to_text (current_acl, NULL);
6345 char *acl_to = acl_to_text (acl, NULL);
6347 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
6349 retval = 0;
6350 errno = e;
6352 if (acl_from)
6353 acl_free (acl_from);
6354 if (acl_to)
6355 acl_free (acl_to);
6356 acl_free (current_acl);
6359 else if (err == ERROR_FILE_NOT_FOUND
6360 || err == ERROR_PATH_NOT_FOUND
6361 /* ERROR_INVALID_NAME is what we get if
6362 w32-unicode-filenames is nil and the file cannot be
6363 encoded in the current ANSI codepage. */
6364 || err == ERROR_INVALID_NAME)
6365 errno = ENOENT;
6366 else
6367 errno = EACCES;
6369 else
6371 retval = 0;
6372 errno = e;
6375 if (st)
6377 if (st >= 2)
6378 restore_privilege (&old2);
6379 restore_privilege (&old1);
6380 revert_to_self ();
6383 return retval;
6386 /* Return true if errno value ERRNUM indicates that ACLs are well
6387 supported on this system. ERRNUM should be an errno value obtained
6388 after an ACL-related system call fails. */
6389 bool
6390 acl_errno_valid (int errnum)
6392 switch (errnum)
6394 case EBUSY:
6395 case EINVAL:
6396 case ENOTSUP:
6397 return false;
6398 default:
6399 return true;
6404 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
6405 have a fixed max size for file names, so we don't need the kind of
6406 alloc/malloc/realloc dance the gnulib version does. We also don't
6407 support FD-relative symlinks. */
6408 char *
6409 careadlinkat (int fd, char const *filename,
6410 char *buffer, size_t buffer_size,
6411 struct allocator const *alloc,
6412 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6414 char linkname[MAX_UTF8_PATH];
6415 ssize_t link_size;
6417 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6419 if (link_size > 0)
6421 char *retval = buffer;
6423 linkname[link_size++] = '\0';
6424 if (link_size > buffer_size)
6425 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6426 if (retval)
6427 memcpy (retval, linkname, link_size);
6429 return retval;
6431 return NULL;
6435 w32_copy_file (const char *from, const char *to,
6436 int keep_time, int preserve_ownership, int copy_acls)
6438 acl_t acl = NULL;
6439 BOOL copy_result;
6440 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6441 char from_a[MAX_PATH], to_a[MAX_PATH];
6443 /* We ignore preserve_ownership for now. */
6444 preserve_ownership = preserve_ownership;
6446 if (copy_acls)
6448 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6449 if (acl == NULL && acl_errno_valid (errno))
6450 return -2;
6452 if (w32_unicode_filenames)
6454 filename_to_utf16 (from, from_w);
6455 filename_to_utf16 (to, to_w);
6456 copy_result = CopyFileW (from_w, to_w, FALSE);
6458 else
6460 filename_to_ansi (from, from_a);
6461 filename_to_ansi (to, to_a);
6462 copy_result = CopyFileA (from_a, to_a, FALSE);
6464 if (!copy_result)
6466 /* CopyFile doesn't set errno when it fails. By far the most
6467 "popular" reason is that the target is read-only. */
6468 DWORD err = GetLastError ();
6470 switch (err)
6472 case ERROR_FILE_NOT_FOUND:
6473 errno = ENOENT;
6474 break;
6475 case ERROR_ACCESS_DENIED:
6476 errno = EACCES;
6477 break;
6478 case ERROR_ENCRYPTION_FAILED:
6479 errno = EIO;
6480 break;
6481 default:
6482 errno = EPERM;
6483 break;
6486 if (acl)
6487 acl_free (acl);
6488 return -1;
6490 /* CopyFile retains the timestamp by default. However, see
6491 "Community Additions" for CopyFile: it sounds like that is not
6492 entirely true. Testing on Windows XP confirms that modified time
6493 is copied, but creation and last-access times are not.
6494 FIXME? */
6495 else if (!keep_time)
6497 struct timespec now;
6498 DWORD attributes;
6500 if (w32_unicode_filenames)
6502 /* Ensure file is writable while its times are set. */
6503 attributes = GetFileAttributesW (to_w);
6504 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6505 now = current_timespec ();
6506 if (set_file_times (-1, to, now, now))
6508 /* Restore original attributes. */
6509 SetFileAttributesW (to_w, attributes);
6510 if (acl)
6511 acl_free (acl);
6512 return -3;
6514 /* Restore original attributes. */
6515 SetFileAttributesW (to_w, attributes);
6517 else
6519 attributes = GetFileAttributesA (to_a);
6520 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6521 now = current_timespec ();
6522 if (set_file_times (-1, to, now, now))
6524 SetFileAttributesA (to_a, attributes);
6525 if (acl)
6526 acl_free (acl);
6527 return -3;
6529 SetFileAttributesA (to_a, attributes);
6532 if (acl != NULL)
6534 bool fail =
6535 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6536 acl_free (acl);
6537 if (fail && acl_errno_valid (errno))
6538 return -4;
6541 return 0;
6545 /* Support for browsing other processes and their attributes. See
6546 process.c for the Lisp bindings. */
6548 /* Helper wrapper functions. */
6550 static HANDLE WINAPI
6551 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6553 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6555 if (g_b_init_create_toolhelp32_snapshot == 0)
6557 g_b_init_create_toolhelp32_snapshot = 1;
6558 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6559 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6560 "CreateToolhelp32Snapshot");
6562 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6564 return INVALID_HANDLE_VALUE;
6566 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6569 static BOOL WINAPI
6570 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6572 static Process32First_Proc s_pfn_Process32_First = NULL;
6574 if (g_b_init_process32_first == 0)
6576 g_b_init_process32_first = 1;
6577 s_pfn_Process32_First = (Process32First_Proc)
6578 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6579 "Process32First");
6581 if (s_pfn_Process32_First == NULL)
6583 return FALSE;
6585 return (s_pfn_Process32_First (hSnapshot, lppe));
6588 static BOOL WINAPI
6589 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6591 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6593 if (g_b_init_process32_next == 0)
6595 g_b_init_process32_next = 1;
6596 s_pfn_Process32_Next = (Process32Next_Proc)
6597 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6598 "Process32Next");
6600 if (s_pfn_Process32_Next == NULL)
6602 return FALSE;
6604 return (s_pfn_Process32_Next (hSnapshot, lppe));
6607 static BOOL WINAPI
6608 open_thread_token (HANDLE ThreadHandle,
6609 DWORD DesiredAccess,
6610 BOOL OpenAsSelf,
6611 PHANDLE TokenHandle)
6613 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6614 HMODULE hm_advapi32 = NULL;
6615 if (is_windows_9x () == TRUE)
6617 SetLastError (ERROR_NOT_SUPPORTED);
6618 return FALSE;
6620 if (g_b_init_open_thread_token == 0)
6622 g_b_init_open_thread_token = 1;
6623 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6624 s_pfn_Open_Thread_Token =
6625 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6627 if (s_pfn_Open_Thread_Token == NULL)
6629 SetLastError (ERROR_NOT_SUPPORTED);
6630 return FALSE;
6632 return (
6633 s_pfn_Open_Thread_Token (
6634 ThreadHandle,
6635 DesiredAccess,
6636 OpenAsSelf,
6637 TokenHandle)
6641 static BOOL WINAPI
6642 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6644 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6645 HMODULE hm_advapi32 = NULL;
6646 if (is_windows_9x () == TRUE)
6648 return FALSE;
6650 if (g_b_init_impersonate_self == 0)
6652 g_b_init_impersonate_self = 1;
6653 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6654 s_pfn_Impersonate_Self =
6655 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6657 if (s_pfn_Impersonate_Self == NULL)
6659 return FALSE;
6661 return s_pfn_Impersonate_Self (ImpersonationLevel);
6664 static BOOL WINAPI
6665 revert_to_self (void)
6667 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6668 HMODULE hm_advapi32 = NULL;
6669 if (is_windows_9x () == TRUE)
6671 return FALSE;
6673 if (g_b_init_revert_to_self == 0)
6675 g_b_init_revert_to_self = 1;
6676 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6677 s_pfn_Revert_To_Self =
6678 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6680 if (s_pfn_Revert_To_Self == NULL)
6682 return FALSE;
6684 return s_pfn_Revert_To_Self ();
6687 static BOOL WINAPI
6688 get_process_memory_info (HANDLE h_proc,
6689 PPROCESS_MEMORY_COUNTERS mem_counters,
6690 DWORD bufsize)
6692 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6693 HMODULE hm_psapi = NULL;
6694 if (is_windows_9x () == TRUE)
6696 return FALSE;
6698 if (g_b_init_get_process_memory_info == 0)
6700 g_b_init_get_process_memory_info = 1;
6701 hm_psapi = LoadLibrary ("Psapi.dll");
6702 if (hm_psapi)
6703 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6704 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6706 if (s_pfn_Get_Process_Memory_Info == NULL)
6708 return FALSE;
6710 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6713 static BOOL WINAPI
6714 get_process_working_set_size (HANDLE h_proc,
6715 PSIZE_T minrss,
6716 PSIZE_T maxrss)
6718 static GetProcessWorkingSetSize_Proc
6719 s_pfn_Get_Process_Working_Set_Size = NULL;
6721 if (is_windows_9x () == TRUE)
6723 return FALSE;
6725 if (g_b_init_get_process_working_set_size == 0)
6727 g_b_init_get_process_working_set_size = 1;
6728 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6729 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6730 "GetProcessWorkingSetSize");
6732 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6734 return FALSE;
6736 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6739 static BOOL WINAPI
6740 global_memory_status (MEMORYSTATUS *buf)
6742 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6744 if (is_windows_9x () == TRUE)
6746 return FALSE;
6748 if (g_b_init_global_memory_status == 0)
6750 g_b_init_global_memory_status = 1;
6751 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6752 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6753 "GlobalMemoryStatus");
6755 if (s_pfn_Global_Memory_Status == NULL)
6757 return FALSE;
6759 return s_pfn_Global_Memory_Status (buf);
6762 static BOOL WINAPI
6763 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6765 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6767 if (is_windows_9x () == TRUE)
6769 return FALSE;
6771 if (g_b_init_global_memory_status_ex == 0)
6773 g_b_init_global_memory_status_ex = 1;
6774 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6775 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6776 "GlobalMemoryStatusEx");
6778 if (s_pfn_Global_Memory_Status_Ex == NULL)
6780 return FALSE;
6782 return s_pfn_Global_Memory_Status_Ex (buf);
6785 Lisp_Object
6786 list_system_processes (void)
6788 Lisp_Object proclist = Qnil;
6789 HANDLE h_snapshot;
6791 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6793 if (h_snapshot != INVALID_HANDLE_VALUE)
6795 PROCESSENTRY32 proc_entry;
6796 DWORD proc_id;
6797 BOOL res;
6799 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6800 for (res = process32_first (h_snapshot, &proc_entry); res;
6801 res = process32_next (h_snapshot, &proc_entry))
6803 proc_id = proc_entry.th32ProcessID;
6804 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6807 CloseHandle (h_snapshot);
6808 proclist = Fnreverse (proclist);
6811 return proclist;
6814 static int
6815 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6817 TOKEN_PRIVILEGES priv;
6818 DWORD priv_size = sizeof (priv);
6819 DWORD opriv_size = sizeof (*old_priv);
6820 HANDLE h_token = NULL;
6821 HANDLE h_thread = GetCurrentThread ();
6822 int ret_val = 0;
6823 BOOL res;
6825 res = open_thread_token (h_thread,
6826 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6827 FALSE, &h_token);
6828 if (!res && GetLastError () == ERROR_NO_TOKEN)
6830 if (impersonate_self (SecurityImpersonation))
6831 res = open_thread_token (h_thread,
6832 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6833 FALSE, &h_token);
6835 if (res)
6837 priv.PrivilegeCount = 1;
6838 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6839 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6840 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6841 old_priv, &opriv_size)
6842 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6843 ret_val = 1;
6845 if (h_token)
6846 CloseHandle (h_token);
6848 return ret_val;
6851 static int
6852 restore_privilege (TOKEN_PRIVILEGES *priv)
6854 DWORD priv_size = sizeof (*priv);
6855 HANDLE h_token = NULL;
6856 int ret_val = 0;
6858 if (open_thread_token (GetCurrentThread (),
6859 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6860 FALSE, &h_token))
6862 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6863 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6864 ret_val = 1;
6866 if (h_token)
6867 CloseHandle (h_token);
6869 return ret_val;
6872 static Lisp_Object
6873 ltime (ULONGLONG time_100ns)
6875 ULONGLONG time_sec = time_100ns / 10000000;
6876 int subsec = time_100ns % 10000000;
6877 return list4i (time_sec >> 16, time_sec & 0xffff,
6878 subsec / 10, subsec % 10 * 100000);
6881 #define U64_TO_LISP_TIME(time) ltime (time)
6883 static int
6884 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6885 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6886 double *pcpu)
6888 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6889 ULONGLONG tem1, tem2, tem3, tem;
6891 if (!h_proc
6892 || !get_process_times_fn
6893 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6894 &ft_kernel, &ft_user))
6895 return 0;
6897 GetSystemTimeAsFileTime (&ft_current);
6899 FILETIME_TO_U64 (tem1, ft_kernel);
6900 *stime = U64_TO_LISP_TIME (tem1);
6902 FILETIME_TO_U64 (tem2, ft_user);
6903 *utime = U64_TO_LISP_TIME (tem2);
6905 tem3 = tem1 + tem2;
6906 *ttime = U64_TO_LISP_TIME (tem3);
6908 FILETIME_TO_U64 (tem, ft_creation);
6909 /* Process no 4 (System) returns zero creation time. */
6910 if (tem)
6911 tem -= utc_base;
6912 *ctime = U64_TO_LISP_TIME (tem);
6914 if (tem)
6916 FILETIME_TO_U64 (tem3, ft_current);
6917 tem = (tem3 - utc_base) - tem;
6919 *etime = U64_TO_LISP_TIME (tem);
6921 if (tem)
6923 *pcpu = 100.0 * (tem1 + tem2) / tem;
6924 if (*pcpu > 100)
6925 *pcpu = 100.0;
6927 else
6928 *pcpu = 0;
6930 return 1;
6933 Lisp_Object
6934 system_process_attributes (Lisp_Object pid)
6936 Lisp_Object attrs = Qnil;
6937 Lisp_Object cmd_str, decoded_cmd, tem;
6938 HANDLE h_snapshot, h_proc;
6939 DWORD proc_id;
6940 int found_proc = 0;
6941 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
6942 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
6943 DWORD glength = sizeof (gname);
6944 HANDLE token = NULL;
6945 SID_NAME_USE user_type;
6946 unsigned char *buf = NULL;
6947 DWORD blen = 0;
6948 TOKEN_USER user_token;
6949 TOKEN_PRIMARY_GROUP group_token;
6950 unsigned euid;
6951 unsigned egid;
6952 PROCESS_MEMORY_COUNTERS mem;
6953 PROCESS_MEMORY_COUNTERS_EX mem_ex;
6954 SIZE_T minrss, maxrss;
6955 MEMORYSTATUS memst;
6956 MEMORY_STATUS_EX memstex;
6957 double totphys = 0.0;
6958 Lisp_Object ctime, stime, utime, etime, ttime;
6959 double pcpu;
6960 BOOL result = FALSE;
6962 CHECK_NUMBER_OR_FLOAT (pid);
6963 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
6965 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6967 if (h_snapshot != INVALID_HANDLE_VALUE)
6969 PROCESSENTRY32 pe;
6970 BOOL res;
6972 pe.dwSize = sizeof (PROCESSENTRY32);
6973 for (res = process32_first (h_snapshot, &pe); res;
6974 res = process32_next (h_snapshot, &pe))
6976 if (proc_id == pe.th32ProcessID)
6978 if (proc_id == 0)
6979 decoded_cmd = build_string ("Idle");
6980 else
6982 /* Decode the command name from locale-specific
6983 encoding. */
6984 cmd_str = build_unibyte_string (pe.szExeFile);
6986 decoded_cmd =
6987 code_convert_string_norecord (cmd_str,
6988 Vlocale_coding_system, 0);
6990 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
6991 attrs = Fcons (Fcons (Qppid,
6992 make_fixnum_or_float (pe.th32ParentProcessID)),
6993 attrs);
6994 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
6995 attrs);
6996 attrs = Fcons (Fcons (Qthcount,
6997 make_fixnum_or_float (pe.cntThreads)),
6998 attrs);
6999 found_proc = 1;
7000 break;
7004 CloseHandle (h_snapshot);
7007 if (!found_proc)
7008 return Qnil;
7010 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
7011 FALSE, proc_id);
7012 /* If we were denied a handle to the process, try again after
7013 enabling the SeDebugPrivilege in our process. */
7014 if (!h_proc)
7016 TOKEN_PRIVILEGES priv_current;
7018 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
7020 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
7021 FALSE, proc_id);
7022 restore_privilege (&priv_current);
7023 revert_to_self ();
7026 if (h_proc)
7028 result = open_process_token (h_proc, TOKEN_QUERY, &token);
7029 if (result)
7031 result = get_token_information (token, TokenUser, NULL, 0, &blen);
7032 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7034 buf = xmalloc (blen);
7035 result = get_token_information (token, TokenUser,
7036 (LPVOID)buf, blen, &needed);
7037 if (result)
7039 memcpy (&user_token, buf, sizeof (user_token));
7040 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
7042 euid = get_rid (user_token.User.Sid);
7043 result = lookup_account_sid (NULL, user_token.User.Sid,
7044 uname, &ulength,
7045 domain, &dlength,
7046 &user_type);
7047 if (result)
7048 w32_add_to_cache (user_token.User.Sid, euid, uname);
7049 else
7051 strcpy (uname, "unknown");
7052 result = TRUE;
7055 ulength = strlen (uname);
7059 if (result)
7061 /* Determine a reasonable euid and gid values. */
7062 if (xstrcasecmp ("administrator", uname) == 0)
7064 euid = 500; /* well-known Administrator uid */
7065 egid = 513; /* well-known None gid */
7067 else
7069 /* Get group id and name. */
7070 result = get_token_information (token, TokenPrimaryGroup,
7071 (LPVOID)buf, blen, &needed);
7072 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7074 buf = xrealloc (buf, blen = needed);
7075 result = get_token_information (token, TokenPrimaryGroup,
7076 (LPVOID)buf, blen, &needed);
7078 if (result)
7080 memcpy (&group_token, buf, sizeof (group_token));
7081 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
7083 egid = get_rid (group_token.PrimaryGroup);
7084 dlength = sizeof (domain);
7085 result =
7086 lookup_account_sid (NULL, group_token.PrimaryGroup,
7087 gname, &glength, NULL, &dlength,
7088 &user_type);
7089 if (result)
7090 w32_add_to_cache (group_token.PrimaryGroup,
7091 egid, gname);
7092 else
7094 strcpy (gname, "None");
7095 result = TRUE;
7098 glength = strlen (gname);
7102 xfree (buf);
7104 if (!result)
7106 if (!is_windows_9x ())
7108 /* We couldn't open the process token, presumably because of
7109 insufficient access rights. Assume this process is run
7110 by the system. */
7111 strcpy (uname, "SYSTEM");
7112 strcpy (gname, "None");
7113 euid = 18; /* SYSTEM */
7114 egid = 513; /* None */
7115 glength = strlen (gname);
7116 ulength = strlen (uname);
7118 /* If we are running under Windows 9X, where security calls are
7119 not supported, we assume all processes are run by the current
7120 user. */
7121 else if (GetUserName (uname, &ulength))
7123 if (xstrcasecmp ("administrator", uname) == 0)
7124 euid = 0;
7125 else
7126 euid = 123;
7127 egid = euid;
7128 strcpy (gname, "None");
7129 glength = strlen (gname);
7130 ulength = strlen (uname);
7132 else
7134 euid = 123;
7135 egid = 123;
7136 strcpy (uname, "administrator");
7137 ulength = strlen (uname);
7138 strcpy (gname, "None");
7139 glength = strlen (gname);
7141 if (token)
7142 CloseHandle (token);
7145 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
7146 tem = make_unibyte_string (uname, ulength);
7147 attrs = Fcons (Fcons (Quser,
7148 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7149 attrs);
7150 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
7151 tem = make_unibyte_string (gname, glength);
7152 attrs = Fcons (Fcons (Qgroup,
7153 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7154 attrs);
7156 if (global_memory_status_ex (&memstex))
7157 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
7158 totphys = memstex.ullTotalPhys / 1024.0;
7159 #else
7160 /* Visual Studio 6 cannot convert an unsigned __int64 type to
7161 double, so we need to do this for it... */
7163 DWORD tot_hi = memstex.ullTotalPhys >> 32;
7164 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
7165 DWORD tot_lo = memstex.ullTotalPhys % 1024;
7167 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
7169 #endif /* __GNUC__ || _MSC_VER >= 1300 */
7170 else if (global_memory_status (&memst))
7171 totphys = memst.dwTotalPhys / 1024.0;
7173 if (h_proc
7174 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
7175 sizeof (mem_ex)))
7177 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7179 attrs = Fcons (Fcons (Qmajflt,
7180 make_fixnum_or_float (mem_ex.PageFaultCount)),
7181 attrs);
7182 attrs = Fcons (Fcons (Qvsize,
7183 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
7184 attrs);
7185 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7186 if (totphys)
7187 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7189 else if (h_proc
7190 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
7192 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7194 attrs = Fcons (Fcons (Qmajflt,
7195 make_fixnum_or_float (mem.PageFaultCount)),
7196 attrs);
7197 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7198 if (totphys)
7199 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7201 else if (h_proc
7202 && get_process_working_set_size (h_proc, &minrss, &maxrss))
7204 DWORD rss = maxrss / 1024;
7206 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
7207 if (totphys)
7208 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7211 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
7213 attrs = Fcons (Fcons (Qutime, utime), attrs);
7214 attrs = Fcons (Fcons (Qstime, stime), attrs);
7215 attrs = Fcons (Fcons (Qtime, ttime), attrs);
7216 attrs = Fcons (Fcons (Qstart, ctime), attrs);
7217 attrs = Fcons (Fcons (Qetime, etime), attrs);
7218 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
7221 /* FIXME: Retrieve command line by walking the PEB of the process. */
7223 if (h_proc)
7224 CloseHandle (h_proc);
7225 return attrs;
7229 w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
7230 unsigned long long *totalswap, unsigned long long *freeswap)
7232 MEMORYSTATUS memst;
7233 MEMORY_STATUS_EX memstex;
7235 /* Use GlobalMemoryStatusEx if available, as it can report more than
7236 2GB of memory. */
7237 if (global_memory_status_ex (&memstex))
7239 *totalram = memstex.ullTotalPhys;
7240 *freeram = memstex.ullAvailPhys;
7241 *totalswap = memstex.ullTotalPageFile;
7242 *freeswap = memstex.ullAvailPageFile;
7243 return 0;
7245 else if (global_memory_status (&memst))
7247 *totalram = memst.dwTotalPhys;
7248 *freeram = memst.dwAvailPhys;
7249 *totalswap = memst.dwTotalPageFile;
7250 *freeswap = memst.dwAvailPageFile;
7251 return 0;
7253 else
7254 return -1;
7258 /* Wrappers for winsock functions to map between our file descriptors
7259 and winsock's handles; also set h_errno for convenience.
7261 To allow Emacs to run on systems which don't have winsock support
7262 installed, we dynamically link to winsock on startup if present, and
7263 otherwise provide the minimum necessary functionality
7264 (eg. gethostname). */
7266 /* function pointers for relevant socket functions */
7267 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
7268 void (PASCAL *pfn_WSASetLastError) (int iError);
7269 int (PASCAL *pfn_WSAGetLastError) (void);
7270 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
7271 int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject,
7272 WSANETWORKEVENTS *NetworkEvents);
7274 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
7275 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
7276 int (PASCAL *pfn_socket) (int af, int type, int protocol);
7277 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
7278 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
7279 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
7280 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
7281 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
7282 int (PASCAL *pfn_closesocket) (SOCKET s);
7283 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
7284 int (PASCAL *pfn_WSACleanup) (void);
7286 u_short (PASCAL *pfn_htons) (u_short hostshort);
7287 u_short (PASCAL *pfn_ntohs) (u_short netshort);
7288 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
7289 int (PASCAL *pfn_gethostname) (char * name, int namelen);
7290 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
7291 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
7292 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
7293 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
7294 const char * optval, int optlen);
7295 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
7296 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
7297 int * namelen);
7298 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
7299 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
7300 struct sockaddr * from, int * fromlen);
7301 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
7302 const struct sockaddr * to, int tolen);
7304 int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
7305 const struct addrinfo *, struct addrinfo **);
7306 void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
7308 /* SetHandleInformation is only needed to make sockets non-inheritable. */
7309 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7310 #ifndef HANDLE_FLAG_INHERIT
7311 #define HANDLE_FLAG_INHERIT 1
7312 #endif
7314 HANDLE winsock_lib;
7315 static int winsock_inuse;
7317 BOOL term_winsock (void);
7319 BOOL
7320 term_winsock (void)
7322 if (winsock_lib != NULL && winsock_inuse == 0)
7324 release_listen_threads ();
7325 /* Not sure what would cause WSAENETDOWN, or even if it can happen
7326 after WSAStartup returns successfully, but it seems reasonable
7327 to allow unloading winsock anyway in that case. */
7328 if (pfn_WSACleanup () == 0 ||
7329 pfn_WSAGetLastError () == WSAENETDOWN)
7331 if (FreeLibrary (winsock_lib))
7332 winsock_lib = NULL;
7333 return TRUE;
7336 return FALSE;
7339 BOOL
7340 init_winsock (int load_now)
7342 WSADATA winsockData;
7344 if (winsock_lib != NULL)
7345 return TRUE;
7347 pfn_SetHandleInformation
7348 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
7349 "SetHandleInformation");
7351 winsock_lib = LoadLibrary ("Ws2_32.dll");
7353 if (winsock_lib != NULL)
7355 /* dynamically link to socket functions */
7357 #define LOAD_PROC(fn) \
7358 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
7359 goto fail;
7361 LOAD_PROC (WSAStartup);
7362 LOAD_PROC (WSASetLastError);
7363 LOAD_PROC (WSAGetLastError);
7364 LOAD_PROC (WSAEventSelect);
7365 LOAD_PROC (WSAEnumNetworkEvents);
7366 LOAD_PROC (WSACreateEvent);
7367 LOAD_PROC (WSACloseEvent);
7368 LOAD_PROC (socket);
7369 LOAD_PROC (bind);
7370 LOAD_PROC (connect);
7371 LOAD_PROC (ioctlsocket);
7372 LOAD_PROC (recv);
7373 LOAD_PROC (send);
7374 LOAD_PROC (closesocket);
7375 LOAD_PROC (shutdown);
7376 LOAD_PROC (htons);
7377 LOAD_PROC (ntohs);
7378 LOAD_PROC (inet_addr);
7379 LOAD_PROC (gethostname);
7380 LOAD_PROC (gethostbyname);
7381 LOAD_PROC (getservbyname);
7382 LOAD_PROC (getpeername);
7383 LOAD_PROC (WSACleanup);
7384 LOAD_PROC (setsockopt);
7385 LOAD_PROC (listen);
7386 LOAD_PROC (getsockname);
7387 LOAD_PROC (accept);
7388 LOAD_PROC (recvfrom);
7389 LOAD_PROC (sendto);
7390 #undef LOAD_PROC
7392 /* Try loading functions not available before XP. */
7393 pfn_getaddrinfo = (void *) GetProcAddress (winsock_lib, "getaddrinfo");
7394 pfn_freeaddrinfo = (void *) GetProcAddress (winsock_lib, "freeaddrinfo");
7395 /* Paranoia: these two functions should go together, so if one
7396 is absent, we cannot use the other. */
7397 if (pfn_getaddrinfo == NULL)
7398 pfn_freeaddrinfo = NULL;
7399 else if (pfn_freeaddrinfo == NULL)
7400 pfn_getaddrinfo = NULL;
7402 /* specify version 1.1 of winsock */
7403 if (pfn_WSAStartup (0x101, &winsockData) == 0)
7405 if (winsockData.wVersion != 0x101)
7406 goto fail;
7408 if (!load_now)
7410 /* Report that winsock exists and is usable, but leave
7411 socket functions disabled. I am assuming that calling
7412 WSAStartup does not require any network interaction,
7413 and in particular does not cause or require a dial-up
7414 connection to be established. */
7416 pfn_WSACleanup ();
7417 FreeLibrary (winsock_lib);
7418 winsock_lib = NULL;
7420 winsock_inuse = 0;
7421 return TRUE;
7424 fail:
7425 FreeLibrary (winsock_lib);
7426 winsock_lib = NULL;
7429 return FALSE;
7433 int h_errno = 0;
7435 /* Function to map winsock error codes to errno codes for those errno
7436 code defined in errno.h (errno values not defined by errno.h are
7437 already in nt/inc/sys/socket.h). */
7438 static void
7439 set_errno (void)
7441 int wsa_err;
7443 h_errno = 0;
7444 if (winsock_lib == NULL)
7445 wsa_err = EINVAL;
7446 else
7447 wsa_err = pfn_WSAGetLastError ();
7449 switch (wsa_err)
7451 case WSAEACCES: errno = EACCES; break;
7452 case WSAEBADF: errno = EBADF; break;
7453 case WSAEFAULT: errno = EFAULT; break;
7454 case WSAEINTR: errno = EINTR; break;
7455 case WSAEINVAL: errno = EINVAL; break;
7456 case WSAEMFILE: errno = EMFILE; break;
7457 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7458 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7459 case WSAEWOULDBLOCK: errno = EWOULDBLOCK; break;
7460 case WSAENOTCONN: errno = ENOTCONN; break;
7461 default: errno = wsa_err; break;
7465 static void
7466 check_errno (void)
7468 h_errno = 0;
7469 if (winsock_lib != NULL)
7470 pfn_WSASetLastError (0);
7473 /* Extend strerror to handle the winsock-specific error codes. */
7474 struct {
7475 int errnum;
7476 const char * msg;
7477 } _wsa_errlist[] = {
7478 {WSAEINTR , "Interrupted function call"},
7479 {WSAEBADF , "Bad file descriptor"},
7480 {WSAEACCES , "Permission denied"},
7481 {WSAEFAULT , "Bad address"},
7482 {WSAEINVAL , "Invalid argument"},
7483 {WSAEMFILE , "Too many open files"},
7485 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7486 {WSAEINPROGRESS , "Operation now in progress"},
7487 {WSAEALREADY , "Operation already in progress"},
7488 {WSAENOTSOCK , "Socket operation on non-socket"},
7489 {WSAEDESTADDRREQ , "Destination address required"},
7490 {WSAEMSGSIZE , "Message too long"},
7491 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7492 {WSAENOPROTOOPT , "Bad protocol option"},
7493 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7494 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7495 {WSAEOPNOTSUPP , "Operation not supported"},
7496 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7497 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7498 {WSAEADDRINUSE , "Address already in use"},
7499 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7500 {WSAENETDOWN , "Network is down"},
7501 {WSAENETUNREACH , "Network is unreachable"},
7502 {WSAENETRESET , "Network dropped connection on reset"},
7503 {WSAECONNABORTED , "Software caused connection abort"},
7504 {WSAECONNRESET , "Connection reset by peer"},
7505 {WSAENOBUFS , "No buffer space available"},
7506 {WSAEISCONN , "Socket is already connected"},
7507 {WSAENOTCONN , "Socket is not connected"},
7508 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7509 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7510 {WSAETIMEDOUT , "Connection timed out"},
7511 {WSAECONNREFUSED , "Connection refused"},
7512 {WSAELOOP , "Network loop"}, /* not sure */
7513 {WSAENAMETOOLONG , "Name is too long"},
7514 {WSAEHOSTDOWN , "Host is down"},
7515 {WSAEHOSTUNREACH , "No route to host"},
7516 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7517 {WSAEPROCLIM , "Too many processes"},
7518 {WSAEUSERS , "Too many users"}, /* not sure */
7519 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7520 {WSAESTALE , "Data is stale"}, /* not sure */
7521 {WSAEREMOTE , "Remote error"}, /* not sure */
7523 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7524 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7525 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7526 {WSAEDISCON , "Graceful shutdown in progress"},
7527 #ifdef WSAENOMORE
7528 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7529 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7530 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7531 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7532 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7533 {WSASYSCALLFAILURE , "System call failure"},
7534 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7535 {WSATYPE_NOT_FOUND , "Class type not found"},
7536 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7537 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7538 {WSAEREFUSED , "Operation refused"}, /* not sure */
7539 #endif
7541 {WSAHOST_NOT_FOUND , "Host not found"},
7542 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7543 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7544 {WSANO_DATA , "Valid name, no data record of requested type"},
7546 {-1, NULL}
7549 char *
7550 sys_strerror (int error_no)
7552 int i;
7553 static char unknown_msg[40];
7555 if (error_no >= 0 && error_no < sys_nerr)
7556 return sys_errlist[error_no];
7558 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7559 if (_wsa_errlist[i].errnum == error_no)
7560 return (char *)_wsa_errlist[i].msg;
7562 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7563 return unknown_msg;
7566 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7567 but I believe the method of keeping the socket handle separate (and
7568 insuring it is not inheritable) is the correct one. */
7570 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7572 static int socket_to_fd (SOCKET s);
7575 sys_socket (int af, int type, int protocol)
7577 SOCKET s;
7579 if (winsock_lib == NULL)
7581 errno = ENETDOWN;
7582 return -1;
7585 check_errno ();
7587 /* call the real socket function */
7588 s = pfn_socket (af, type, protocol);
7590 if (s != INVALID_SOCKET)
7591 return socket_to_fd (s);
7593 set_errno ();
7594 return -1;
7597 /* Convert a SOCKET to a file descriptor. */
7598 static int
7599 socket_to_fd (SOCKET s)
7601 int fd;
7602 child_process * cp;
7604 /* Although under NT 3.5 _open_osfhandle will accept a socket
7605 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7606 that does not work under NT 3.1. However, we can get the same
7607 effect by using a backdoor function to replace an existing
7608 descriptor handle with the one we want. */
7610 /* allocate a file descriptor (with appropriate flags) */
7611 fd = _open ("NUL:", _O_RDWR);
7612 if (fd >= 0)
7614 /* Make a non-inheritable copy of the socket handle. Note
7615 that it is possible that sockets aren't actually kernel
7616 handles, which appears to be the case on Windows 9x when
7617 the MS Proxy winsock client is installed. */
7619 /* Apparently there is a bug in NT 3.51 with some service
7620 packs, which prevents using DuplicateHandle to make a
7621 socket handle non-inheritable (causes WSACleanup to
7622 hang). The work-around is to use SetHandleInformation
7623 instead if it is available and implemented. */
7624 if (pfn_SetHandleInformation)
7626 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7628 else
7630 HANDLE parent = GetCurrentProcess ();
7631 HANDLE new_s = INVALID_HANDLE_VALUE;
7633 if (DuplicateHandle (parent,
7634 (HANDLE) s,
7635 parent,
7636 &new_s,
7638 FALSE,
7639 DUPLICATE_SAME_ACCESS))
7641 /* It is possible that DuplicateHandle succeeds even
7642 though the socket wasn't really a kernel handle,
7643 because a real handle has the same value. So
7644 test whether the new handle really is a socket. */
7645 unsigned long nonblocking = 0;
7646 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7648 pfn_closesocket (s);
7649 s = (SOCKET) new_s;
7651 else
7653 CloseHandle (new_s);
7658 eassert (fd < MAXDESC);
7659 fd_info[fd].hnd = (HANDLE) s;
7661 /* set our own internal flags */
7662 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7664 cp = new_child ();
7665 if (cp)
7667 cp->fd = fd;
7668 cp->status = STATUS_READ_ACKNOWLEDGED;
7670 /* attach child_process to fd_info */
7671 if (fd_info[ fd ].cp != NULL)
7673 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7674 emacs_abort ();
7677 fd_info[ fd ].cp = cp;
7679 /* success! */
7680 winsock_inuse++; /* count open sockets */
7681 return fd;
7684 /* clean up */
7685 _close (fd);
7687 else
7688 pfn_closesocket (s);
7689 errno = EMFILE;
7690 return -1;
7694 sys_bind (int s, const struct sockaddr * addr, int namelen)
7696 if (winsock_lib == NULL)
7698 errno = ENOTSOCK;
7699 return SOCKET_ERROR;
7702 check_errno ();
7703 if (fd_info[s].flags & FILE_SOCKET)
7705 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7706 if (rc == SOCKET_ERROR)
7707 set_errno ();
7708 return rc;
7710 errno = ENOTSOCK;
7711 return SOCKET_ERROR;
7715 sys_connect (int s, const struct sockaddr * name, int namelen)
7717 if (winsock_lib == NULL)
7719 errno = ENOTSOCK;
7720 return SOCKET_ERROR;
7723 check_errno ();
7724 if (fd_info[s].flags & FILE_SOCKET)
7726 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7727 if (rc == SOCKET_ERROR)
7729 set_errno ();
7730 /* If this is a non-blocking 'connect', set the bit in flags
7731 that will tell reader_thread to wait for connection
7732 before trying to read. */
7733 if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0)
7735 errno = EINPROGRESS; /* that's what process.c expects */
7736 fd_info[s].flags |= FILE_CONNECT;
7739 return rc;
7741 errno = ENOTSOCK;
7742 return SOCKET_ERROR;
7745 u_short
7746 sys_htons (u_short hostshort)
7748 return (winsock_lib != NULL) ?
7749 pfn_htons (hostshort) : hostshort;
7752 u_short
7753 sys_ntohs (u_short netshort)
7755 return (winsock_lib != NULL) ?
7756 pfn_ntohs (netshort) : netshort;
7759 unsigned long
7760 sys_inet_addr (const char * cp)
7762 return (winsock_lib != NULL) ?
7763 pfn_inet_addr (cp) : INADDR_NONE;
7767 sys_gethostname (char * name, int namelen)
7769 if (winsock_lib != NULL)
7771 int retval;
7773 check_errno ();
7774 retval = pfn_gethostname (name, namelen);
7775 if (retval == SOCKET_ERROR)
7776 set_errno ();
7777 return retval;
7780 if (namelen > MAX_COMPUTERNAME_LENGTH)
7781 return !GetComputerName (name, (DWORD *)&namelen);
7783 errno = EFAULT;
7784 return SOCKET_ERROR;
7787 struct hostent *
7788 sys_gethostbyname (const char * name)
7790 struct hostent * host;
7791 int h_err = h_errno;
7793 if (winsock_lib == NULL)
7795 h_errno = NO_RECOVERY;
7796 errno = ENETDOWN;
7797 return NULL;
7800 check_errno ();
7801 host = pfn_gethostbyname (name);
7802 if (!host)
7804 set_errno ();
7805 h_errno = errno;
7807 else
7808 h_errno = h_err;
7809 return host;
7812 struct servent *
7813 sys_getservbyname (const char * name, const char * proto)
7815 struct servent * serv;
7817 if (winsock_lib == NULL)
7819 errno = ENETDOWN;
7820 return NULL;
7823 check_errno ();
7824 serv = pfn_getservbyname (name, proto);
7825 if (!serv)
7826 set_errno ();
7827 return serv;
7831 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7833 if (winsock_lib == NULL)
7835 errno = ENETDOWN;
7836 return SOCKET_ERROR;
7839 check_errno ();
7840 if (fd_info[s].flags & FILE_SOCKET)
7842 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7843 if (rc == SOCKET_ERROR)
7844 set_errno ();
7845 return rc;
7847 errno = ENOTSOCK;
7848 return SOCKET_ERROR;
7852 sys_getaddrinfo (const char *node, const char *service,
7853 const struct addrinfo *hints, struct addrinfo **res)
7855 int rc;
7857 if (winsock_lib == NULL)
7859 errno = ENETDOWN;
7860 return SOCKET_ERROR;
7863 check_errno ();
7864 if (pfn_getaddrinfo)
7865 rc = pfn_getaddrinfo (node, service, hints, res);
7866 else
7868 int port = 0;
7869 struct hostent *host_info;
7870 struct gai_storage {
7871 struct addrinfo addrinfo;
7872 struct sockaddr_in sockaddr_in;
7873 } *gai_storage;
7875 /* We don't (yet) support any flags, as Emacs doesn't need that. */
7876 if (hints && hints->ai_flags != 0)
7877 return WSAEINVAL;
7878 /* NODE cannot be NULL, since process.c has fallbacks for that. */
7879 if (!node)
7880 return WSAHOST_NOT_FOUND;
7882 if (service)
7884 const char *protocol =
7885 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
7886 struct servent *srv = sys_getservbyname (service, protocol);
7888 if (srv)
7889 port = srv->s_port;
7890 else if (*service >= '0' && *service <= '9')
7892 char *endp;
7894 port = strtoul (service, &endp, 10);
7895 if (*endp || port > 65536)
7896 return WSAHOST_NOT_FOUND;
7897 port = sys_htons ((unsigned short) port);
7899 else
7900 return WSAHOST_NOT_FOUND;
7903 gai_storage = xzalloc (sizeof *gai_storage);
7904 gai_storage->sockaddr_in.sin_port = port;
7905 host_info = sys_gethostbyname (node);
7906 if (host_info)
7908 memcpy (&gai_storage->sockaddr_in.sin_addr,
7909 host_info->h_addr, host_info->h_length);
7910 gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
7912 else
7914 /* Attempt to interpret host as numeric inet address. */
7915 unsigned long numeric_addr = sys_inet_addr (node);
7917 if (numeric_addr == -1)
7919 free (gai_storage);
7920 return WSAHOST_NOT_FOUND;
7923 memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
7924 sizeof (gai_storage->sockaddr_in.sin_addr));
7925 gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
7928 gai_storage->addrinfo.ai_addr =
7929 (struct sockaddr *)&gai_storage->sockaddr_in;
7930 gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
7931 gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
7932 gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
7933 gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
7934 gai_storage->addrinfo.ai_next = NULL;
7936 *res = &gai_storage->addrinfo;
7937 rc = 0;
7940 return rc;
7943 void
7944 sys_freeaddrinfo (struct addrinfo *ai)
7946 if (winsock_lib == NULL)
7948 errno = ENETDOWN;
7949 return;
7952 check_errno ();
7953 if (pfn_freeaddrinfo)
7954 pfn_freeaddrinfo (ai);
7955 else
7957 eassert (ai->ai_next == NULL);
7958 xfree (ai);
7963 sys_shutdown (int s, int how)
7965 if (winsock_lib == NULL)
7967 errno = ENETDOWN;
7968 return SOCKET_ERROR;
7971 check_errno ();
7972 if (fd_info[s].flags & FILE_SOCKET)
7974 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
7975 if (rc == SOCKET_ERROR)
7976 set_errno ();
7977 return rc;
7979 errno = ENOTSOCK;
7980 return SOCKET_ERROR;
7984 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
7986 if (winsock_lib == NULL)
7988 errno = ENETDOWN;
7989 return SOCKET_ERROR;
7992 check_errno ();
7993 if (fd_info[s].flags & FILE_SOCKET)
7995 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
7996 (const char *)optval, optlen);
7997 if (rc == SOCKET_ERROR)
7998 set_errno ();
7999 return rc;
8001 errno = ENOTSOCK;
8002 return SOCKET_ERROR;
8006 sys_listen (int s, int backlog)
8008 if (winsock_lib == NULL)
8010 errno = ENETDOWN;
8011 return SOCKET_ERROR;
8014 check_errno ();
8015 if (fd_info[s].flags & FILE_SOCKET)
8017 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
8018 if (rc == SOCKET_ERROR)
8019 set_errno ();
8020 else
8021 fd_info[s].flags |= FILE_LISTEN;
8022 return rc;
8024 errno = ENOTSOCK;
8025 return SOCKET_ERROR;
8029 sys_getsockname (int s, struct sockaddr * name, int * namelen)
8031 if (winsock_lib == NULL)
8033 errno = ENETDOWN;
8034 return SOCKET_ERROR;
8037 check_errno ();
8038 if (fd_info[s].flags & FILE_SOCKET)
8040 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
8041 if (rc == SOCKET_ERROR)
8042 set_errno ();
8043 return rc;
8045 errno = ENOTSOCK;
8046 return SOCKET_ERROR;
8050 sys_accept (int s, struct sockaddr * addr, int * addrlen)
8052 if (winsock_lib == NULL)
8054 errno = ENETDOWN;
8055 return -1;
8058 check_errno ();
8059 if (fd_info[s].flags & FILE_LISTEN)
8061 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
8062 int fd = -1;
8063 if (t == INVALID_SOCKET)
8064 set_errno ();
8065 else
8066 fd = socket_to_fd (t);
8068 if (fd >= 0)
8070 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
8071 ResetEvent (fd_info[s].cp->char_avail);
8073 return fd;
8075 errno = ENOTSOCK;
8076 return -1;
8080 sys_recvfrom (int s, char * buf, int len, int flags,
8081 struct sockaddr * from, int * fromlen)
8083 if (winsock_lib == NULL)
8085 errno = ENETDOWN;
8086 return SOCKET_ERROR;
8089 check_errno ();
8090 if (fd_info[s].flags & FILE_SOCKET)
8092 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
8093 if (rc == SOCKET_ERROR)
8094 set_errno ();
8095 return rc;
8097 errno = ENOTSOCK;
8098 return SOCKET_ERROR;
8102 sys_sendto (int s, const char * buf, int len, int flags,
8103 const struct sockaddr * to, int tolen)
8105 if (winsock_lib == NULL)
8107 errno = ENETDOWN;
8108 return SOCKET_ERROR;
8111 check_errno ();
8112 if (fd_info[s].flags & FILE_SOCKET)
8114 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
8115 if (rc == SOCKET_ERROR)
8116 set_errno ();
8117 return rc;
8119 errno = ENOTSOCK;
8120 return SOCKET_ERROR;
8123 /* Windows does not have an fcntl function. Provide an implementation
8124 good enough for Emacs. */
8126 fcntl (int s, int cmd, int options)
8128 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
8129 invoked in a context where fd1 is closed and all descriptors less
8130 than fd1 are open, so sys_dup is an adequate implementation. */
8131 if (cmd == F_DUPFD_CLOEXEC)
8132 return sys_dup (s);
8134 check_errno ();
8135 if (fd_info[s].flags & FILE_SOCKET)
8137 if (winsock_lib == NULL)
8139 errno = ENETDOWN;
8140 return -1;
8143 if (cmd == F_SETFL && options == O_NONBLOCK)
8145 unsigned long nblock = 1;
8146 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
8147 if (rc == SOCKET_ERROR)
8148 set_errno ();
8149 /* Keep track of the fact that we set this to non-blocking. */
8150 fd_info[s].flags |= FILE_NDELAY;
8151 return rc;
8153 else
8155 errno = EINVAL;
8156 return SOCKET_ERROR;
8159 else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE))
8160 == (FILE_PIPE | FILE_WRITE))
8162 /* Force our writes to pipes be non-blocking. */
8163 if (cmd == F_SETFL && options == O_NONBLOCK)
8165 HANDLE h = (HANDLE)_get_osfhandle (s);
8166 DWORD pipe_mode = PIPE_NOWAIT;
8168 if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL))
8170 DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ()));
8171 return SOCKET_ERROR;
8173 fd_info[s].flags |= FILE_NDELAY;
8174 return 0;
8176 else
8178 errno = EINVAL;
8179 return SOCKET_ERROR;
8182 errno = ENOTSOCK;
8183 return SOCKET_ERROR;
8187 /* Shadow main io functions: we need to handle pipes and sockets more
8188 intelligently. */
8191 sys_close (int fd)
8193 int rc;
8195 if (fd < 0)
8197 errno = EBADF;
8198 return -1;
8201 if (fd < MAXDESC && fd_info[fd].cp)
8203 child_process * cp = fd_info[fd].cp;
8205 fd_info[fd].cp = NULL;
8207 if (CHILD_ACTIVE (cp))
8209 /* if last descriptor to active child_process then cleanup */
8210 int i;
8211 for (i = 0; i < MAXDESC; i++)
8213 if (i == fd)
8214 continue;
8215 if (fd_info[i].cp == cp)
8216 break;
8218 if (i == MAXDESC)
8220 if (fd_info[fd].flags & FILE_SOCKET)
8222 if (winsock_lib == NULL) emacs_abort ();
8224 pfn_shutdown (SOCK_HANDLE (fd), 2);
8225 rc = pfn_closesocket (SOCK_HANDLE (fd));
8227 winsock_inuse--; /* count open sockets */
8229 /* If the process handle is NULL, it's either a socket
8230 or serial connection, or a subprocess that was
8231 already reaped by reap_subprocess, but whose
8232 resources were not yet freed, because its output was
8233 not fully read yet by the time it was reaped. (This
8234 usually happens with async subprocesses whose output
8235 is being read by Emacs.) Otherwise, this process was
8236 not reaped yet, so we set its FD to a negative value
8237 to make sure sys_select will eventually get to
8238 calling the SIGCHLD handler for it, which will then
8239 invoke waitpid and reap_subprocess. */
8240 if (cp->procinfo.hProcess == NULL)
8241 delete_child (cp);
8242 else
8243 cp->fd = -1;
8248 if (fd >= 0 && fd < MAXDESC)
8249 fd_info[fd].flags = 0;
8251 /* Note that sockets do not need special treatment here (at least on
8252 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
8253 closesocket is equivalent to CloseHandle, which is to be expected
8254 because socket handles are fully fledged kernel handles. */
8255 rc = _close (fd);
8257 return rc;
8261 sys_dup (int fd)
8263 int new_fd;
8265 new_fd = _dup (fd);
8266 if (new_fd >= 0 && new_fd < MAXDESC)
8268 /* duplicate our internal info as well */
8269 fd_info[new_fd] = fd_info[fd];
8271 return new_fd;
8275 sys_dup2 (int src, int dst)
8277 int rc;
8279 if (dst < 0 || dst >= MAXDESC)
8281 errno = EBADF;
8282 return -1;
8285 /* MS _dup2 seems to have weird side effect when invoked with 2
8286 identical arguments: an attempt to fclose the corresponding stdio
8287 stream after that hangs (we do close standard streams in
8288 init_ntproc). Attempt to avoid that by not calling _dup2 that
8289 way: if SRC is valid, we know that dup2 should be a no-op, so do
8290 nothing and return DST. */
8291 if (src == dst)
8293 if ((HANDLE)_get_osfhandle (src) == INVALID_HANDLE_VALUE)
8295 errno = EBADF;
8296 return -1;
8298 return dst;
8301 /* Make sure we close the destination first if it's a pipe or socket. */
8302 if (fd_info[dst].flags != 0)
8303 sys_close (dst);
8305 rc = _dup2 (src, dst);
8306 if (rc == 0)
8308 /* Duplicate our internal info as well. */
8309 fd_info[dst] = fd_info[src];
8311 return rc == 0 ? dst : rc;
8315 pipe2 (int * phandles, int pipe2_flags)
8317 int rc;
8318 unsigned flags;
8319 unsigned pipe_size = 0;
8321 eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
8323 /* Allow Lisp to override the default buffer size of the pipe. */
8324 if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
8325 pipe_size = w32_pipe_buffer_size;
8327 /* make pipe handles non-inheritable; when we spawn a child, we
8328 replace the relevant handle with an inheritable one. Also put
8329 pipes into binary mode; we will do text mode translation ourselves
8330 if required. */
8331 rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
8333 if (rc == 0)
8335 /* Protect against overflow, since Windows can open more handles than
8336 our fd_info array has room for. */
8337 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
8339 _close (phandles[0]);
8340 _close (phandles[1]);
8341 errno = EMFILE;
8342 rc = -1;
8344 else
8346 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
8347 fd_info[phandles[0]].flags = flags;
8349 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
8350 fd_info[phandles[1]].flags = flags;
8354 return rc;
8357 /* Function to do blocking read of one byte, needed to implement
8358 select. It is only allowed on communication ports, sockets, or
8359 pipes. */
8361 _sys_read_ahead (int fd)
8363 child_process * cp;
8364 int rc;
8366 if (fd < 0 || fd >= MAXDESC)
8367 return STATUS_READ_ERROR;
8369 cp = fd_info[fd].cp;
8371 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8372 return STATUS_READ_ERROR;
8374 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
8375 || (fd_info[fd].flags & FILE_READ) == 0)
8377 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
8378 emacs_abort ();
8381 if ((fd_info[fd].flags & FILE_CONNECT) != 0)
8382 DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd));
8383 cp->status = STATUS_READ_IN_PROGRESS;
8385 if (fd_info[fd].flags & FILE_PIPE)
8387 rc = _read (fd, &cp->chr, sizeof (char));
8389 /* Give subprocess time to buffer some more output for us before
8390 reporting that input is available; we need this because Windows 95
8391 connects DOS programs to pipes by making the pipe appear to be
8392 the normal console stdout - as a result most DOS programs will
8393 write to stdout without buffering, ie. one character at a
8394 time. Even some W32 programs do this - "dir" in a command
8395 shell on NT is very slow if we don't do this. */
8396 if (rc > 0)
8398 int wait = w32_pipe_read_delay;
8400 if (wait > 0)
8401 Sleep (wait);
8402 else if (wait < 0)
8403 while (++wait <= 0)
8404 /* Yield remainder of our time slice, effectively giving a
8405 temporary priority boost to the child process. */
8406 Sleep (0);
8409 else if (fd_info[fd].flags & FILE_SERIAL)
8411 HANDLE hnd = fd_info[fd].hnd;
8412 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8413 COMMTIMEOUTS ct;
8415 /* Configure timeouts for blocking read. */
8416 if (!GetCommTimeouts (hnd, &ct))
8418 cp->status = STATUS_READ_ERROR;
8419 return STATUS_READ_ERROR;
8421 ct.ReadIntervalTimeout = 0;
8422 ct.ReadTotalTimeoutMultiplier = 0;
8423 ct.ReadTotalTimeoutConstant = 0;
8424 if (!SetCommTimeouts (hnd, &ct))
8426 cp->status = STATUS_READ_ERROR;
8427 return STATUS_READ_ERROR;
8430 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
8432 if (GetLastError () != ERROR_IO_PENDING)
8434 cp->status = STATUS_READ_ERROR;
8435 return STATUS_READ_ERROR;
8437 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8439 cp->status = STATUS_READ_ERROR;
8440 return STATUS_READ_ERROR;
8444 else if (fd_info[fd].flags & FILE_SOCKET)
8446 unsigned long nblock = 0;
8447 /* We always want this to block, so temporarily disable NDELAY. */
8448 if (fd_info[fd].flags & FILE_NDELAY)
8449 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8451 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
8453 if (fd_info[fd].flags & FILE_NDELAY)
8455 nblock = 1;
8456 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8460 if (rc == sizeof (char))
8461 cp->status = STATUS_READ_SUCCEEDED;
8462 else
8463 cp->status = STATUS_READ_FAILED;
8465 return cp->status;
8469 _sys_wait_accept (int fd)
8471 HANDLE hEv;
8472 child_process * cp;
8473 int rc;
8475 if (fd < 0 || fd >= MAXDESC)
8476 return STATUS_READ_ERROR;
8478 cp = fd_info[fd].cp;
8480 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8481 return STATUS_READ_ERROR;
8483 cp->status = STATUS_READ_FAILED;
8485 hEv = pfn_WSACreateEvent ();
8486 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
8487 if (rc != SOCKET_ERROR)
8489 do {
8490 rc = WaitForSingleObject (hEv, 500);
8491 Sleep (5);
8492 } while (rc == WAIT_TIMEOUT
8493 && cp->status != STATUS_READ_ERROR
8494 && cp->char_avail);
8495 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8496 if (rc == WAIT_OBJECT_0)
8497 cp->status = STATUS_READ_SUCCEEDED;
8499 pfn_WSACloseEvent (hEv);
8501 return cp->status;
8505 _sys_wait_connect (int fd)
8507 HANDLE hEv;
8508 child_process * cp;
8509 int rc;
8511 if (fd < 0 || fd >= MAXDESC)
8512 return STATUS_READ_ERROR;
8514 cp = fd_info[fd].cp;
8515 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8516 return STATUS_READ_ERROR;
8518 cp->status = STATUS_READ_FAILED;
8520 hEv = pfn_WSACreateEvent ();
8521 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT);
8522 if (rc != SOCKET_ERROR)
8524 do {
8525 rc = WaitForSingleObject (hEv, 500);
8526 Sleep (5);
8527 } while (rc == WAIT_TIMEOUT
8528 && cp->status != STATUS_READ_ERROR
8529 && cp->char_avail);
8530 if (rc == WAIT_OBJECT_0)
8532 /* We've got an event, but it could be a successful
8533 connection, or it could be a failure. Find out
8534 which one is it. */
8535 WSANETWORKEVENTS events;
8537 pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events);
8538 if ((events.lNetworkEvents & FD_CONNECT) != 0
8539 && events.iErrorCode[FD_CONNECT_BIT])
8541 cp->status = STATUS_CONNECT_FAILED;
8542 cp->errcode = events.iErrorCode[FD_CONNECT_BIT];
8544 else
8546 cp->status = STATUS_READ_SUCCEEDED;
8547 cp->errcode = 0;
8550 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8552 else
8553 pfn_WSACloseEvent (hEv);
8555 return cp->status;
8559 sys_read (int fd, char * buffer, unsigned int count)
8561 int nchars;
8562 int to_read;
8563 DWORD waiting;
8564 char * orig_buffer = buffer;
8566 if (fd < 0)
8568 errno = EBADF;
8569 return -1;
8572 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8574 child_process *cp = fd_info[fd].cp;
8576 if ((fd_info[fd].flags & FILE_READ) == 0)
8578 errno = EBADF;
8579 return -1;
8582 nchars = 0;
8584 /* re-read CR carried over from last read */
8585 if (fd_info[fd].flags & FILE_LAST_CR)
8587 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
8588 *buffer++ = 0x0d;
8589 count--;
8590 nchars++;
8591 fd_info[fd].flags &= ~FILE_LAST_CR;
8594 /* presence of a child_process structure means we are operating in
8595 non-blocking mode - otherwise we just call _read directly.
8596 Note that the child_process structure might be missing because
8597 reap_subprocess has been called; in this case the pipe is
8598 already broken, so calling _read on it is okay. */
8599 if (cp)
8601 int current_status = cp->status;
8603 switch (current_status)
8605 case STATUS_READ_FAILED:
8606 case STATUS_READ_ERROR:
8607 /* report normal EOF if nothing in buffer */
8608 if (nchars <= 0)
8609 fd_info[fd].flags |= FILE_AT_EOF;
8610 return nchars;
8612 case STATUS_READ_READY:
8613 case STATUS_READ_IN_PROGRESS:
8614 #if 0
8615 /* This happens all the time during GnuTLS handshake
8616 with the remote, evidently because GnuTLS waits for
8617 the read to complete by retrying the read operation
8618 upon EAGAIN. So I'm disabling the DebPrint to avoid
8619 wasting cycles on something that is not a real
8620 problem. Enable if you need to debug something that
8621 bumps into this. */
8622 DebPrint (("sys_read called when read is in progress %d\n",
8623 current_status));
8624 #endif
8625 errno = EWOULDBLOCK;
8626 return -1;
8628 case STATUS_READ_SUCCEEDED:
8629 /* consume read-ahead char */
8630 *buffer++ = cp->chr;
8631 count--;
8632 nchars++;
8633 cp->status = STATUS_READ_ACKNOWLEDGED;
8634 ResetEvent (cp->char_avail);
8636 case STATUS_READ_ACKNOWLEDGED:
8637 case STATUS_CONNECT_FAILED:
8638 break;
8640 default:
8641 DebPrint (("sys_read: bad status %d\n", current_status));
8642 errno = EBADF;
8643 return -1;
8646 if (fd_info[fd].flags & FILE_PIPE)
8648 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
8649 to_read = min (waiting, (DWORD) count);
8651 if (to_read > 0)
8652 nchars += _read (fd, buffer, to_read);
8654 else if (fd_info[fd].flags & FILE_SERIAL)
8656 HANDLE hnd = fd_info[fd].hnd;
8657 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8658 int rc = 0;
8659 COMMTIMEOUTS ct;
8661 if (count > 0)
8663 /* Configure timeouts for non-blocking read. */
8664 if (!GetCommTimeouts (hnd, &ct))
8666 errno = EIO;
8667 return -1;
8669 ct.ReadIntervalTimeout = MAXDWORD;
8670 ct.ReadTotalTimeoutMultiplier = 0;
8671 ct.ReadTotalTimeoutConstant = 0;
8672 if (!SetCommTimeouts (hnd, &ct))
8674 errno = EIO;
8675 return -1;
8678 if (!ResetEvent (ovl->hEvent))
8680 errno = EIO;
8681 return -1;
8683 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8685 if (GetLastError () != ERROR_IO_PENDING)
8687 errno = EIO;
8688 return -1;
8690 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8692 errno = EIO;
8693 return -1;
8696 nchars += rc;
8699 else /* FILE_SOCKET */
8701 if (winsock_lib == NULL) emacs_abort ();
8703 /* When a non-blocking 'connect' call fails,
8704 wait_reading_process_output detects this by calling
8705 'getpeername', and then attempts to obtain the connection
8706 error code by trying to read 1 byte from the socket. If
8707 we try to serve that read by calling 'recv' below, the
8708 error we get is a generic WSAENOTCONN, not the actual
8709 connection error. So instead, we use the actual error
8710 code stashed by '_sys_wait_connect' in cp->errcode.
8711 Alternatively, we could have used 'getsockopt', like on
8712 GNU/Linux, but: (a) I have no idea whether the winsock
8713 version could hang, as it does "on some systems" (see the
8714 comment in process.c); and (b) 'getsockopt' on Windows is
8715 documented to clear the socket error for the entire
8716 process, which I'm not sure is TRT; FIXME. */
8717 if (current_status == STATUS_CONNECT_FAILED
8718 && (fd_info[fd].flags & FILE_CONNECT) != 0
8719 && cp->errcode != 0)
8721 pfn_WSASetLastError (cp->errcode);
8722 set_errno ();
8723 return -1;
8725 /* Do the equivalent of a non-blocking read. */
8726 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8727 if (waiting == 0 && nchars == 0)
8729 errno = EWOULDBLOCK;
8730 return -1;
8733 if (waiting)
8735 /* always use binary mode for sockets */
8736 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8737 if (res == SOCKET_ERROR)
8739 set_errno ();
8740 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8741 errno, SOCK_HANDLE (fd)));
8742 return -1;
8744 nchars += res;
8748 else
8750 int nread = _read (fd, buffer, count);
8751 if (nread >= 0)
8752 nchars += nread;
8753 else if (nchars == 0)
8754 nchars = nread;
8757 if (nchars <= 0)
8758 fd_info[fd].flags |= FILE_AT_EOF;
8759 /* Perform text mode translation if required. */
8760 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8762 nchars = crlf_to_lf (nchars, orig_buffer);
8763 /* If buffer contains only CR, return that. To be absolutely
8764 sure we should attempt to read the next char, but in
8765 practice a CR to be followed by LF would not appear by
8766 itself in the buffer. */
8767 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8769 fd_info[fd].flags |= FILE_LAST_CR;
8770 nchars--;
8774 else
8775 nchars = _read (fd, buffer, count);
8777 return nchars;
8780 /* From w32xfns.c */
8781 extern HANDLE interrupt_handle;
8784 sys_write (int fd, const void * buffer, unsigned int count)
8786 int nchars;
8787 USE_SAFE_ALLOCA;
8789 if (fd < 0)
8791 errno = EBADF;
8792 return -1;
8795 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8797 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8799 errno = EBADF;
8800 return -1;
8803 /* Perform text mode translation if required. */
8804 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8806 char * tmpbuf;
8807 const unsigned char * src = buffer;
8808 unsigned char * dst;
8809 int nbytes = count;
8811 SAFE_NALLOCA (tmpbuf, 2, count);
8812 dst = (unsigned char *)tmpbuf;
8814 while (1)
8816 unsigned char *next;
8817 /* Copy next line or remaining bytes. */
8818 next = _memccpy (dst, src, '\n', nbytes);
8819 if (next)
8821 /* Copied one line ending with '\n'. */
8822 int copied = next - dst;
8823 nbytes -= copied;
8824 src += copied;
8825 /* Insert '\r' before '\n'. */
8826 next[-1] = '\r';
8827 next[0] = '\n';
8828 dst = next + 1;
8829 count++;
8831 else
8832 /* Copied remaining partial line -> now finished. */
8833 break;
8835 buffer = tmpbuf;
8839 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8841 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8842 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8843 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8844 DWORD active = 0;
8846 /* This is async (a.k.a. "overlapped") I/O, so the return value
8847 of FALSE from WriteFile means either an error or the output
8848 will be completed asynchronously (ERROR_IO_PENDING). */
8849 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8851 if (GetLastError () != ERROR_IO_PENDING)
8853 errno = EIO;
8854 nchars = -1;
8856 else
8858 /* Wait for the write to complete, and watch C-g while
8859 at that. */
8860 if (detect_input_pending ())
8861 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
8862 INFINITE, QS_ALLINPUT);
8863 else
8864 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8865 switch (active)
8867 case WAIT_OBJECT_0:
8868 /* User pressed C-g, cancel write, then leave.
8869 Don't bother cleaning up as we may only get stuck
8870 in buggy drivers. */
8871 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8872 CancelIo (hnd);
8873 errno = EIO; /* Why not EINTR? */
8874 nchars = -1;
8875 break;
8876 case WAIT_OBJECT_0 + 1:
8877 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8879 errno = EIO;
8880 nchars = -1;
8882 break;
8887 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8889 unsigned long nblock = 0;
8890 if (winsock_lib == NULL) emacs_abort ();
8892 child_process *cp = fd_info[fd].cp;
8894 /* If this is a non-blocking socket whose connection is in
8895 progress or terminated with an error already, return the
8896 proper error code to the caller. */
8897 if (cp != NULL && (fd_info[fd].flags & FILE_CONNECT) != 0)
8899 /* In case connection is in progress, ENOTCONN that would
8900 result from calling pfn_send is not what callers expect. */
8901 if (cp->status != STATUS_CONNECT_FAILED)
8903 errno = EWOULDBLOCK;
8904 return -1;
8906 /* In case connection failed, use the actual error code
8907 stashed by '_sys_wait_connect' in cp->errcode. */
8908 else if (cp->errcode != 0)
8910 pfn_WSASetLastError (cp->errcode);
8911 set_errno ();
8912 return -1;
8916 /* TODO: implement select() properly so non-blocking I/O works. */
8917 /* For now, make sure the write blocks. */
8918 if (fd_info[fd].flags & FILE_NDELAY)
8919 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8921 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
8923 if (nchars == SOCKET_ERROR)
8925 set_errno ();
8926 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
8927 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8930 /* Set the socket back to non-blocking if it was before,
8931 for other operations that support it. */
8932 if (fd_info[fd].flags & FILE_NDELAY)
8934 nblock = 1;
8935 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8938 else
8940 /* Some networked filesystems don't like too large writes, so
8941 break them into smaller chunks. See the Comments section of
8942 the MSDN documentation of WriteFile for details behind the
8943 choice of the value of CHUNK below. See also the thread
8944 http://thread.gmane.org/gmane.comp.version-control.git/145294
8945 in the git mailing list. */
8946 const unsigned char *p = buffer;
8947 const bool is_pipe = (fd < MAXDESC
8948 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
8949 == (FILE_PIPE | FILE_NDELAY)));
8950 /* Some programs, notably Node.js's node.exe, seem to never
8951 completely empty the pipe, so writing more than the size of
8952 the pipe's buffer always returns ENOSPC, and we loop forever
8953 between send_process and here. As a workaround, write no
8954 more than the pipe's buffer can hold. */
8955 DWORD pipe_buffer_size;
8956 if (is_pipe)
8958 if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
8959 NULL, &pipe_buffer_size, NULL, NULL))
8961 DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
8962 pipe_buffer_size = 4096;
8965 const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
8967 nchars = 0;
8968 errno = 0;
8969 while (count > 0)
8971 unsigned this_chunk = count < chunk ? count : chunk;
8972 int n = _write (fd, p, this_chunk);
8974 if (n > 0)
8975 nchars += n;
8976 if (n < 0)
8978 /* When there's no buffer space in a pipe that is in the
8979 non-blocking mode, _write returns ENOSPC. We return
8980 EAGAIN instead, which should trigger the logic in
8981 send_process that enters waiting loop and calls
8982 wait_reading_process_output to allow process input to
8983 be accepted during the wait. Those calls to
8984 wait_reading_process_output allow sys_select to
8985 notice when process input becomes available, thus
8986 avoiding deadlock whereby each side of the pipe is
8987 blocked on write, waiting for the other party to read
8988 its end of the pipe. */
8989 if (errno == ENOSPC && is_pipe)
8990 errno = EAGAIN;
8991 if (nchars == 0)
8992 nchars = -1;
8993 break;
8995 else if (n < this_chunk)
8996 break;
8997 count -= n;
8998 p += n;
9002 SAFE_FREE ();
9003 return nchars;
9007 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
9009 /* Return information about network interface IFNAME, or about all
9010 interfaces (if IFNAME is nil). */
9011 static Lisp_Object
9012 network_interface_get_info (Lisp_Object ifname)
9014 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
9015 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
9016 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
9017 Lisp_Object res = Qnil;
9019 if (retval == ERROR_BUFFER_OVERFLOW)
9021 ainfo = xrealloc (ainfo, ainfo_len);
9022 retval = get_adapters_info (ainfo, &ainfo_len);
9025 if (retval == ERROR_SUCCESS)
9027 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
9028 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
9029 int if_num;
9030 struct sockaddr_in sa;
9032 /* For the below, we need some winsock functions, so make sure
9033 the winsock DLL is loaded. If we cannot successfully load
9034 it, they will have no use of the information we provide,
9035 anyway, so punt. */
9036 if (!winsock_lib && !init_winsock (1))
9037 goto done;
9039 for (adapter = ainfo; adapter; adapter = adapter->Next)
9041 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
9042 u_long ip_addr;
9043 /* Present Unix-compatible interface names, instead of the
9044 Windows names, which are really GUIDs not readable by
9045 humans. */
9046 static const char *ifmt[] = {
9047 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
9048 "lo", "ifx%d"
9050 enum {
9051 NONE = -1,
9052 ETHERNET = 0,
9053 TOKENRING = 1,
9054 FDDI = 2,
9055 PPP = 3,
9056 SLIP = 4,
9057 WLAN = 5,
9058 LOOPBACK = 6,
9059 OTHER_IF = 7
9060 } ifmt_idx;
9062 switch (adapter->Type)
9064 case MIB_IF_TYPE_ETHERNET:
9065 /* Windows before Vista reports wireless adapters as
9066 Ethernet. Work around by looking at the Description
9067 string. */
9068 if (strstr (adapter->Description, "Wireless "))
9070 ifmt_idx = WLAN;
9071 if_num = wlan_count++;
9073 else
9075 ifmt_idx = ETHERNET;
9076 if_num = eth_count++;
9078 break;
9079 case MIB_IF_TYPE_TOKENRING:
9080 ifmt_idx = TOKENRING;
9081 if_num = tr_count++;
9082 break;
9083 case MIB_IF_TYPE_FDDI:
9084 ifmt_idx = FDDI;
9085 if_num = fddi_count++;
9086 break;
9087 case MIB_IF_TYPE_PPP:
9088 ifmt_idx = PPP;
9089 if_num = ppp_count++;
9090 break;
9091 case MIB_IF_TYPE_SLIP:
9092 ifmt_idx = SLIP;
9093 if_num = sl_count++;
9094 break;
9095 case IF_TYPE_IEEE80211:
9096 ifmt_idx = WLAN;
9097 if_num = wlan_count++;
9098 break;
9099 case MIB_IF_TYPE_LOOPBACK:
9100 if (lo_count < 0)
9102 ifmt_idx = LOOPBACK;
9103 if_num = lo_count++;
9105 else
9106 ifmt_idx = NONE;
9107 break;
9108 default:
9109 ifmt_idx = OTHER_IF;
9110 if_num = ifx_count++;
9111 break;
9113 if (ifmt_idx == NONE)
9114 continue;
9115 sprintf (namebuf, ifmt[ifmt_idx], if_num);
9117 sa.sin_family = AF_INET;
9118 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
9119 if (ip_addr == INADDR_NONE)
9121 /* Bogus address, skip this interface. */
9122 continue;
9124 sa.sin_addr.s_addr = ip_addr;
9125 sa.sin_port = 0;
9126 if (NILP (ifname))
9127 res = Fcons (Fcons (build_string (namebuf),
9128 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9129 sizeof (struct sockaddr))),
9130 res);
9131 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
9133 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
9134 register struct Lisp_Vector *p = XVECTOR (hwaddr);
9135 Lisp_Object flags = Qnil;
9136 int n;
9137 u_long net_mask;
9139 /* Flags. We guess most of them by type, since the
9140 Windows flags are different and hard to get by. */
9141 flags = Fcons (intern ("up"), flags);
9142 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
9144 flags = Fcons (intern ("broadcast"), flags);
9145 flags = Fcons (intern ("multicast"), flags);
9147 flags = Fcons (intern ("running"), flags);
9148 if (ifmt_idx == PPP)
9150 flags = Fcons (intern ("pointopoint"), flags);
9151 flags = Fcons (intern ("noarp"), flags);
9153 if (adapter->HaveWins)
9154 flags = Fcons (intern ("WINS"), flags);
9155 if (adapter->DhcpEnabled)
9156 flags = Fcons (intern ("dynamic"), flags);
9158 res = Fcons (flags, res);
9160 /* Hardware address and its family. */
9161 for (n = 0; n < adapter->AddressLength; n++)
9162 p->contents[n] = make_number ((int) adapter->Address[n]);
9163 /* Windows does not support AF_LINK or AF_PACKET family
9164 of addresses. Use an arbitrary family number that is
9165 identical to what GNU/Linux returns. */
9166 res = Fcons (Fcons (make_number (1), hwaddr), res);
9168 /* Network mask. */
9169 sa.sin_family = AF_INET;
9170 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
9171 if (net_mask != INADDR_NONE)
9173 sa.sin_addr.s_addr = net_mask;
9174 sa.sin_port = 0;
9175 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9176 sizeof (struct sockaddr)),
9177 res);
9179 else
9180 res = Fcons (Qnil, res);
9182 sa.sin_family = AF_INET;
9183 if (ip_addr != INADDR_NONE)
9185 /* Broadcast address is only reported by
9186 GetAdaptersAddresses, which is of limited
9187 availability. Generate it on our own. */
9188 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
9190 sa.sin_addr.s_addr = bcast_addr;
9191 sa.sin_port = 0;
9192 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9193 sizeof (struct sockaddr)),
9194 res);
9196 /* IP address. */
9197 sa.sin_addr.s_addr = ip_addr;
9198 sa.sin_port = 0;
9199 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9200 sizeof (struct sockaddr)),
9201 res);
9203 else
9204 res = Fcons (Qnil, Fcons (Qnil, res));
9207 /* GetAdaptersInfo is documented to not report loopback
9208 interfaces, so we generate one out of thin air. */
9209 if (!lo_count)
9211 sa.sin_family = AF_INET;
9212 sa.sin_port = 0;
9213 if (NILP (ifname))
9215 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9216 res = Fcons (Fcons (build_string ("lo"),
9217 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9218 sizeof (struct sockaddr))),
9219 res);
9221 else if (strcmp (SSDATA (ifname), "lo") == 0)
9223 res = Fcons (Fcons (intern ("running"),
9224 Fcons (intern ("loopback"),
9225 Fcons (intern ("up"), Qnil))), Qnil);
9226 /* 772 is what 3 different GNU/Linux systems report for
9227 the loopback interface. */
9228 res = Fcons (Fcons (make_number (772),
9229 Fmake_vector (make_number (6),
9230 make_number (0))),
9231 res);
9232 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
9233 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9234 sizeof (struct sockaddr)),
9235 res);
9236 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
9237 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9238 sizeof (struct sockaddr)),
9239 res);
9240 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9241 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9242 sizeof (struct sockaddr)),
9243 res);
9249 done:
9250 xfree (ainfo);
9251 return res;
9254 Lisp_Object
9255 network_interface_list (void)
9257 return network_interface_get_info (Qnil);
9260 Lisp_Object
9261 network_interface_info (Lisp_Object ifname)
9263 CHECK_STRING (ifname);
9264 return network_interface_get_info (ifname);
9268 /* The Windows CRT functions are "optimized for speed", so they don't
9269 check for timezone and DST changes if they were last called less
9270 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
9271 all Emacs features that repeatedly call time functions (e.g.,
9272 display-time) are in real danger of missing timezone and DST
9273 changes. Calling tzset before each localtime call fixes that. */
9274 struct tm *
9275 sys_localtime (const time_t *t)
9277 tzset ();
9278 return localtime (t);
9283 /* Try loading LIBRARY_ID from the file(s) specified in
9284 Vdynamic_library_alist. If the library is loaded successfully,
9285 return the handle of the DLL, and record the filename in the
9286 property :loaded-from of LIBRARY_ID. If the library could not be
9287 found, or when it was already loaded (because the handle is not
9288 recorded anywhere, and so is lost after use), return NULL.
9290 We could also save the handle in :loaded-from, but currently
9291 there's no use case for it. */
9292 HMODULE
9293 w32_delayed_load (Lisp_Object library_id)
9295 HMODULE dll_handle = NULL;
9297 CHECK_SYMBOL (library_id);
9299 if (CONSP (Vdynamic_library_alist)
9300 && NILP (Fassq (library_id, Vlibrary_cache)))
9302 Lisp_Object found = Qnil;
9303 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
9305 if (CONSP (dlls))
9306 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
9308 Lisp_Object dll = XCAR (dlls);
9309 char name[MAX_UTF8_PATH];
9310 DWORD res = -1;
9312 CHECK_STRING (dll);
9313 dll = ENCODE_FILE (dll);
9314 if (w32_unicode_filenames)
9316 wchar_t name_w[MAX_PATH];
9318 filename_to_utf16 (SSDATA (dll), name_w);
9319 dll_handle = LoadLibraryW (name_w);
9320 if (dll_handle)
9322 res = GetModuleFileNameW (dll_handle, name_w,
9323 sizeof (name_w));
9324 if (res > 0)
9325 filename_from_utf16 (name_w, name);
9328 else
9330 char name_a[MAX_PATH];
9332 filename_to_ansi (SSDATA (dll), name_a);
9333 dll_handle = LoadLibraryA (name_a);
9334 if (dll_handle)
9336 res = GetModuleFileNameA (dll_handle, name_a,
9337 sizeof (name_a));
9338 if (res > 0)
9339 filename_from_ansi (name_a, name);
9342 if (dll_handle)
9344 ptrdiff_t len = strlen (name);
9345 found = Fcons (dll,
9346 (res > 0)
9347 /* Possibly truncated */
9348 ? make_specified_string (name, -1, len, 1)
9349 : Qnil);
9350 /* This prevents thread start and end notifications
9351 from being sent to the DLL, for every thread we
9352 start. We don't need those notifications because
9353 threads we create never use any of these DLLs, only
9354 the main thread uses them. This is supposed to
9355 speed up thread creation. */
9356 DisableThreadLibraryCalls (dll_handle);
9357 break;
9361 Fput (library_id, QCloaded_from, found);
9364 return dll_handle;
9368 void
9369 check_windows_init_file (void)
9371 /* A common indication that Emacs is not installed properly is when
9372 it cannot find the Windows installation file. If this file does
9373 not exist in the expected place, tell the user. */
9375 if (!noninteractive && !inhibit_window_system
9376 /* Vload_path is not yet initialized when we are loading
9377 loadup.el. */
9378 && NILP (Vpurify_flag))
9380 Lisp_Object init_file;
9381 int fd;
9383 /* Implementation note: this function runs early during Emacs
9384 startup, before startup.el is run. So Vload_path is still in
9385 its initial unibyte form, but it holds UTF-8 encoded file
9386 names, since init_callproc was already called. So we do not
9387 need to ENCODE_FILE here, but we do need to convert the file
9388 names from UTF-8 to ANSI. */
9389 init_file = build_string ("term/w32-win");
9390 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
9391 if (fd < 0)
9393 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
9394 char *init_file_name = SSDATA (init_file);
9395 char *load_path = SSDATA (load_path_print);
9396 char *buffer = alloca (1024
9397 + strlen (init_file_name)
9398 + strlen (load_path));
9399 char *msg = buffer;
9400 int needed;
9402 sprintf (buffer,
9403 "The Emacs Windows initialization file \"%s.el\" "
9404 "could not be found in your Emacs installation. "
9405 "Emacs checked the following directories for this file:\n"
9406 "\n%s\n\n"
9407 "When Emacs cannot find this file, it usually means that it "
9408 "was not installed properly, or its distribution file was "
9409 "not unpacked properly.\nSee the README.W32 file in the "
9410 "top-level Emacs directory for more information.",
9411 init_file_name, load_path);
9412 needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
9413 buffer, -1, NULL, 0);
9414 if (needed > 0)
9416 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
9418 pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
9419 -1, msg_w, needed);
9420 needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
9421 NULL, 0, NULL, NULL);
9422 if (needed > 0)
9424 char *msg_a = alloca (needed + 1);
9426 pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
9427 NULL, NULL);
9428 msg = msg_a;
9431 MessageBox (NULL,
9432 msg,
9433 "Emacs Abort Dialog",
9434 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
9435 /* Use the low-level system abort. */
9436 abort ();
9438 else
9440 _close (fd);
9445 void
9446 term_ntproc (int ignored)
9448 (void)ignored;
9450 term_timers ();
9452 /* shutdown the socket interface if necessary */
9453 term_winsock ();
9455 term_w32select ();
9458 void
9459 init_ntproc (int dumping)
9461 sigset_t initial_mask = 0;
9463 /* Initialize the socket interface now if available and requested by
9464 the user by defining PRELOAD_WINSOCK; otherwise loading will be
9465 delayed until open-network-stream is called (w32-has-winsock can
9466 also be used to dynamically load or reload winsock).
9468 Conveniently, init_environment is called before us, so
9469 PRELOAD_WINSOCK can be set in the registry. */
9471 /* Always initialize this correctly. */
9472 winsock_lib = NULL;
9474 if (getenv ("PRELOAD_WINSOCK") != NULL)
9475 init_winsock (TRUE);
9477 /* Initial preparation for subprocess support: replace our standard
9478 handles with non-inheritable versions. */
9480 HANDLE parent;
9481 HANDLE stdin_save = INVALID_HANDLE_VALUE;
9482 HANDLE stdout_save = INVALID_HANDLE_VALUE;
9483 HANDLE stderr_save = INVALID_HANDLE_VALUE;
9485 parent = GetCurrentProcess ();
9487 /* ignore errors when duplicating and closing; typically the
9488 handles will be invalid when running as a gui program. */
9489 DuplicateHandle (parent,
9490 GetStdHandle (STD_INPUT_HANDLE),
9491 parent,
9492 &stdin_save,
9494 FALSE,
9495 DUPLICATE_SAME_ACCESS);
9497 DuplicateHandle (parent,
9498 GetStdHandle (STD_OUTPUT_HANDLE),
9499 parent,
9500 &stdout_save,
9502 FALSE,
9503 DUPLICATE_SAME_ACCESS);
9505 DuplicateHandle (parent,
9506 GetStdHandle (STD_ERROR_HANDLE),
9507 parent,
9508 &stderr_save,
9510 FALSE,
9511 DUPLICATE_SAME_ACCESS);
9513 fclose (stdin);
9514 fclose (stdout);
9515 fclose (stderr);
9517 if (stdin_save != INVALID_HANDLE_VALUE)
9518 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
9519 else
9520 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
9521 _fdopen (0, "r");
9523 if (stdout_save != INVALID_HANDLE_VALUE)
9524 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
9525 else
9526 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9527 _fdopen (1, "w");
9529 if (stderr_save != INVALID_HANDLE_VALUE)
9530 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
9531 else
9532 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9533 _fdopen (2, "w");
9536 /* unfortunately, atexit depends on implementation of malloc */
9537 /* atexit (term_ntproc); */
9538 if (!dumping)
9540 /* Make sure we start with all signals unblocked. */
9541 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
9542 signal (SIGABRT, term_ntproc);
9544 init_timers ();
9546 /* determine which drives are fixed, for GetCachedVolumeInformation */
9548 /* GetDriveType must have trailing backslash. */
9549 char drive[] = "A:\\";
9551 /* Loop over all possible drive letters */
9552 while (*drive <= 'Z')
9554 /* Record if this drive letter refers to a fixed drive. */
9555 fixed_drives[DRIVE_INDEX (*drive)] =
9556 (GetDriveType (drive) == DRIVE_FIXED);
9558 (*drive)++;
9561 /* Reset the volume info cache. */
9562 volume_cache = NULL;
9567 shutdown_handler ensures that buffers' autosave files are
9568 up to date when the user logs off, or the system shuts down.
9570 static BOOL WINAPI
9571 shutdown_handler (DWORD type)
9573 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
9574 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
9575 || type == CTRL_LOGOFF_EVENT /* User logs off. */
9576 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
9578 /* Shut down cleanly, making sure autosave files are up to date. */
9579 shut_down_emacs (0, Qnil);
9582 /* Allow other handlers to handle this signal. */
9583 return FALSE;
9586 /* On Windows 9X, load UNICOWS.DLL and return its handle, or die. On
9587 NT, return a handle to GDI32.DLL. */
9588 HANDLE
9589 maybe_load_unicows_dll (void)
9591 if (os_subtype == OS_9X)
9593 HANDLE ret = LoadLibrary ("Unicows.dll");
9594 if (ret)
9596 /* These two functions are present on Windows 9X as stubs
9597 that always fail. We need the real implementations from
9598 UNICOWS.DLL, so we must call these functions through
9599 pointers, and assign the correct addresses to these
9600 pointers at program startup (see emacs.c, which calls
9601 this function early on). */
9602 pMultiByteToWideChar =
9603 (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
9604 pWideCharToMultiByte =
9605 (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
9606 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9607 return ret;
9609 else
9611 int button;
9613 button = MessageBox (NULL,
9614 "Emacs cannot load the UNICOWS.DLL library.\n"
9615 "This library is essential for using Emacs\n"
9616 "on this system. You need to install it.\n\n"
9617 "Emacs will exit when you click OK.",
9618 "Emacs cannot load UNICOWS.DLL",
9619 MB_ICONERROR | MB_TASKMODAL
9620 | MB_SETFOREGROUND | MB_OK);
9621 switch (button)
9623 case IDOK:
9624 default:
9625 exit (1);
9629 else
9631 /* On NT family of Windows, these two functions are always
9632 linked in, so we just assign their addresses to the 2
9633 pointers; no need for the LoadLibrary dance. */
9634 pMultiByteToWideChar = MultiByteToWideChar;
9635 pWideCharToMultiByte = WideCharToMultiByte;
9636 /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported. */
9637 if (w32_major_version < 5)
9638 multiByteToWideCharFlags = 0;
9639 else
9640 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9641 return LoadLibrary ("Gdi32.dll");
9646 globals_of_w32 is used to initialize those global variables that
9647 must always be initialized on startup even when the global variable
9648 initialized is non zero (see the function main in emacs.c).
9650 void
9651 globals_of_w32 (void)
9653 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
9655 get_process_times_fn = (GetProcessTimes_Proc)
9656 GetProcAddress (kernel32, "GetProcessTimes");
9658 DEFSYM (QCloaded_from, ":loaded-from");
9660 g_b_init_is_windows_9x = 0;
9661 g_b_init_open_process_token = 0;
9662 g_b_init_get_token_information = 0;
9663 g_b_init_lookup_account_sid = 0;
9664 g_b_init_get_sid_sub_authority = 0;
9665 g_b_init_get_sid_sub_authority_count = 0;
9666 g_b_init_get_security_info = 0;
9667 g_b_init_get_file_security_w = 0;
9668 g_b_init_get_file_security_a = 0;
9669 g_b_init_get_security_descriptor_owner = 0;
9670 g_b_init_get_security_descriptor_group = 0;
9671 g_b_init_is_valid_sid = 0;
9672 g_b_init_create_toolhelp32_snapshot = 0;
9673 g_b_init_process32_first = 0;
9674 g_b_init_process32_next = 0;
9675 g_b_init_open_thread_token = 0;
9676 g_b_init_impersonate_self = 0;
9677 g_b_init_revert_to_self = 0;
9678 g_b_init_get_process_memory_info = 0;
9679 g_b_init_get_process_working_set_size = 0;
9680 g_b_init_global_memory_status = 0;
9681 g_b_init_global_memory_status_ex = 0;
9682 g_b_init_equal_sid = 0;
9683 g_b_init_copy_sid = 0;
9684 g_b_init_get_length_sid = 0;
9685 g_b_init_get_native_system_info = 0;
9686 g_b_init_get_system_times = 0;
9687 g_b_init_create_symbolic_link_w = 0;
9688 g_b_init_create_symbolic_link_a = 0;
9689 g_b_init_get_security_descriptor_dacl = 0;
9690 g_b_init_convert_sd_to_sddl = 0;
9691 g_b_init_convert_sddl_to_sd = 0;
9692 g_b_init_is_valid_security_descriptor = 0;
9693 g_b_init_set_file_security_w = 0;
9694 g_b_init_set_file_security_a = 0;
9695 g_b_init_set_named_security_info_w = 0;
9696 g_b_init_set_named_security_info_a = 0;
9697 g_b_init_get_adapters_info = 0;
9698 g_b_init_compare_string_w = 0;
9699 g_b_init_debug_break_process = 0;
9700 num_of_processors = 0;
9701 /* The following sets a handler for shutdown notifications for
9702 console apps. This actually applies to Emacs in both console and
9703 GUI modes, since we had to fool windows into thinking emacs is a
9704 console application to get console mode to work. */
9705 SetConsoleCtrlHandler (shutdown_handler, TRUE);
9707 /* "None" is the default group name on standalone workstations. */
9708 strcpy (dflt_group_name, "None");
9710 /* Reset, in case it has some value inherited from dump time. */
9711 w32_stat_get_owner_group = 0;
9713 /* If w32_unicode_filenames is non-zero, we will be using Unicode
9714 (a.k.a. "wide") APIs to invoke functions that accept file
9715 names. */
9716 if (is_windows_9x ())
9717 w32_unicode_filenames = 0;
9718 else
9719 w32_unicode_filenames = 1;
9721 #ifdef HAVE_MODULES
9722 dynlib_reset_last_error ();
9723 #endif
9725 w32_crypto_hprov = (HCRYPTPROV)0;
9728 /* For make-serial-process */
9730 serial_open (Lisp_Object port_obj)
9732 char *port = SSDATA (port_obj);
9733 HANDLE hnd;
9734 child_process *cp;
9735 int fd = -1;
9737 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
9738 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
9739 if (hnd == INVALID_HANDLE_VALUE)
9740 error ("Could not open %s", port);
9741 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
9742 if (fd == -1)
9743 error ("Could not open %s", port);
9745 cp = new_child ();
9746 if (!cp)
9747 error ("Could not create child process");
9748 cp->fd = fd;
9749 cp->status = STATUS_READ_ACKNOWLEDGED;
9750 fd_info[ fd ].hnd = hnd;
9751 fd_info[ fd ].flags |=
9752 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
9753 if (fd_info[ fd ].cp != NULL)
9755 error ("fd_info[fd = %d] is already in use", fd);
9757 fd_info[ fd ].cp = cp;
9758 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9759 if (cp->ovl_read.hEvent == NULL)
9760 error ("Could not create read event");
9761 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9762 if (cp->ovl_write.hEvent == NULL)
9763 error ("Could not create write event");
9765 return fd;
9768 /* For serial-process-configure */
9769 void
9770 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
9772 Lisp_Object childp2 = Qnil;
9773 Lisp_Object tem = Qnil;
9774 HANDLE hnd;
9775 DCB dcb;
9776 COMMTIMEOUTS ct;
9777 char summary[4] = "???"; /* This usually becomes "8N1". */
9779 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
9780 error ("Not a serial process");
9781 hnd = fd_info[ p->outfd ].hnd;
9783 childp2 = Fcopy_sequence (p->childp);
9785 /* Initialize timeouts for blocking read and blocking write. */
9786 if (!GetCommTimeouts (hnd, &ct))
9787 error ("GetCommTimeouts() failed");
9788 ct.ReadIntervalTimeout = 0;
9789 ct.ReadTotalTimeoutMultiplier = 0;
9790 ct.ReadTotalTimeoutConstant = 0;
9791 ct.WriteTotalTimeoutMultiplier = 0;
9792 ct.WriteTotalTimeoutConstant = 0;
9793 if (!SetCommTimeouts (hnd, &ct))
9794 error ("SetCommTimeouts() failed");
9795 /* Read port attributes and prepare default configuration. */
9796 memset (&dcb, 0, sizeof (dcb));
9797 dcb.DCBlength = sizeof (DCB);
9798 if (!GetCommState (hnd, &dcb))
9799 error ("GetCommState() failed");
9800 dcb.fBinary = TRUE;
9801 dcb.fNull = FALSE;
9802 dcb.fAbortOnError = FALSE;
9803 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
9804 dcb.ErrorChar = 0;
9805 dcb.EofChar = 0;
9806 dcb.EvtChar = 0;
9808 /* Configure speed. */
9809 if (!NILP (Fplist_member (contact, QCspeed)))
9810 tem = Fplist_get (contact, QCspeed);
9811 else
9812 tem = Fplist_get (p->childp, QCspeed);
9813 CHECK_NUMBER (tem);
9814 dcb.BaudRate = XINT (tem);
9815 childp2 = Fplist_put (childp2, QCspeed, tem);
9817 /* Configure bytesize. */
9818 if (!NILP (Fplist_member (contact, QCbytesize)))
9819 tem = Fplist_get (contact, QCbytesize);
9820 else
9821 tem = Fplist_get (p->childp, QCbytesize);
9822 if (NILP (tem))
9823 tem = make_number (8);
9824 CHECK_NUMBER (tem);
9825 if (XINT (tem) != 7 && XINT (tem) != 8)
9826 error (":bytesize must be nil (8), 7, or 8");
9827 dcb.ByteSize = XINT (tem);
9828 summary[0] = XINT (tem) + '0';
9829 childp2 = Fplist_put (childp2, QCbytesize, tem);
9831 /* Configure parity. */
9832 if (!NILP (Fplist_member (contact, QCparity)))
9833 tem = Fplist_get (contact, QCparity);
9834 else
9835 tem = Fplist_get (p->childp, QCparity);
9836 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
9837 error (":parity must be nil (no parity), `even', or `odd'");
9838 dcb.fParity = FALSE;
9839 dcb.Parity = NOPARITY;
9840 dcb.fErrorChar = FALSE;
9841 if (NILP (tem))
9843 summary[1] = 'N';
9845 else if (EQ (tem, Qeven))
9847 summary[1] = 'E';
9848 dcb.fParity = TRUE;
9849 dcb.Parity = EVENPARITY;
9850 dcb.fErrorChar = TRUE;
9852 else if (EQ (tem, Qodd))
9854 summary[1] = 'O';
9855 dcb.fParity = TRUE;
9856 dcb.Parity = ODDPARITY;
9857 dcb.fErrorChar = TRUE;
9859 childp2 = Fplist_put (childp2, QCparity, tem);
9861 /* Configure stopbits. */
9862 if (!NILP (Fplist_member (contact, QCstopbits)))
9863 tem = Fplist_get (contact, QCstopbits);
9864 else
9865 tem = Fplist_get (p->childp, QCstopbits);
9866 if (NILP (tem))
9867 tem = make_number (1);
9868 CHECK_NUMBER (tem);
9869 if (XINT (tem) != 1 && XINT (tem) != 2)
9870 error (":stopbits must be nil (1 stopbit), 1, or 2");
9871 summary[2] = XINT (tem) + '0';
9872 if (XINT (tem) == 1)
9873 dcb.StopBits = ONESTOPBIT;
9874 else if (XINT (tem) == 2)
9875 dcb.StopBits = TWOSTOPBITS;
9876 childp2 = Fplist_put (childp2, QCstopbits, tem);
9878 /* Configure flowcontrol. */
9879 if (!NILP (Fplist_member (contact, QCflowcontrol)))
9880 tem = Fplist_get (contact, QCflowcontrol);
9881 else
9882 tem = Fplist_get (p->childp, QCflowcontrol);
9883 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
9884 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
9885 dcb.fOutxCtsFlow = FALSE;
9886 dcb.fOutxDsrFlow = FALSE;
9887 dcb.fDtrControl = DTR_CONTROL_DISABLE;
9888 dcb.fDsrSensitivity = FALSE;
9889 dcb.fTXContinueOnXoff = FALSE;
9890 dcb.fOutX = FALSE;
9891 dcb.fInX = FALSE;
9892 dcb.fRtsControl = RTS_CONTROL_DISABLE;
9893 dcb.XonChar = 17; /* Control-Q */
9894 dcb.XoffChar = 19; /* Control-S */
9895 if (NILP (tem))
9897 /* Already configured. */
9899 else if (EQ (tem, Qhw))
9901 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
9902 dcb.fOutxCtsFlow = TRUE;
9904 else if (EQ (tem, Qsw))
9906 dcb.fOutX = TRUE;
9907 dcb.fInX = TRUE;
9909 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
9911 /* Activate configuration. */
9912 if (!SetCommState (hnd, &dcb))
9913 error ("SetCommState() failed");
9915 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
9916 pset_childp (p, childp2);
9919 /* For make-pipe-process */
9920 void
9921 register_aux_fd (int infd)
9923 child_process *cp;
9925 cp = new_child ();
9926 if (!cp)
9927 error ("Could not create child process");
9928 cp->fd = infd;
9929 cp->status = STATUS_READ_ACKNOWLEDGED;
9931 if (fd_info[ infd ].cp != NULL)
9933 error ("fd_info[fd = %d] is already in use", infd);
9935 fd_info[ infd ].cp = cp;
9936 fd_info[ infd ].hnd = (HANDLE) _get_osfhandle (infd);
9939 #ifdef HAVE_GNUTLS
9941 ssize_t
9942 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
9944 int n, err;
9945 struct Lisp_Process *process = (struct Lisp_Process *)p;
9946 int fd = process->infd;
9948 n = sys_read (fd, (char*)buf, sz);
9950 if (n >= 0)
9951 return n;
9953 err = errno;
9955 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9956 if (err == EWOULDBLOCK)
9957 err = EAGAIN;
9959 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
9961 return -1;
9964 ssize_t
9965 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
9967 struct Lisp_Process *process = (struct Lisp_Process *)p;
9968 int fd = process->outfd;
9969 ssize_t n = sys_write (fd, buf, sz);
9971 /* 0 or more bytes written means everything went fine. */
9972 if (n >= 0)
9973 return n;
9975 /* Negative bytes written means we got an error in errno.
9976 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9977 emacs_gnutls_transport_set_errno (process->gnutls_state,
9978 errno == EWOULDBLOCK ? EAGAIN : errno);
9980 return -1;
9982 #endif /* HAVE_GNUTLS */
9984 /* end of w32.c */