Improve fontification of footnote references in Info buffers
[emacs.git] / src / w32.c
blobad7d94a21d299d3dbc62de0ae299a5e5a917870f
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
3 Copyright (C) 1994-1995, 2000-2016 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_mkdir (const char *);
78 int sys_open (const char *, int, int);
79 int sys_rename (char const *, char const *);
80 int sys_rmdir (const char *);
81 int sys_close (int);
82 int sys_dup2 (int, int);
83 int sys_read (int, char *, unsigned int);
84 int sys_write (int, const void *, unsigned int);
85 struct tm *sys_localtime (const time_t *);
87 #ifdef HAVE_MODULES
88 extern void dynlib_reset_last_error (void);
89 #endif
91 #include "lisp.h"
92 #include "epaths.h" /* for PATH_EXEC */
94 #include <pwd.h>
95 #include <grp.h>
97 #include <windows.h>
98 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
99 use a different name to avoid compilation problems. */
100 typedef struct _MEMORY_STATUS_EX {
101 DWORD dwLength;
102 DWORD dwMemoryLoad;
103 DWORDLONG ullTotalPhys;
104 DWORDLONG ullAvailPhys;
105 DWORDLONG ullTotalPageFile;
106 DWORDLONG ullAvailPageFile;
107 DWORDLONG ullTotalVirtual;
108 DWORDLONG ullAvailVirtual;
109 DWORDLONG ullAvailExtendedVirtual;
110 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
112 /* These are here so that GDB would know about these data types. This
113 allows attaching GDB to Emacs when a fatal exception is triggered
114 and Windows pops up the "application needs to be closed" dialog.
115 At that point, _gnu_exception_handler, the top-level exception
116 handler installed by the MinGW startup code, is somewhere on the
117 call-stack of the main thread, so going to that call frame and
118 looking at the argument to _gnu_exception_handler, which is a
119 PEXCEPTION_POINTERS pointer, can reveal the exception code
120 (excptr->ExceptionRecord->ExceptionCode) and the address where the
121 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
122 well as some additional information specific to the exception. */
123 PEXCEPTION_POINTERS excptr;
124 PEXCEPTION_RECORD excprec;
125 PCONTEXT ctxrec;
127 #include <lmcons.h>
128 #include <shlobj.h>
130 #include <tlhelp32.h>
131 #include <psapi.h>
132 #ifndef _MSC_VER
133 #include <w32api.h>
134 #endif
135 #if _WIN32_WINNT < 0x0500
136 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
137 /* This either is not in psapi.h or guarded by higher value of
138 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
139 defines it in psapi.h */
140 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
141 DWORD cb;
142 DWORD PageFaultCount;
143 SIZE_T PeakWorkingSetSize;
144 SIZE_T WorkingSetSize;
145 SIZE_T QuotaPeakPagedPoolUsage;
146 SIZE_T QuotaPagedPoolUsage;
147 SIZE_T QuotaPeakNonPagedPoolUsage;
148 SIZE_T QuotaNonPagedPoolUsage;
149 SIZE_T PagefileUsage;
150 SIZE_T PeakPagefileUsage;
151 SIZE_T PrivateUsage;
152 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
153 #endif
154 #endif
156 #include <winioctl.h>
157 #include <aclapi.h>
158 #include <sddl.h>
160 #include <sys/acl.h>
161 #include <acl.h>
163 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
164 define them by hand if not already defined. */
165 #ifndef SDDL_REVISION_1
166 #define SDDL_REVISION_1 1
167 #endif /* SDDL_REVISION_1 */
169 #if defined(_MSC_VER) || defined(MINGW_W64)
170 /* MSVC and MinGW64 don't provide the definition of
171 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
172 which cannot be included because it triggers conflicts with other
173 Windows API headers. So we define it here by hand. */
175 typedef struct _REPARSE_DATA_BUFFER {
176 ULONG ReparseTag;
177 USHORT ReparseDataLength;
178 USHORT Reserved;
179 union {
180 struct {
181 USHORT SubstituteNameOffset;
182 USHORT SubstituteNameLength;
183 USHORT PrintNameOffset;
184 USHORT PrintNameLength;
185 ULONG Flags;
186 WCHAR PathBuffer[1];
187 } SymbolicLinkReparseBuffer;
188 struct {
189 USHORT SubstituteNameOffset;
190 USHORT SubstituteNameLength;
191 USHORT PrintNameOffset;
192 USHORT PrintNameLength;
193 WCHAR PathBuffer[1];
194 } MountPointReparseBuffer;
195 struct {
196 UCHAR DataBuffer[1];
197 } GenericReparseBuffer;
198 } DUMMYUNIONNAME;
199 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
201 #ifndef FILE_DEVICE_FILE_SYSTEM
202 #define FILE_DEVICE_FILE_SYSTEM 9
203 #endif
204 #ifndef METHOD_BUFFERED
205 #define METHOD_BUFFERED 0
206 #endif
207 #ifndef FILE_ANY_ACCESS
208 #define FILE_ANY_ACCESS 0x00000000
209 #endif
210 #ifndef CTL_CODE
211 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
212 #endif
213 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
214 #ifndef FSCTL_GET_REPARSE_POINT
215 #define FSCTL_GET_REPARSE_POINT \
216 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
217 #endif
218 #endif
220 /* TCP connection support. */
221 #include <sys/socket.h>
222 #undef socket
223 #undef bind
224 #undef connect
225 #undef htons
226 #undef ntohs
227 #undef inet_addr
228 #undef gethostname
229 #undef gethostbyname
230 #undef getservbyname
231 #undef getpeername
232 #undef shutdown
233 #undef setsockopt
234 #undef listen
235 #undef getsockname
236 #undef accept
237 #undef recvfrom
238 #undef sendto
240 #include <iphlpapi.h> /* should be after winsock2.h */
242 #include <wincrypt.h>
244 #include <c-strcase.h>
245 #include <utimens.h> /* for fdutimens */
247 #include "w32.h"
248 #include <dirent.h>
249 #include "w32common.h"
250 #include "w32select.h"
251 #include "systime.h" /* for current_timespec, struct timespec */
252 #include "dispextern.h" /* for xstrcasecmp */
253 #include "coding.h" /* for Vlocale_coding_system */
255 #include "careadlinkat.h"
256 #include "allocator.h"
258 /* For Lisp_Process, serial_configure and serial_open. */
259 #include "process.h"
260 #include "systty.h"
262 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
263 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
265 static DWORD get_rid (PSID);
266 static int is_symlink (const char *);
267 static char * chase_symlinks (const char *);
268 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
269 static int restore_privilege (TOKEN_PRIVILEGES *);
270 static BOOL WINAPI revert_to_self (void);
272 static int sys_access (const char *, int);
273 extern void *e_malloc (size_t);
274 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
275 struct timespec *, void *);
276 extern int sys_dup (int);
279 /* Initialization states.
281 WARNING: If you add any more such variables for additional APIs,
282 you MUST add initialization for them to globals_of_w32
283 below. This is because these variables might get set
284 to non-NULL values during dumping, but the dumped Emacs
285 cannot reuse those values, because it could be run on a
286 different version of the OS, where API addresses are
287 different. */
288 static BOOL g_b_init_is_windows_9x;
289 static BOOL g_b_init_open_process_token;
290 static BOOL g_b_init_get_token_information;
291 static BOOL g_b_init_lookup_account_sid;
292 static BOOL g_b_init_get_sid_sub_authority;
293 static BOOL g_b_init_get_sid_sub_authority_count;
294 static BOOL g_b_init_get_security_info;
295 static BOOL g_b_init_get_file_security_w;
296 static BOOL g_b_init_get_file_security_a;
297 static BOOL g_b_init_get_security_descriptor_owner;
298 static BOOL g_b_init_get_security_descriptor_group;
299 static BOOL g_b_init_is_valid_sid;
300 static BOOL g_b_init_create_toolhelp32_snapshot;
301 static BOOL g_b_init_process32_first;
302 static BOOL g_b_init_process32_next;
303 static BOOL g_b_init_open_thread_token;
304 static BOOL g_b_init_impersonate_self;
305 static BOOL g_b_init_revert_to_self;
306 static BOOL g_b_init_get_process_memory_info;
307 static BOOL g_b_init_get_process_working_set_size;
308 static BOOL g_b_init_global_memory_status;
309 static BOOL g_b_init_global_memory_status_ex;
310 static BOOL g_b_init_get_length_sid;
311 static BOOL g_b_init_equal_sid;
312 static BOOL g_b_init_copy_sid;
313 static BOOL g_b_init_get_native_system_info;
314 static BOOL g_b_init_get_system_times;
315 static BOOL g_b_init_create_symbolic_link_w;
316 static BOOL g_b_init_create_symbolic_link_a;
317 static BOOL g_b_init_get_security_descriptor_dacl;
318 static BOOL g_b_init_convert_sd_to_sddl;
319 static BOOL g_b_init_convert_sddl_to_sd;
320 static BOOL g_b_init_is_valid_security_descriptor;
321 static BOOL g_b_init_set_file_security_w;
322 static BOOL g_b_init_set_file_security_a;
323 static BOOL g_b_init_set_named_security_info_w;
324 static BOOL g_b_init_set_named_security_info_a;
325 static BOOL g_b_init_get_adapters_info;
327 BOOL g_b_init_compare_string_w;
328 BOOL g_b_init_debug_break_process;
331 BEGIN: Wrapper functions around OpenProcessToken
332 and other functions in advapi32.dll that are only
333 supported in Windows NT / 2k / XP
335 /* ** Function pointer typedefs ** */
336 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
337 HANDLE ProcessHandle,
338 DWORD DesiredAccess,
339 PHANDLE TokenHandle);
340 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
341 HANDLE TokenHandle,
342 TOKEN_INFORMATION_CLASS TokenInformationClass,
343 LPVOID TokenInformation,
344 DWORD TokenInformationLength,
345 PDWORD ReturnLength);
346 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
347 HANDLE process_handle,
348 LPFILETIME creation_time,
349 LPFILETIME exit_time,
350 LPFILETIME kernel_time,
351 LPFILETIME user_time);
353 GetProcessTimes_Proc get_process_times_fn = NULL;
355 #ifdef _UNICODE
356 const char * const LookupAccountSid_Name = "LookupAccountSidW";
357 #else
358 const char * const LookupAccountSid_Name = "LookupAccountSidA";
359 #endif
360 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
361 LPCTSTR lpSystemName,
362 PSID Sid,
363 LPTSTR Name,
364 LPDWORD cbName,
365 LPTSTR DomainName,
366 LPDWORD cbDomainName,
367 PSID_NAME_USE peUse);
368 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
369 PSID pSid,
370 DWORD n);
371 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
372 PSID pSid);
373 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
374 HANDLE handle,
375 SE_OBJECT_TYPE ObjectType,
376 SECURITY_INFORMATION SecurityInfo,
377 PSID *ppsidOwner,
378 PSID *ppsidGroup,
379 PACL *ppDacl,
380 PACL *ppSacl,
381 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
382 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
383 LPCWSTR lpFileName,
384 SECURITY_INFORMATION RequestedInformation,
385 PSECURITY_DESCRIPTOR pSecurityDescriptor,
386 DWORD nLength,
387 LPDWORD lpnLengthNeeded);
388 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
389 LPCSTR lpFileName,
390 SECURITY_INFORMATION RequestedInformation,
391 PSECURITY_DESCRIPTOR pSecurityDescriptor,
392 DWORD nLength,
393 LPDWORD lpnLengthNeeded);
394 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
395 LPCWSTR lpFileName,
396 SECURITY_INFORMATION SecurityInformation,
397 PSECURITY_DESCRIPTOR pSecurityDescriptor);
398 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
399 LPCSTR lpFileName,
400 SECURITY_INFORMATION SecurityInformation,
401 PSECURITY_DESCRIPTOR pSecurityDescriptor);
402 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
403 LPCWSTR lpObjectName,
404 SE_OBJECT_TYPE ObjectType,
405 SECURITY_INFORMATION SecurityInformation,
406 PSID psidOwner,
407 PSID psidGroup,
408 PACL pDacl,
409 PACL pSacl);
410 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
411 LPCSTR lpObjectName,
412 SE_OBJECT_TYPE ObjectType,
413 SECURITY_INFORMATION SecurityInformation,
414 PSID psidOwner,
415 PSID psidGroup,
416 PACL pDacl,
417 PACL pSacl);
418 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
419 PSECURITY_DESCRIPTOR pSecurityDescriptor,
420 PSID *pOwner,
421 LPBOOL lpbOwnerDefaulted);
422 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
423 PSECURITY_DESCRIPTOR pSecurityDescriptor,
424 PSID *pGroup,
425 LPBOOL lpbGroupDefaulted);
426 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
427 PSECURITY_DESCRIPTOR pSecurityDescriptor,
428 LPBOOL lpbDaclPresent,
429 PACL *pDacl,
430 LPBOOL lpbDaclDefaulted);
431 typedef BOOL (WINAPI * IsValidSid_Proc) (
432 PSID sid);
433 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
434 DWORD dwFlags,
435 DWORD th32ProcessID);
436 typedef BOOL (WINAPI * Process32First_Proc) (
437 HANDLE hSnapshot,
438 LPPROCESSENTRY32 lppe);
439 typedef BOOL (WINAPI * Process32Next_Proc) (
440 HANDLE hSnapshot,
441 LPPROCESSENTRY32 lppe);
442 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
443 HANDLE ThreadHandle,
444 DWORD DesiredAccess,
445 BOOL OpenAsSelf,
446 PHANDLE TokenHandle);
447 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
448 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
449 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
450 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
451 HANDLE Process,
452 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
453 DWORD cb);
454 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
455 HANDLE hProcess,
456 PSIZE_T lpMinimumWorkingSetSize,
457 PSIZE_T lpMaximumWorkingSetSize);
458 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
459 LPMEMORYSTATUS lpBuffer);
460 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
461 LPMEMORY_STATUS_EX lpBuffer);
462 typedef BOOL (WINAPI * CopySid_Proc) (
463 DWORD nDestinationSidLength,
464 PSID pDestinationSid,
465 PSID pSourceSid);
466 typedef BOOL (WINAPI * EqualSid_Proc) (
467 PSID pSid1,
468 PSID pSid2);
469 typedef DWORD (WINAPI * GetLengthSid_Proc) (
470 PSID pSid);
471 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
472 LPSYSTEM_INFO lpSystemInfo);
473 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
474 LPFILETIME lpIdleTime,
475 LPFILETIME lpKernelTime,
476 LPFILETIME lpUserTime);
477 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
478 LPCWSTR lpSymlinkFileName,
479 LPCWSTR lpTargetFileName,
480 DWORD dwFlags);
481 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
482 LPCSTR lpSymlinkFileName,
483 LPCSTR lpTargetFileName,
484 DWORD dwFlags);
485 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
486 LPCTSTR StringSecurityDescriptor,
487 DWORD StringSDRevision,
488 PSECURITY_DESCRIPTOR *SecurityDescriptor,
489 PULONG SecurityDescriptorSize);
490 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
491 PSECURITY_DESCRIPTOR SecurityDescriptor,
492 DWORD RequestedStringSDRevision,
493 SECURITY_INFORMATION SecurityInformation,
494 LPTSTR *StringSecurityDescriptor,
495 PULONG StringSecurityDescriptorLen);
496 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
497 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
498 PIP_ADAPTER_INFO pAdapterInfo,
499 PULONG pOutBufLen);
501 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
502 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
503 DWORD multiByteToWideCharFlags;
505 /* ** A utility function ** */
506 static BOOL
507 is_windows_9x (void)
509 static BOOL s_b_ret = 0;
510 OSVERSIONINFO os_ver;
511 if (g_b_init_is_windows_9x == 0)
513 g_b_init_is_windows_9x = 1;
514 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
515 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
516 if (GetVersionEx (&os_ver))
518 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
521 return s_b_ret;
524 static Lisp_Object ltime (ULONGLONG);
526 /* Get total user and system times for get-internal-run-time.
527 Returns a list of integers if the times are provided by the OS
528 (NT derivatives), otherwise it returns the result of current-time. */
529 Lisp_Object w32_get_internal_run_time (void);
531 Lisp_Object
532 w32_get_internal_run_time (void)
534 if (get_process_times_fn)
536 FILETIME create, exit, kernel, user;
537 HANDLE proc = GetCurrentProcess ();
538 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
540 LARGE_INTEGER user_int, kernel_int, total;
541 user_int.LowPart = user.dwLowDateTime;
542 user_int.HighPart = user.dwHighDateTime;
543 kernel_int.LowPart = kernel.dwLowDateTime;
544 kernel_int.HighPart = kernel.dwHighDateTime;
545 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
546 return ltime (total.QuadPart);
550 return Fcurrent_time ();
553 /* ** The wrapper functions ** */
555 static BOOL WINAPI
556 open_process_token (HANDLE ProcessHandle,
557 DWORD DesiredAccess,
558 PHANDLE TokenHandle)
560 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
561 HMODULE hm_advapi32 = NULL;
562 if (is_windows_9x () == TRUE)
564 return FALSE;
566 if (g_b_init_open_process_token == 0)
568 g_b_init_open_process_token = 1;
569 hm_advapi32 = LoadLibrary ("Advapi32.dll");
570 s_pfn_Open_Process_Token =
571 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
573 if (s_pfn_Open_Process_Token == NULL)
575 return FALSE;
577 return (
578 s_pfn_Open_Process_Token (
579 ProcessHandle,
580 DesiredAccess,
581 TokenHandle)
585 static BOOL WINAPI
586 get_token_information (HANDLE TokenHandle,
587 TOKEN_INFORMATION_CLASS TokenInformationClass,
588 LPVOID TokenInformation,
589 DWORD TokenInformationLength,
590 PDWORD ReturnLength)
592 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
593 HMODULE hm_advapi32 = NULL;
594 if (is_windows_9x () == TRUE)
596 return FALSE;
598 if (g_b_init_get_token_information == 0)
600 g_b_init_get_token_information = 1;
601 hm_advapi32 = LoadLibrary ("Advapi32.dll");
602 s_pfn_Get_Token_Information =
603 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
605 if (s_pfn_Get_Token_Information == NULL)
607 return FALSE;
609 return (
610 s_pfn_Get_Token_Information (
611 TokenHandle,
612 TokenInformationClass,
613 TokenInformation,
614 TokenInformationLength,
615 ReturnLength)
619 static BOOL WINAPI
620 lookup_account_sid (LPCTSTR lpSystemName,
621 PSID Sid,
622 LPTSTR Name,
623 LPDWORD cbName,
624 LPTSTR DomainName,
625 LPDWORD cbDomainName,
626 PSID_NAME_USE peUse)
628 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
629 HMODULE hm_advapi32 = NULL;
630 if (is_windows_9x () == TRUE)
632 return FALSE;
634 if (g_b_init_lookup_account_sid == 0)
636 g_b_init_lookup_account_sid = 1;
637 hm_advapi32 = LoadLibrary ("Advapi32.dll");
638 s_pfn_Lookup_Account_Sid =
639 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
641 if (s_pfn_Lookup_Account_Sid == NULL)
643 return FALSE;
645 return (
646 s_pfn_Lookup_Account_Sid (
647 lpSystemName,
648 Sid,
649 Name,
650 cbName,
651 DomainName,
652 cbDomainName,
653 peUse)
657 static PDWORD WINAPI
658 get_sid_sub_authority (PSID pSid, DWORD n)
660 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
661 static DWORD zero = 0U;
662 HMODULE hm_advapi32 = NULL;
663 if (is_windows_9x () == TRUE)
665 return &zero;
667 if (g_b_init_get_sid_sub_authority == 0)
669 g_b_init_get_sid_sub_authority = 1;
670 hm_advapi32 = LoadLibrary ("Advapi32.dll");
671 s_pfn_Get_Sid_Sub_Authority =
672 (GetSidSubAuthority_Proc) GetProcAddress (
673 hm_advapi32, "GetSidSubAuthority");
675 if (s_pfn_Get_Sid_Sub_Authority == NULL)
677 return &zero;
679 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
682 static PUCHAR WINAPI
683 get_sid_sub_authority_count (PSID pSid)
685 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
686 static UCHAR zero = 0U;
687 HMODULE hm_advapi32 = NULL;
688 if (is_windows_9x () == TRUE)
690 return &zero;
692 if (g_b_init_get_sid_sub_authority_count == 0)
694 g_b_init_get_sid_sub_authority_count = 1;
695 hm_advapi32 = LoadLibrary ("Advapi32.dll");
696 s_pfn_Get_Sid_Sub_Authority_Count =
697 (GetSidSubAuthorityCount_Proc) GetProcAddress (
698 hm_advapi32, "GetSidSubAuthorityCount");
700 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
702 return &zero;
704 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
707 static DWORD WINAPI
708 get_security_info (HANDLE handle,
709 SE_OBJECT_TYPE ObjectType,
710 SECURITY_INFORMATION SecurityInfo,
711 PSID *ppsidOwner,
712 PSID *ppsidGroup,
713 PACL *ppDacl,
714 PACL *ppSacl,
715 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
717 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
718 HMODULE hm_advapi32 = NULL;
719 if (is_windows_9x () == TRUE)
721 return FALSE;
723 if (g_b_init_get_security_info == 0)
725 g_b_init_get_security_info = 1;
726 hm_advapi32 = LoadLibrary ("Advapi32.dll");
727 s_pfn_Get_Security_Info =
728 (GetSecurityInfo_Proc) GetProcAddress (
729 hm_advapi32, "GetSecurityInfo");
731 if (s_pfn_Get_Security_Info == NULL)
733 return FALSE;
735 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
736 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
737 ppSecurityDescriptor));
740 static BOOL WINAPI
741 get_file_security (const char *lpFileName,
742 SECURITY_INFORMATION RequestedInformation,
743 PSECURITY_DESCRIPTOR pSecurityDescriptor,
744 DWORD nLength,
745 LPDWORD lpnLengthNeeded)
747 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
748 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
749 HMODULE hm_advapi32 = NULL;
750 if (is_windows_9x () == TRUE)
752 errno = ENOTSUP;
753 return FALSE;
755 if (w32_unicode_filenames)
757 wchar_t filename_w[MAX_PATH];
759 if (g_b_init_get_file_security_w == 0)
761 g_b_init_get_file_security_w = 1;
762 hm_advapi32 = LoadLibrary ("Advapi32.dll");
763 s_pfn_Get_File_SecurityW =
764 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
765 "GetFileSecurityW");
767 if (s_pfn_Get_File_SecurityW == NULL)
769 errno = ENOTSUP;
770 return FALSE;
772 filename_to_utf16 (lpFileName, filename_w);
773 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
774 pSecurityDescriptor, nLength,
775 lpnLengthNeeded));
777 else
779 char filename_a[MAX_PATH];
781 if (g_b_init_get_file_security_a == 0)
783 g_b_init_get_file_security_a = 1;
784 hm_advapi32 = LoadLibrary ("Advapi32.dll");
785 s_pfn_Get_File_SecurityA =
786 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
787 "GetFileSecurityA");
789 if (s_pfn_Get_File_SecurityA == NULL)
791 errno = ENOTSUP;
792 return FALSE;
794 filename_to_ansi (lpFileName, filename_a);
795 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
796 pSecurityDescriptor, nLength,
797 lpnLengthNeeded));
801 static BOOL WINAPI
802 set_file_security (const char *lpFileName,
803 SECURITY_INFORMATION SecurityInformation,
804 PSECURITY_DESCRIPTOR pSecurityDescriptor)
806 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
807 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
808 HMODULE hm_advapi32 = NULL;
809 if (is_windows_9x () == TRUE)
811 errno = ENOTSUP;
812 return FALSE;
814 if (w32_unicode_filenames)
816 wchar_t filename_w[MAX_PATH];
818 if (g_b_init_set_file_security_w == 0)
820 g_b_init_set_file_security_w = 1;
821 hm_advapi32 = LoadLibrary ("Advapi32.dll");
822 s_pfn_Set_File_SecurityW =
823 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
824 "SetFileSecurityW");
826 if (s_pfn_Set_File_SecurityW == NULL)
828 errno = ENOTSUP;
829 return FALSE;
831 filename_to_utf16 (lpFileName, filename_w);
832 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
833 pSecurityDescriptor));
835 else
837 char filename_a[MAX_PATH];
839 if (g_b_init_set_file_security_a == 0)
841 g_b_init_set_file_security_a = 1;
842 hm_advapi32 = LoadLibrary ("Advapi32.dll");
843 s_pfn_Set_File_SecurityA =
844 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
845 "SetFileSecurityA");
847 if (s_pfn_Set_File_SecurityA == NULL)
849 errno = ENOTSUP;
850 return FALSE;
852 filename_to_ansi (lpFileName, filename_a);
853 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
854 pSecurityDescriptor));
858 static DWORD WINAPI
859 set_named_security_info (LPCTSTR lpObjectName,
860 SE_OBJECT_TYPE ObjectType,
861 SECURITY_INFORMATION SecurityInformation,
862 PSID psidOwner,
863 PSID psidGroup,
864 PACL pDacl,
865 PACL pSacl)
867 static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
868 static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
869 HMODULE hm_advapi32 = NULL;
870 if (is_windows_9x () == TRUE)
872 errno = ENOTSUP;
873 return ENOTSUP;
875 if (w32_unicode_filenames)
877 wchar_t filename_w[MAX_PATH];
879 if (g_b_init_set_named_security_info_w == 0)
881 g_b_init_set_named_security_info_w = 1;
882 hm_advapi32 = LoadLibrary ("Advapi32.dll");
883 s_pfn_Set_Named_Security_InfoW =
884 (SetNamedSecurityInfoW_Proc) GetProcAddress (hm_advapi32,
885 "SetNamedSecurityInfoW");
887 if (s_pfn_Set_Named_Security_InfoW == NULL)
889 errno = ENOTSUP;
890 return ENOTSUP;
892 filename_to_utf16 (lpObjectName, filename_w);
893 return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
894 SecurityInformation, psidOwner,
895 psidGroup, pDacl, pSacl));
897 else
899 char filename_a[MAX_PATH];
901 if (g_b_init_set_named_security_info_a == 0)
903 g_b_init_set_named_security_info_a = 1;
904 hm_advapi32 = LoadLibrary ("Advapi32.dll");
905 s_pfn_Set_Named_Security_InfoA =
906 (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
907 "SetNamedSecurityInfoA");
909 if (s_pfn_Set_Named_Security_InfoA == NULL)
911 errno = ENOTSUP;
912 return ENOTSUP;
914 filename_to_ansi (lpObjectName, filename_a);
915 return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
916 SecurityInformation, psidOwner,
917 psidGroup, pDacl, pSacl));
921 static BOOL WINAPI
922 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
923 PSID *pOwner,
924 LPBOOL lpbOwnerDefaulted)
926 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
927 HMODULE hm_advapi32 = NULL;
928 if (is_windows_9x () == TRUE)
930 errno = ENOTSUP;
931 return FALSE;
933 if (g_b_init_get_security_descriptor_owner == 0)
935 g_b_init_get_security_descriptor_owner = 1;
936 hm_advapi32 = LoadLibrary ("Advapi32.dll");
937 s_pfn_Get_Security_Descriptor_Owner =
938 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
939 hm_advapi32, "GetSecurityDescriptorOwner");
941 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
943 errno = ENOTSUP;
944 return FALSE;
946 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
947 lpbOwnerDefaulted));
950 static BOOL WINAPI
951 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
952 PSID *pGroup,
953 LPBOOL lpbGroupDefaulted)
955 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
956 HMODULE hm_advapi32 = NULL;
957 if (is_windows_9x () == TRUE)
959 errno = ENOTSUP;
960 return FALSE;
962 if (g_b_init_get_security_descriptor_group == 0)
964 g_b_init_get_security_descriptor_group = 1;
965 hm_advapi32 = LoadLibrary ("Advapi32.dll");
966 s_pfn_Get_Security_Descriptor_Group =
967 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
968 hm_advapi32, "GetSecurityDescriptorGroup");
970 if (s_pfn_Get_Security_Descriptor_Group == NULL)
972 errno = ENOTSUP;
973 return FALSE;
975 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
976 lpbGroupDefaulted));
979 static BOOL WINAPI
980 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
981 LPBOOL lpbDaclPresent,
982 PACL *pDacl,
983 LPBOOL lpbDaclDefaulted)
985 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
986 HMODULE hm_advapi32 = NULL;
987 if (is_windows_9x () == TRUE)
989 errno = ENOTSUP;
990 return FALSE;
992 if (g_b_init_get_security_descriptor_dacl == 0)
994 g_b_init_get_security_descriptor_dacl = 1;
995 hm_advapi32 = LoadLibrary ("Advapi32.dll");
996 s_pfn_Get_Security_Descriptor_Dacl =
997 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
998 hm_advapi32, "GetSecurityDescriptorDacl");
1000 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
1002 errno = ENOTSUP;
1003 return FALSE;
1005 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
1006 lpbDaclPresent, pDacl,
1007 lpbDaclDefaulted));
1010 static BOOL WINAPI
1011 is_valid_sid (PSID sid)
1013 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
1014 HMODULE hm_advapi32 = NULL;
1015 if (is_windows_9x () == TRUE)
1017 return FALSE;
1019 if (g_b_init_is_valid_sid == 0)
1021 g_b_init_is_valid_sid = 1;
1022 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1023 s_pfn_Is_Valid_Sid =
1024 (IsValidSid_Proc) GetProcAddress (
1025 hm_advapi32, "IsValidSid");
1027 if (s_pfn_Is_Valid_Sid == NULL)
1029 return FALSE;
1031 return (s_pfn_Is_Valid_Sid (sid));
1034 static BOOL WINAPI
1035 equal_sid (PSID sid1, PSID sid2)
1037 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
1038 HMODULE hm_advapi32 = NULL;
1039 if (is_windows_9x () == TRUE)
1041 return FALSE;
1043 if (g_b_init_equal_sid == 0)
1045 g_b_init_equal_sid = 1;
1046 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1047 s_pfn_Equal_Sid =
1048 (EqualSid_Proc) GetProcAddress (
1049 hm_advapi32, "EqualSid");
1051 if (s_pfn_Equal_Sid == NULL)
1053 return FALSE;
1055 return (s_pfn_Equal_Sid (sid1, sid2));
1058 static DWORD WINAPI
1059 get_length_sid (PSID sid)
1061 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
1062 HMODULE hm_advapi32 = NULL;
1063 if (is_windows_9x () == TRUE)
1065 return 0;
1067 if (g_b_init_get_length_sid == 0)
1069 g_b_init_get_length_sid = 1;
1070 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1071 s_pfn_Get_Length_Sid =
1072 (GetLengthSid_Proc) GetProcAddress (
1073 hm_advapi32, "GetLengthSid");
1075 if (s_pfn_Get_Length_Sid == NULL)
1077 return 0;
1079 return (s_pfn_Get_Length_Sid (sid));
1082 static BOOL WINAPI
1083 copy_sid (DWORD destlen, PSID dest, PSID src)
1085 static CopySid_Proc s_pfn_Copy_Sid = NULL;
1086 HMODULE hm_advapi32 = NULL;
1087 if (is_windows_9x () == TRUE)
1089 return FALSE;
1091 if (g_b_init_copy_sid == 0)
1093 g_b_init_copy_sid = 1;
1094 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1095 s_pfn_Copy_Sid =
1096 (CopySid_Proc) GetProcAddress (
1097 hm_advapi32, "CopySid");
1099 if (s_pfn_Copy_Sid == NULL)
1101 return FALSE;
1103 return (s_pfn_Copy_Sid (destlen, dest, src));
1107 END: Wrapper functions around OpenProcessToken
1108 and other functions in advapi32.dll that are only
1109 supported in Windows NT / 2k / XP
1112 static void WINAPI
1113 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1115 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1116 if (is_windows_9x () != TRUE)
1118 if (g_b_init_get_native_system_info == 0)
1120 g_b_init_get_native_system_info = 1;
1121 s_pfn_Get_Native_System_Info =
1122 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1123 "GetNativeSystemInfo");
1125 if (s_pfn_Get_Native_System_Info != NULL)
1126 s_pfn_Get_Native_System_Info (lpSystemInfo);
1128 else
1129 lpSystemInfo->dwNumberOfProcessors = -1;
1132 static BOOL WINAPI
1133 get_system_times (LPFILETIME lpIdleTime,
1134 LPFILETIME lpKernelTime,
1135 LPFILETIME lpUserTime)
1137 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1138 if (is_windows_9x () == TRUE)
1140 return FALSE;
1142 if (g_b_init_get_system_times == 0)
1144 g_b_init_get_system_times = 1;
1145 s_pfn_Get_System_times =
1146 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1147 "GetSystemTimes");
1149 if (s_pfn_Get_System_times == NULL)
1150 return FALSE;
1151 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1154 static BOOLEAN WINAPI
1155 create_symbolic_link (LPCSTR lpSymlinkFilename,
1156 LPCSTR lpTargetFileName,
1157 DWORD dwFlags)
1159 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1160 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1161 BOOLEAN retval;
1163 if (is_windows_9x () == TRUE)
1165 errno = ENOSYS;
1166 return 0;
1168 if (w32_unicode_filenames)
1170 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1172 if (g_b_init_create_symbolic_link_w == 0)
1174 g_b_init_create_symbolic_link_w = 1;
1175 s_pfn_Create_Symbolic_LinkW =
1176 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1177 "CreateSymbolicLinkW");
1179 if (s_pfn_Create_Symbolic_LinkW == NULL)
1181 errno = ENOSYS;
1182 return 0;
1185 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1186 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1187 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1188 /* If we were denied creation of the symlink, try again after
1189 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1190 if (!retval)
1192 TOKEN_PRIVILEGES priv_current;
1194 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1195 &priv_current))
1197 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1198 restore_privilege (&priv_current);
1199 revert_to_self ();
1203 else
1205 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1207 if (g_b_init_create_symbolic_link_a == 0)
1209 g_b_init_create_symbolic_link_a = 1;
1210 s_pfn_Create_Symbolic_LinkA =
1211 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1212 "CreateSymbolicLinkA");
1214 if (s_pfn_Create_Symbolic_LinkA == NULL)
1216 errno = ENOSYS;
1217 return 0;
1220 filename_to_ansi (lpSymlinkFilename, symfn_a);
1221 filename_to_ansi (lpTargetFileName, tgtfn_a);
1222 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1223 /* If we were denied creation of the symlink, try again after
1224 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1225 if (!retval)
1227 TOKEN_PRIVILEGES priv_current;
1229 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1230 &priv_current))
1232 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1233 restore_privilege (&priv_current);
1234 revert_to_self ();
1238 return retval;
1241 static BOOL WINAPI
1242 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1244 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1246 if (is_windows_9x () == TRUE)
1248 errno = ENOTSUP;
1249 return FALSE;
1252 if (g_b_init_is_valid_security_descriptor == 0)
1254 g_b_init_is_valid_security_descriptor = 1;
1255 s_pfn_Is_Valid_Security_Descriptor_Proc =
1256 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1257 "IsValidSecurityDescriptor");
1259 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1261 errno = ENOTSUP;
1262 return FALSE;
1265 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1268 static BOOL WINAPI
1269 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1270 DWORD RequestedStringSDRevision,
1271 SECURITY_INFORMATION SecurityInformation,
1272 LPTSTR *StringSecurityDescriptor,
1273 PULONG StringSecurityDescriptorLen)
1275 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1276 BOOL retval;
1278 if (is_windows_9x () == TRUE)
1280 errno = ENOTSUP;
1281 return FALSE;
1284 if (g_b_init_convert_sd_to_sddl == 0)
1286 g_b_init_convert_sd_to_sddl = 1;
1287 #ifdef _UNICODE
1288 s_pfn_Convert_SD_To_SDDL =
1289 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1290 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1291 #else
1292 s_pfn_Convert_SD_To_SDDL =
1293 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1294 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1295 #endif
1297 if (s_pfn_Convert_SD_To_SDDL == NULL)
1299 errno = ENOTSUP;
1300 return FALSE;
1303 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1304 RequestedStringSDRevision,
1305 SecurityInformation,
1306 StringSecurityDescriptor,
1307 StringSecurityDescriptorLen);
1309 return retval;
1312 static BOOL WINAPI
1313 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1314 DWORD StringSDRevision,
1315 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1316 PULONG SecurityDescriptorSize)
1318 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1319 BOOL retval;
1321 if (is_windows_9x () == TRUE)
1323 errno = ENOTSUP;
1324 return FALSE;
1327 if (g_b_init_convert_sddl_to_sd == 0)
1329 g_b_init_convert_sddl_to_sd = 1;
1330 #ifdef _UNICODE
1331 s_pfn_Convert_SDDL_To_SD =
1332 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1333 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1334 #else
1335 s_pfn_Convert_SDDL_To_SD =
1336 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1337 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1338 #endif
1340 if (s_pfn_Convert_SDDL_To_SD == NULL)
1342 errno = ENOTSUP;
1343 return FALSE;
1346 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1347 StringSDRevision,
1348 SecurityDescriptor,
1349 SecurityDescriptorSize);
1351 return retval;
1354 static DWORD WINAPI
1355 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1357 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1358 HMODULE hm_iphlpapi = NULL;
1360 if (is_windows_9x () == TRUE)
1361 return ERROR_NOT_SUPPORTED;
1363 if (g_b_init_get_adapters_info == 0)
1365 g_b_init_get_adapters_info = 1;
1366 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1367 if (hm_iphlpapi)
1368 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1369 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1371 if (s_pfn_Get_Adapters_Info == NULL)
1372 return ERROR_NOT_SUPPORTED;
1373 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1378 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1379 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1381 This is called from alloc.c:valid_pointer_p. */
1383 w32_valid_pointer_p (void *p, int size)
1385 SIZE_T done;
1386 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1388 if (h)
1390 unsigned char *buf = alloca (size);
1391 int retval = ReadProcessMemory (h, p, buf, size, &done);
1393 CloseHandle (h);
1394 return retval;
1396 else
1397 return -1;
1402 /* Here's an overview of how the Windows build supports file names
1403 that cannot be encoded by the current system codepage.
1405 From the POV of Lisp and layers of C code above the functions here,
1406 Emacs on Windows pretends that its file names are encoded in UTF-8;
1407 see encode_file and decode_file on coding.c. Any file name that is
1408 passed as a unibyte string to C functions defined here is assumed
1409 to be in UTF-8 encoding. Any file name returned by functions
1410 defined here must be in UTF-8 encoding, with only a few exceptions
1411 reserved for a couple of special cases. (Be sure to use
1412 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1413 as they can be much longer than MAX_PATH!)
1415 The UTF-8 encoded file names cannot be passed to system APIs, as
1416 Windows does not support that. Therefore, they are converted
1417 either to UTF-16 or to the ANSI codepage, depending on the value of
1418 w32-unicode-filenames, before calling any system APIs or CRT library
1419 functions. The default value of that variable is determined by the
1420 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1421 user can change that default (although I don't see why would she
1422 want to).
1424 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1425 filename_from_utf16, and filename_from_ansi, are the workhorses of
1426 these conversions. They rely on Windows native APIs
1427 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1428 functions from coding.c here, because they allocate memory, which
1429 is a bad idea on the level of libc, which is what the functions
1430 here emulate. (If you worry about performance due to constant
1431 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1432 it was measured to take only a few microseconds on a not-so-fast
1433 machine, and second, that's exactly what the ANSI APIs we used
1434 before did anyway, because they are just thin wrappers around the
1435 Unicode APIs.)
1437 The variables file-name-coding-system and default-file-name-coding-system
1438 still exist, but are actually used only when a file name needs to
1439 be converted to the ANSI codepage. This happens all the time when
1440 w32-unicode-filenames is nil, but can also happen from time to time
1441 when it is t. Otherwise, these variables have no effect on file-name
1442 encoding when w32-unicode-filenames is t; this is similar to
1443 selection-coding-system.
1445 This arrangement works very well, but it has a few gotchas and
1446 limitations:
1448 . Lisp code that encodes or decodes file names manually should
1449 normally use 'utf-8' as the coding-system on Windows,
1450 disregarding file-name-coding-system. This is a somewhat
1451 unpleasant consequence, but it cannot be avoided. Fortunately,
1452 very few Lisp packages need to do that.
1454 More generally, passing to library functions (e.g., fopen or
1455 opendir) file names already encoded in the ANSI codepage is
1456 explicitly *verboten*, as all those functions, as shadowed and
1457 emulated here, assume they will receive UTF-8 encoded file names.
1459 For the same reasons, no CRT function or Win32 API can be called
1460 directly in Emacs sources, without either converting the file
1461 names from UTF-8 to UTF-16 or ANSI codepage, or going through
1462 some shadowing function defined here.
1464 . Environment variables stored in Vprocess_environment are encoded
1465 in the ANSI codepage, so if getenv/egetenv is used for a variable
1466 whose value is a file name or a list of directories, it needs to
1467 be converted to UTF-8, before it is used as argument to functions
1468 or decoded into a Lisp string.
1470 . File names passed to external libraries, like the image libraries
1471 and GnuTLS, need special handling. These libraries generally
1472 don't support UTF-16 or UTF-8 file names, so they must get file
1473 names encoded in the ANSI codepage. To facilitate using these
1474 libraries with file names that are not encodable in the ANSI
1475 codepage, use the function ansi_encode_filename, which will try
1476 to use the short 8+3 alias of a file name if that file name is
1477 not encodable in the ANSI codepage. See image.c and gnutls.c for
1478 examples of how this should be done.
1480 . Running subprocesses in non-ASCII directories and with non-ASCII
1481 file arguments is limited to the current codepage (even though
1482 Emacs is perfectly capable of finding an executable program file
1483 in a directory whose name cannot be encoded in the current
1484 codepage). This is because the command-line arguments are
1485 encoded _before_ they get to the w32-specific level, and the
1486 encoding is not known in advance (it doesn't have to be the
1487 current ANSI codepage), so w32proc.c functions cannot re-encode
1488 them in UTF-16. This should be fixed, but will also require
1489 changes in cmdproxy. The current limitation is not terribly bad
1490 anyway, since very few, if any, Windows console programs that are
1491 likely to be invoked by Emacs support UTF-16 encoded command
1492 lines.
1494 . For similar reasons, server.el and emacsclient are also limited
1495 to the current ANSI codepage for now.
1497 . Emacs itself can only handle command-line arguments encoded in
1498 the current codepage.
1500 . Turning on w32-unicode-filename on Windows 9X (if it at all
1501 works) requires UNICOWS.DLL, which is thus a requirement even in
1502 non-GUI sessions, something the we previously avoided. */
1506 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1507 codepage defined by file-name-coding-system. */
1509 /* Current codepage for encoding file names. */
1510 static int file_name_codepage;
1512 /* Produce a Windows ANSI codepage suitable for encoding file names.
1513 Return the information about that codepage in CP_INFO. */
1515 codepage_for_filenames (CPINFO *cp_info)
1517 /* A simple cache to avoid calling GetCPInfo every time we need to
1518 encode/decode a file name. The file-name encoding is not
1519 supposed to be changed too frequently, if ever. */
1520 static Lisp_Object last_file_name_encoding;
1521 static CPINFO cp;
1522 Lisp_Object current_encoding;
1524 current_encoding = Vfile_name_coding_system;
1525 if (NILP (current_encoding))
1526 current_encoding = Vdefault_file_name_coding_system;
1528 if (!EQ (last_file_name_encoding, current_encoding))
1530 /* Default to the current ANSI codepage. */
1531 file_name_codepage = w32_ansi_code_page;
1533 if (NILP (current_encoding))
1535 char *cpname = SSDATA (SYMBOL_NAME (current_encoding));
1536 char *cp = NULL, *end;
1537 int cpnum;
1539 if (strncmp (cpname, "cp", 2) == 0)
1540 cp = cpname + 2;
1541 else if (strncmp (cpname, "windows-", 8) == 0)
1542 cp = cpname + 8;
1544 if (cp)
1546 end = cp;
1547 cpnum = strtol (cp, &end, 10);
1548 if (cpnum && *end == '\0' && end - cp >= 2)
1549 file_name_codepage = cpnum;
1553 if (!file_name_codepage)
1554 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1556 if (!GetCPInfo (file_name_codepage, &cp))
1558 file_name_codepage = CP_ACP;
1559 if (!GetCPInfo (file_name_codepage, &cp))
1560 emacs_abort ();
1563 if (cp_info)
1564 *cp_info = cp;
1566 return file_name_codepage;
1570 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1572 int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
1573 -1, fn_out, MAX_PATH);
1575 if (!result)
1577 DWORD err = GetLastError ();
1579 switch (err)
1581 case ERROR_INVALID_FLAGS:
1582 case ERROR_INVALID_PARAMETER:
1583 errno = EINVAL;
1584 break;
1585 case ERROR_INSUFFICIENT_BUFFER:
1586 case ERROR_NO_UNICODE_TRANSLATION:
1587 default:
1588 errno = ENOENT;
1589 break;
1591 return -1;
1593 return 0;
1597 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1599 int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1600 fn_out, MAX_UTF8_PATH, NULL, NULL);
1602 if (!result)
1604 DWORD err = GetLastError ();
1606 switch (err)
1608 case ERROR_INVALID_FLAGS:
1609 case ERROR_INVALID_PARAMETER:
1610 errno = EINVAL;
1611 break;
1612 case ERROR_INSUFFICIENT_BUFFER:
1613 case ERROR_NO_UNICODE_TRANSLATION:
1614 default:
1615 errno = ENOENT;
1616 break;
1618 return -1;
1620 return 0;
1624 filename_to_ansi (const char *fn_in, char *fn_out)
1626 wchar_t fn_utf16[MAX_PATH];
1628 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1630 int result;
1631 int codepage = codepage_for_filenames (NULL);
1633 result = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
1634 fn_out, MAX_PATH, NULL, NULL);
1635 if (!result)
1637 DWORD err = GetLastError ();
1639 switch (err)
1641 case ERROR_INVALID_FLAGS:
1642 case ERROR_INVALID_PARAMETER:
1643 errno = EINVAL;
1644 break;
1645 case ERROR_INSUFFICIENT_BUFFER:
1646 case ERROR_NO_UNICODE_TRANSLATION:
1647 default:
1648 errno = ENOENT;
1649 break;
1651 return -1;
1653 return 0;
1655 return -1;
1659 filename_from_ansi (const char *fn_in, char *fn_out)
1661 wchar_t fn_utf16[MAX_PATH];
1662 int codepage = codepage_for_filenames (NULL);
1663 int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
1664 -1, fn_utf16, MAX_PATH);
1666 if (!result)
1668 DWORD err = GetLastError ();
1670 switch (err)
1672 case ERROR_INVALID_FLAGS:
1673 case ERROR_INVALID_PARAMETER:
1674 errno = EINVAL;
1675 break;
1676 case ERROR_INSUFFICIENT_BUFFER:
1677 case ERROR_NO_UNICODE_TRANSLATION:
1678 default:
1679 errno = ENOENT;
1680 break;
1682 return -1;
1684 return filename_from_utf16 (fn_utf16, fn_out);
1689 /* The directory where we started, in UTF-8. */
1690 static char startup_dir[MAX_UTF8_PATH];
1692 /* Get the current working directory. */
1693 char *
1694 getcwd (char *dir, int dirsize)
1696 if (!dirsize)
1698 errno = EINVAL;
1699 return NULL;
1701 if (dirsize <= strlen (startup_dir))
1703 errno = ERANGE;
1704 return NULL;
1706 #if 0
1707 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1708 return dir;
1709 return NULL;
1710 #else
1711 /* Emacs doesn't actually change directory itself, it stays in the
1712 same directory where it was started. */
1713 strcpy (dir, startup_dir);
1714 return dir;
1715 #endif
1718 /* Emulate getloadavg. */
1720 struct load_sample {
1721 time_t sample_time;
1722 ULONGLONG idle;
1723 ULONGLONG kernel;
1724 ULONGLONG user;
1727 /* Number of processors on this machine. */
1728 static unsigned num_of_processors;
1730 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1731 static struct load_sample samples[16*60];
1732 static int first_idx = -1, last_idx = -1;
1733 static int max_idx = ARRAYELTS (samples);
1735 static int
1736 buf_next (int from)
1738 int next_idx = from + 1;
1740 if (next_idx >= max_idx)
1741 next_idx = 0;
1743 return next_idx;
1746 static int
1747 buf_prev (int from)
1749 int prev_idx = from - 1;
1751 if (prev_idx < 0)
1752 prev_idx = max_idx - 1;
1754 return prev_idx;
1757 static void
1758 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1760 SYSTEM_INFO sysinfo;
1761 FILETIME ft_idle, ft_user, ft_kernel;
1763 /* Initialize the number of processors on this machine. */
1764 if (num_of_processors <= 0)
1766 get_native_system_info (&sysinfo);
1767 num_of_processors = sysinfo.dwNumberOfProcessors;
1768 if (num_of_processors <= 0)
1770 GetSystemInfo (&sysinfo);
1771 num_of_processors = sysinfo.dwNumberOfProcessors;
1773 if (num_of_processors <= 0)
1774 num_of_processors = 1;
1777 /* TODO: Take into account threads that are ready to run, by
1778 sampling the "\System\Processor Queue Length" performance
1779 counter. The code below accounts only for threads that are
1780 actually running. */
1782 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1784 ULARGE_INTEGER uidle, ukernel, uuser;
1786 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1787 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1788 memcpy (&uuser, &ft_user, sizeof (ft_user));
1789 *idle = uidle.QuadPart;
1790 *kernel = ukernel.QuadPart;
1791 *user = uuser.QuadPart;
1793 else
1795 *idle = 0;
1796 *kernel = 0;
1797 *user = 0;
1801 /* Produce the load average for a given time interval, using the
1802 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1803 1-minute, 5-minute, or 15-minute average, respectively. */
1804 static double
1805 getavg (int which)
1807 double retval = -1.0;
1808 double tdiff;
1809 int idx;
1810 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1811 time_t now = samples[last_idx].sample_time;
1813 if (first_idx != last_idx)
1815 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1817 tdiff = difftime (now, samples[idx].sample_time);
1818 if (tdiff >= span - 2*DBL_EPSILON*now)
1820 long double sys =
1821 samples[last_idx].kernel + samples[last_idx].user
1822 - (samples[idx].kernel + samples[idx].user);
1823 long double idl = samples[last_idx].idle - samples[idx].idle;
1825 retval = (1.0 - idl / sys) * num_of_processors;
1826 break;
1828 if (idx == first_idx)
1829 break;
1833 return retval;
1837 getloadavg (double loadavg[], int nelem)
1839 int elem;
1840 ULONGLONG idle, kernel, user;
1841 time_t now = time (NULL);
1843 /* If system time jumped back for some reason, delete all samples
1844 whose time is later than the current wall-clock time. This
1845 prevents load average figures from becoming frozen for prolonged
1846 periods of time, when system time is reset backwards. */
1847 if (last_idx >= 0)
1849 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1851 if (last_idx == first_idx)
1853 first_idx = last_idx = -1;
1854 break;
1856 last_idx = buf_prev (last_idx);
1860 /* Store another sample. We ignore samples that are less than 1 sec
1861 apart. */
1862 if (last_idx < 0
1863 || (difftime (now, samples[last_idx].sample_time)
1864 >= 1.0 - 2*DBL_EPSILON*now))
1866 sample_system_load (&idle, &kernel, &user);
1867 last_idx = buf_next (last_idx);
1868 samples[last_idx].sample_time = now;
1869 samples[last_idx].idle = idle;
1870 samples[last_idx].kernel = kernel;
1871 samples[last_idx].user = user;
1872 /* If the buffer has more that 15 min worth of samples, discard
1873 the old ones. */
1874 if (first_idx == -1)
1875 first_idx = last_idx;
1876 while (first_idx != last_idx
1877 && (difftime (now, samples[first_idx].sample_time)
1878 >= 15.0*60 + 2*DBL_EPSILON*now))
1879 first_idx = buf_next (first_idx);
1882 for (elem = 0; elem < nelem; elem++)
1884 double avg = getavg (elem);
1886 if (avg < 0)
1887 break;
1888 loadavg[elem] = avg;
1891 return elem;
1894 /* Emulate getpwuid, getpwnam and others. */
1896 #define PASSWD_FIELD_SIZE 256
1898 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1899 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1900 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1901 static char dflt_passwd_dir[MAX_UTF8_PATH];
1902 static char dflt_passwd_shell[MAX_UTF8_PATH];
1904 static struct passwd dflt_passwd =
1906 dflt_passwd_name,
1907 dflt_passwd_passwd,
1911 dflt_passwd_gecos,
1912 dflt_passwd_dir,
1913 dflt_passwd_shell,
1916 static char dflt_group_name[GNLEN+1];
1918 static struct group dflt_group =
1920 /* When group information is not available, we return this as the
1921 group for all files. */
1922 dflt_group_name,
1926 unsigned
1927 getuid (void)
1929 return dflt_passwd.pw_uid;
1932 unsigned
1933 geteuid (void)
1935 /* I could imagine arguing for checking to see whether the user is
1936 in the Administrators group and returning a UID of 0 for that
1937 case, but I don't know how wise that would be in the long run. */
1938 return getuid ();
1941 unsigned
1942 getgid (void)
1944 return dflt_passwd.pw_gid;
1947 unsigned
1948 getegid (void)
1950 return getgid ();
1953 struct passwd *
1954 getpwuid (unsigned uid)
1956 if (uid == dflt_passwd.pw_uid)
1957 return &dflt_passwd;
1958 return NULL;
1961 struct group *
1962 getgrgid (gid_t gid)
1964 return &dflt_group;
1967 struct passwd *
1968 getpwnam (char *name)
1970 struct passwd *pw;
1972 pw = getpwuid (getuid ());
1973 if (!pw)
1974 return pw;
1976 if (xstrcasecmp (name, pw->pw_name))
1977 return NULL;
1979 return pw;
1982 static void
1983 init_user_info (void)
1985 /* Find the user's real name by opening the process token and
1986 looking up the name associated with the user-sid in that token.
1988 Use the relative portion of the identifier authority value from
1989 the user-sid as the user id value (same for group id using the
1990 primary group sid from the process token). */
1992 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1993 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1994 DWORD glength = sizeof (gname);
1995 HANDLE token = NULL;
1996 SID_NAME_USE user_type;
1997 unsigned char *buf = NULL;
1998 DWORD blen = 0;
1999 TOKEN_USER user_token;
2000 TOKEN_PRIMARY_GROUP group_token;
2001 BOOL result;
2003 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
2004 if (result)
2006 result = get_token_information (token, TokenUser, NULL, 0, &blen);
2007 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2009 buf = xmalloc (blen);
2010 result = get_token_information (token, TokenUser,
2011 (LPVOID)buf, blen, &needed);
2012 if (result)
2014 memcpy (&user_token, buf, sizeof (user_token));
2015 result = lookup_account_sid (NULL, user_token.User.Sid,
2016 uname, &ulength,
2017 domain, &dlength, &user_type);
2020 else
2021 result = FALSE;
2023 if (result)
2025 strcpy (dflt_passwd.pw_name, uname);
2026 /* Determine a reasonable uid value. */
2027 if (xstrcasecmp ("administrator", uname) == 0)
2029 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
2030 dflt_passwd.pw_gid = 513; /* well-known None gid */
2032 else
2034 /* Use the last sub-authority value of the RID, the relative
2035 portion of the SID, as user/group ID. */
2036 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
2038 /* Get group id and name. */
2039 result = get_token_information (token, TokenPrimaryGroup,
2040 (LPVOID)buf, blen, &needed);
2041 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2043 buf = xrealloc (buf, blen = needed);
2044 result = get_token_information (token, TokenPrimaryGroup,
2045 (LPVOID)buf, blen, &needed);
2047 if (result)
2049 memcpy (&group_token, buf, sizeof (group_token));
2050 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
2051 dlength = sizeof (domain);
2052 /* If we can get at the real Primary Group name, use that.
2053 Otherwise, the default group name was already set to
2054 "None" in globals_of_w32. */
2055 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
2056 gname, &glength, NULL, &dlength,
2057 &user_type))
2058 strcpy (dflt_group_name, gname);
2060 else
2061 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2064 /* If security calls are not supported (presumably because we
2065 are running under Windows 9X), fallback to this: */
2066 else if (GetUserName (uname, &ulength))
2068 strcpy (dflt_passwd.pw_name, uname);
2069 if (xstrcasecmp ("administrator", uname) == 0)
2070 dflt_passwd.pw_uid = 0;
2071 else
2072 dflt_passwd.pw_uid = 123;
2073 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2075 else
2077 strcpy (dflt_passwd.pw_name, "unknown");
2078 dflt_passwd.pw_uid = 123;
2079 dflt_passwd.pw_gid = 123;
2081 dflt_group.gr_gid = dflt_passwd.pw_gid;
2083 /* Set dir and shell from environment variables. */
2084 if (w32_unicode_filenames)
2086 wchar_t *home = _wgetenv (L"HOME");
2087 wchar_t *shell = _wgetenv (L"SHELL");
2089 /* Ensure HOME and SHELL are defined. */
2090 if (home == NULL)
2091 emacs_abort ();
2092 if (shell == NULL)
2093 emacs_abort ();
2094 filename_from_utf16 (home, dflt_passwd.pw_dir);
2095 filename_from_utf16 (shell, dflt_passwd.pw_shell);
2097 else
2099 char *home = getenv ("HOME");
2100 char *shell = getenv ("SHELL");
2102 if (home == NULL)
2103 emacs_abort ();
2104 if (shell == NULL)
2105 emacs_abort ();
2106 filename_from_ansi (home, dflt_passwd.pw_dir);
2107 filename_from_ansi (shell, dflt_passwd.pw_shell);
2110 xfree (buf);
2111 if (token)
2112 CloseHandle (token);
2115 static HCRYPTPROV w32_crypto_hprov;
2116 static int
2117 w32_init_crypt_random (void)
2119 if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL,
2120 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2122 DebPrint (("CryptAcquireContext failed with error %x\n",
2123 GetLastError ()));
2124 w32_crypto_hprov = 0;
2125 return -1;
2127 return 0;
2131 w32_init_random (void *buf, ptrdiff_t buflen)
2133 if (!w32_crypto_hprov)
2134 w32_init_crypt_random ();
2135 if (w32_crypto_hprov)
2137 if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf))
2138 return 0;
2140 return -1;
2144 random (void)
2146 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
2147 return ((rand () << 15) | rand ());
2150 void
2151 srandom (int seed)
2153 srand (seed);
2156 /* Return the maximum length in bytes of a multibyte character
2157 sequence encoded in the current ANSI codepage. This is required to
2158 correctly walk the encoded file names one character at a time. */
2159 static int
2160 max_filename_mbslen (void)
2162 CPINFO cp_info;
2164 codepage_for_filenames (&cp_info);
2165 return cp_info.MaxCharSize;
2168 /* Normalize filename by converting in-place all of its path
2169 separators to the separator specified by PATH_SEP. */
2171 static void
2172 normalize_filename (register char *fp, char path_sep)
2174 char *p2;
2176 /* Always lower-case drive letters a-z, even if the filesystem
2177 preserves case in filenames.
2178 This is so filenames can be compared by string comparison
2179 functions that are case-sensitive. Even case-preserving filesystems
2180 do not distinguish case in drive letters. */
2181 p2 = fp + 1;
2183 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2185 *fp += 'a' - 'A';
2186 fp += 2;
2189 while (*fp)
2191 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2192 *fp = path_sep;
2193 fp++;
2197 /* Destructively turn backslashes into slashes. */
2198 void
2199 dostounix_filename (register char *p)
2201 normalize_filename (p, '/');
2204 /* Destructively turn slashes into backslashes. */
2205 void
2206 unixtodos_filename (register char *p)
2208 normalize_filename (p, '\\');
2211 /* Remove all CR's that are followed by a LF.
2212 (From msdos.c...probably should figure out a way to share it,
2213 although this code isn't going to ever change.) */
2214 static int
2215 crlf_to_lf (register int n, register char *buf)
2217 unsigned char *np = (unsigned char *)buf;
2218 unsigned char *startp = np;
2219 char *endp = buf + n;
2221 if (n == 0)
2222 return n;
2223 while (buf < endp - 1)
2225 if (*buf == 0x0d)
2227 if (*(++buf) != 0x0a)
2228 *np++ = 0x0d;
2230 else
2231 *np++ = *buf++;
2233 if (buf < endp)
2234 *np++ = *buf++;
2235 return np - startp;
2238 /* Parse the root part of file name, if present. Return length and
2239 optionally store pointer to char after root. */
2240 static int
2241 parse_root (const char * name, const char ** pPath)
2243 const char * start = name;
2245 if (name == NULL)
2246 return 0;
2248 /* find the root name of the volume if given */
2249 if (isalpha (name[0]) && name[1] == ':')
2251 /* skip past drive specifier */
2252 name += 2;
2253 if (IS_DIRECTORY_SEP (name[0]))
2254 name++;
2256 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2258 int slashes = 2;
2260 name += 2;
2263 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2264 break;
2265 name++;
2267 while ( *name );
2268 if (IS_DIRECTORY_SEP (name[0]))
2269 name++;
2272 if (pPath)
2273 *pPath = name;
2275 return name - start;
2278 /* Get long base name for name; name is assumed to be absolute. */
2279 static int
2280 get_long_basename (char * name, char * buf, int size)
2282 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2283 char fname_utf8[MAX_UTF8_PATH];
2284 int len = 0;
2285 int cstatus = -1;
2287 /* Must be valid filename, no wild cards or other invalid characters. */
2288 if (strpbrk (name, "*?|<>\""))
2289 return 0;
2291 if (w32_unicode_filenames)
2293 wchar_t fname_utf16[MAX_PATH];
2294 WIN32_FIND_DATAW find_data_wide;
2296 filename_to_utf16 (name, fname_utf16);
2297 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2298 if (dir_handle != INVALID_HANDLE_VALUE)
2299 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2301 else
2303 char fname_ansi[MAX_PATH];
2304 WIN32_FIND_DATAA find_data_ansi;
2306 filename_to_ansi (name, fname_ansi);
2307 /* If the ANSI name includes ? characters, it is not encodable
2308 in the ANSI codepage. In that case, we deliver the question
2309 marks to the caller; calling FindFirstFileA in this case
2310 could return some unrelated file name in the same
2311 directory. */
2312 if (_mbspbrk (fname_ansi, "?"))
2314 /* Find the basename of fname_ansi. */
2315 char *p = strrchr (fname_ansi, '\\');
2317 if (!p)
2318 p = fname_ansi;
2319 else
2320 p++;
2321 cstatus = filename_from_ansi (p, fname_utf8);
2323 else
2325 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2326 if (dir_handle != INVALID_HANDLE_VALUE)
2327 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2331 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2332 memcpy (buf, fname_utf8, len + 1);
2333 else
2334 len = 0;
2336 if (dir_handle != INVALID_HANDLE_VALUE)
2337 FindClose (dir_handle);
2339 return len;
2342 /* Get long name for file, if possible (assumed to be absolute). */
2343 BOOL
2344 w32_get_long_filename (const char * name, char * buf, int size)
2346 char * o = buf;
2347 char * p;
2348 const char * q;
2349 char full[ MAX_UTF8_PATH ];
2350 int len;
2352 len = strlen (name);
2353 if (len >= MAX_UTF8_PATH)
2354 return FALSE;
2356 /* Use local copy for destructive modification. */
2357 memcpy (full, name, len+1);
2358 unixtodos_filename (full);
2360 /* Copy root part verbatim. */
2361 len = parse_root (full, (const char **)&p);
2362 memcpy (o, full, len);
2363 o += len;
2364 *o = '\0';
2365 size -= len;
2367 while (p != NULL && *p)
2369 q = p;
2370 p = strchr (q, '\\');
2371 if (p) *p = '\0';
2372 len = get_long_basename (full, o, size);
2373 if (len > 0)
2375 o += len;
2376 size -= len;
2377 if (p != NULL)
2379 *p++ = '\\';
2380 if (size < 2)
2381 return FALSE;
2382 *o++ = '\\';
2383 size--;
2384 *o = '\0';
2387 else
2388 return FALSE;
2391 return TRUE;
2394 unsigned int
2395 w32_get_short_filename (const char * name, char * buf, int size)
2397 if (w32_unicode_filenames)
2399 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2400 unsigned int retval;
2402 filename_to_utf16 (name, name_utf16);
2403 retval = GetShortPathNameW (name_utf16, short_name, size);
2404 if (retval && retval < size)
2405 filename_from_utf16 (short_name, buf);
2406 return retval;
2408 else
2410 char name_ansi[MAX_PATH];
2412 filename_to_ansi (name, name_ansi);
2413 return GetShortPathNameA (name_ansi, buf, size);
2417 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2418 MS-Windows ANSI codepage. If FILENAME includes characters not
2419 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2420 if it exists. This is needed because the w32 build wants to
2421 support file names outside of the system locale, but image
2422 libraries typically don't support wide (a.k.a. "Unicode") APIs
2423 required for that. */
2425 Lisp_Object
2426 ansi_encode_filename (Lisp_Object filename)
2428 Lisp_Object encoded_filename;
2429 char fname[MAX_PATH];
2431 filename_to_ansi (SSDATA (filename), fname);
2432 if (_mbspbrk (fname, "?"))
2434 char shortname[MAX_PATH];
2436 if (w32_get_short_filename (SSDATA (filename), shortname, MAX_PATH))
2438 dostounix_filename (shortname);
2439 encoded_filename = build_string (shortname);
2441 else
2442 encoded_filename = build_unibyte_string (fname);
2444 else
2445 encoded_filename = build_unibyte_string (fname);
2446 return encoded_filename;
2449 static int
2450 is_unc_volume (const char *filename)
2452 const char *ptr = filename;
2454 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2455 return 0;
2457 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2458 return 0;
2460 return 1;
2463 /* Emulate the Posix unsetenv. */
2465 unsetenv (const char *name)
2467 char *var;
2468 size_t name_len;
2470 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2472 errno = EINVAL;
2473 return -1;
2475 name_len = strlen (name);
2476 /* MS docs says an environment variable cannot be longer than 32K. */
2477 if (name_len > 32767)
2479 errno = ENOMEM;
2480 return 0;
2482 /* It is safe to use 'alloca' with 32K size, since the stack is at
2483 least 2MB, and we set it to 8MB in the link command line. */
2484 var = alloca (name_len + 2);
2485 strncpy (var, name, name_len);
2486 var[name_len++] = '=';
2487 var[name_len] = '\0';
2488 return _putenv (var);
2491 /* MS _putenv doesn't support removing a variable when the argument
2492 does not include the '=' character, so we fix that here. */
2494 sys_putenv (char *str)
2496 const char *const name_end = strchr (str, '=');
2498 if (name_end == NULL)
2500 /* Remove the variable from the environment. */
2501 return unsetenv (str);
2504 if (strncmp (str, "TZ=<", 4) == 0)
2506 /* MS-Windows does not support POSIX.1-2001 angle-bracket TZ
2507 abbreviation syntax. Convert to POSIX.1-1988 syntax if possible,
2508 and to the undocumented placeholder "ZZZ" otherwise. */
2509 bool supported_abbr = true;
2510 for (char *p = str + 4; *p; p++)
2512 if (('0' <= *p && *p <= '9') || *p == '-' || *p == '+')
2513 supported_abbr = false;
2514 else if (*p == '>')
2516 ptrdiff_t abbrlen;
2517 if (supported_abbr)
2519 abbrlen = p - (str + 4);
2520 memmove (str + 3, str + 4, abbrlen);
2522 else
2524 abbrlen = 3;
2525 memset (str + 3, 'Z', abbrlen);
2527 memmove (str + 3 + abbrlen, p + 1, strlen (p));
2528 break;
2533 return _putenv (str);
2536 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2538 LPBYTE
2539 w32_get_resource (const char *key, LPDWORD lpdwtype)
2541 LPBYTE lpvalue;
2542 HKEY hrootkey = NULL;
2543 DWORD cbData;
2545 /* Check both the current user and the local machine to see if
2546 we have any resources. */
2548 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2550 lpvalue = NULL;
2552 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2553 && (lpvalue = xmalloc (cbData)) != NULL
2554 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2556 RegCloseKey (hrootkey);
2557 return (lpvalue);
2560 xfree (lpvalue);
2562 RegCloseKey (hrootkey);
2565 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2567 lpvalue = NULL;
2569 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2570 && (lpvalue = xmalloc (cbData)) != NULL
2571 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2573 RegCloseKey (hrootkey);
2574 return (lpvalue);
2577 xfree (lpvalue);
2579 RegCloseKey (hrootkey);
2582 return (NULL);
2585 /* The argv[] array holds ANSI-encoded strings, and so this function
2586 works with ANS_encoded strings. */
2587 void
2588 init_environment (char ** argv)
2590 static const char * const tempdirs[] = {
2591 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2594 int i;
2596 const int imax = ARRAYELTS (tempdirs);
2598 /* Implementation note: This function explicitly works with ANSI
2599 file names, not with UTF-8 encoded file names. This is because
2600 this function pushes variables into the Emacs's environment, and
2601 the environment variables are always assumed to be in the
2602 locale-specific encoding. Do NOT call any functions that accept
2603 UTF-8 file names from this function! */
2605 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2606 temporary files and assume "/tmp" if $TMPDIR is unset, which
2607 will break on DOS/Windows. Refuse to work if we cannot find
2608 a directory, not even "c:/", usable for that purpose. */
2609 for (i = 0; i < imax ; i++)
2611 const char *tmp = tempdirs[i];
2613 if (*tmp == '$')
2614 tmp = getenv (tmp + 1);
2615 /* Note that `access' can lie to us if the directory resides on a
2616 read-only filesystem, like CD-ROM or a write-protected floppy.
2617 The only way to be really sure is to actually create a file and
2618 see if it succeeds. But I think that's too much to ask. */
2620 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2621 if (tmp && sys_access (tmp, D_OK) == 0)
2623 char * var = alloca (strlen (tmp) + 8);
2624 sprintf (var, "TMPDIR=%s", tmp);
2625 _putenv (strdup (var));
2626 break;
2629 if (i >= imax)
2630 cmd_error_internal
2631 (Fcons (Qerror,
2632 Fcons (build_string ("no usable temporary directories found!!"),
2633 Qnil)),
2634 "While setting TMPDIR: ");
2636 /* Check for environment variables and use registry settings if they
2637 don't exist. Fallback on default values where applicable. */
2639 int i;
2640 LPBYTE lpval;
2641 DWORD dwType;
2642 char locale_name[32];
2643 char default_home[MAX_PATH];
2644 int appdata = 0;
2646 static const struct env_entry
2648 const char * name;
2649 const char * def_value;
2650 } dflt_envvars[] =
2652 /* If the default value is NULL, we will use the value from the
2653 outside environment or the Registry, but will not push the
2654 variable into the Emacs environment if it is defined neither
2655 in the Registry nor in the outside environment. */
2656 {"HOME", "C:/"},
2657 {"PRELOAD_WINSOCK", NULL},
2658 {"emacs_dir", "C:/emacs"},
2659 {"EMACSLOADPATH", NULL},
2660 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2661 {"EMACSDATA", NULL},
2662 {"EMACSPATH", NULL},
2663 {"INFOPATH", NULL},
2664 {"EMACSDOC", NULL},
2665 {"TERM", "cmd"},
2666 {"LANG", NULL},
2669 #define N_ENV_VARS ARRAYELTS (dflt_envvars)
2671 /* We need to copy dflt_envvars[] and work on the copy because we
2672 don't want the dumped Emacs to inherit the values of
2673 environment variables we saw during dumping (which could be on
2674 a different system). The defaults above must be left intact. */
2675 struct env_entry env_vars[N_ENV_VARS];
2677 for (i = 0; i < N_ENV_VARS; i++)
2678 env_vars[i] = dflt_envvars[i];
2680 /* For backwards compatibility, check if a .emacs file exists in C:/
2681 If not, then we can try to default to the appdata directory under the
2682 user's profile, which is more likely to be writable. */
2683 if (sys_access ("C:/.emacs", F_OK) != 0)
2685 HRESULT profile_result;
2686 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2687 of Windows 95 and NT4 that have not been updated to include
2688 MSIE 5. */
2689 ShGetFolderPath_fn get_folder_path;
2690 get_folder_path = (ShGetFolderPath_fn)
2691 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2693 if (get_folder_path != NULL)
2695 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2696 0, default_home);
2698 /* If we can't get the appdata dir, revert to old behavior. */
2699 if (profile_result == S_OK)
2701 env_vars[0].def_value = default_home;
2702 appdata = 1;
2707 /* Get default locale info and use it for LANG. */
2708 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2709 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2710 locale_name, sizeof (locale_name)))
2712 for (i = 0; i < N_ENV_VARS; i++)
2714 if (strcmp (env_vars[i].name, "LANG") == 0)
2716 env_vars[i].def_value = locale_name;
2717 break;
2722 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2724 /* Treat emacs_dir specially: set it unconditionally based on our
2725 location. */
2727 char *p;
2728 char modname[MAX_PATH];
2730 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2731 emacs_abort ();
2732 if ((p = _mbsrchr (modname, '\\')) == NULL)
2733 emacs_abort ();
2734 *p = 0;
2736 if ((p = _mbsrchr (modname, '\\'))
2737 /* From bin means installed Emacs, from src means uninstalled. */
2738 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2740 char buf[SET_ENV_BUF_SIZE];
2741 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2743 *p = 0;
2744 for (p = modname; *p; p = CharNext (p))
2745 if (*p == '\\') *p = '/';
2747 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2748 _putenv (strdup (buf));
2749 /* If we are running from the Posix-like build tree, define
2750 SHELL to point to our own cmdproxy. The loop below will
2751 then disregard PATH_EXEC and the default value. */
2752 if (within_build_tree)
2754 _snprintf (buf, sizeof (buf) - 1,
2755 "SHELL=%s/nt/cmdproxy.exe", modname);
2756 _putenv (strdup (buf));
2761 for (i = 0; i < N_ENV_VARS; i++)
2763 if (!getenv (env_vars[i].name))
2765 int dont_free = 0;
2766 char bufc[SET_ENV_BUF_SIZE];
2768 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2769 /* Also ignore empty environment variables. */
2770 || *lpval == 0)
2772 xfree (lpval);
2773 dont_free = 1;
2774 if (strcmp (env_vars[i].name, "SHELL") == 0)
2776 /* Look for cmdproxy.exe in every directory in
2777 PATH_EXEC. FIXME: This does not find cmdproxy
2778 in nt/ when we run uninstalled. */
2779 char fname[MAX_PATH];
2780 const char *pstart = PATH_EXEC, *pend;
2782 do {
2783 pend = _mbschr (pstart, ';');
2784 if (!pend)
2785 pend = pstart + strlen (pstart);
2786 /* Be defensive against series of ;;; characters. */
2787 if (pend > pstart)
2789 strncpy (fname, pstart, pend - pstart);
2790 fname[pend - pstart] = '/';
2791 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2792 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2793 sizeof (bufc));
2794 if (sys_access (bufc, F_OK) == 0)
2796 lpval = bufc;
2797 dwType = REG_SZ;
2798 break;
2801 if (*pend)
2802 pstart = pend + 1;
2803 else
2804 pstart = pend;
2805 if (!*pstart)
2807 /* If not found in any directory, use the
2808 default as the last resort. */
2809 lpval = (char *)env_vars[i].def_value;
2810 dwType = REG_EXPAND_SZ;
2812 } while (*pstart);
2814 else
2816 lpval = (char *)env_vars[i].def_value;
2817 dwType = REG_EXPAND_SZ;
2819 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2820 Vdelayed_warnings_list
2821 = Fcons
2822 (listn (CONSTYPE_HEAP, 2,
2823 intern ("initialization"), build_string
2824 ("Use of `C:\\.emacs' without defining `HOME'\n"
2825 "in the environment is deprecated, "
2826 "see `Windows HOME' in the Emacs manual.")),
2827 Vdelayed_warnings_list);
2830 if (lpval)
2832 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2834 if (dwType == REG_EXPAND_SZ)
2835 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2836 else if (dwType == REG_SZ)
2837 strcpy (buf1, (char *)lpval);
2838 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2840 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2841 buf1);
2842 _putenv (strdup (buf2));
2845 if (!dont_free)
2846 xfree (lpval);
2852 /* Rebuild system configuration to reflect invoking system. */
2853 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2855 /* Another special case: on NT, the PATH variable is actually named
2856 "Path" although cmd.exe (perhaps NT itself) arranges for
2857 environment variable lookup and setting to be case insensitive.
2858 However, Emacs assumes a fully case sensitive environment, so we
2859 need to change "Path" to "PATH" to match the expectations of
2860 various elisp packages. We do this by the sneaky method of
2861 modifying the string in the C runtime environ entry.
2863 The same applies to COMSPEC. */
2865 char ** envp;
2867 for (envp = environ; *envp; envp++)
2868 if (_strnicmp (*envp, "PATH=", 5) == 0)
2869 memcpy (*envp, "PATH=", 5);
2870 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
2871 memcpy (*envp, "COMSPEC=", 8);
2874 /* Remember the initial working directory for getcwd. */
2875 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2876 Does it matter anywhere in Emacs? */
2877 if (w32_unicode_filenames)
2879 wchar_t wstartup_dir[MAX_PATH];
2881 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2882 emacs_abort ();
2883 filename_from_utf16 (wstartup_dir, startup_dir);
2885 else
2887 char astartup_dir[MAX_PATH];
2889 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2890 emacs_abort ();
2891 filename_from_ansi (astartup_dir, startup_dir);
2895 static char modname[MAX_PATH];
2897 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2898 emacs_abort ();
2899 argv[0] = modname;
2902 /* Determine if there is a middle mouse button, to allow parse_button
2903 to decide whether right mouse events should be mouse-2 or
2904 mouse-3. */
2905 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2907 init_user_info ();
2910 /* Called from expand-file-name when default-directory is not a string. */
2912 char *
2913 emacs_root_dir (void)
2915 static char root_dir[MAX_UTF8_PATH];
2916 const char *p;
2918 p = getenv ("emacs_dir");
2919 if (p == NULL)
2920 emacs_abort ();
2921 filename_from_ansi (p, root_dir);
2922 root_dir[parse_root (root_dir, NULL)] = '\0';
2923 dostounix_filename (root_dir);
2924 return root_dir;
2927 #include <sys/timeb.h>
2929 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2931 gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
2933 struct _timeb tb;
2934 _ftime (&tb);
2936 tv->tv_sec = tb.time;
2937 tv->tv_usec = tb.millitm * 1000L;
2938 /* Implementation note: _ftime sometimes doesn't update the dstflag
2939 according to the new timezone when the system timezone is
2940 changed. We could fix that by using GetSystemTime and
2941 GetTimeZoneInformation, but that doesn't seem necessary, since
2942 Emacs always calls gettimeofday with the 2nd argument NULL (see
2943 current_emacs_time). */
2944 if (tz)
2946 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2947 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2949 return 0;
2952 /* Emulate fdutimens. */
2954 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2955 TIMESPEC[0] and TIMESPEC[1], respectively.
2956 FD must be either negative -- in which case it is ignored --
2957 or a file descriptor that is open on FILE.
2958 If FD is nonnegative, then FILE can be NULL, which means
2959 use just futimes instead of utimes.
2960 If TIMESPEC is null, FAIL.
2961 Return 0 on success, -1 (setting errno) on failure. */
2964 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2966 if (!timespec)
2968 errno = ENOSYS;
2969 return -1;
2971 if (fd < 0 && !file)
2973 errno = EBADF;
2974 return -1;
2976 /* _futime's prototype defines 2nd arg as having the type 'struct
2977 _utimbuf', while utime needs to accept 'struct utimbuf' for
2978 compatibility with Posix. So we need to use 2 different (but
2979 equivalent) types to avoid compiler warnings, sigh. */
2980 if (fd >= 0)
2982 struct _utimbuf _ut;
2984 _ut.actime = timespec[0].tv_sec;
2985 _ut.modtime = timespec[1].tv_sec;
2986 return _futime (fd, &_ut);
2988 else
2990 struct utimbuf ut;
2992 ut.actime = timespec[0].tv_sec;
2993 ut.modtime = timespec[1].tv_sec;
2994 /* Call 'utime', which is implemented below, not the MS library
2995 function, which fails on directories. */
2996 return utime (file, &ut);
3001 /* ------------------------------------------------------------------------- */
3002 /* IO support and wrapper functions for the Windows API. */
3003 /* ------------------------------------------------------------------------- */
3005 /* Place a wrapper around the MSVC version of ctime. It returns NULL
3006 on network directories, so we handle that case here.
3007 (Ulrich Leodolter, 1/11/95). */
3008 char *
3009 sys_ctime (const time_t *t)
3011 char *str = (char *) ctime (t);
3012 return (str ? str : (char *)"Sun Jan 01 00:00:00 1970");
3015 /* Emulate sleep...we could have done this with a define, but that
3016 would necessitate including windows.h in the files that used it.
3017 This is much easier. */
3018 void
3019 sys_sleep (int seconds)
3021 Sleep (seconds * 1000);
3024 /* Internal MSVC functions for low-level descriptor munging */
3025 extern int __cdecl _set_osfhnd (int fd, long h);
3026 extern int __cdecl _free_osfhnd (int fd);
3028 /* parallel array of private info on file handles */
3029 filedesc fd_info [ MAXDESC ];
3031 typedef struct volume_info_data {
3032 struct volume_info_data * next;
3034 /* time when info was obtained */
3035 DWORD timestamp;
3037 /* actual volume info */
3038 char * root_dir;
3039 DWORD serialnum;
3040 DWORD maxcomp;
3041 DWORD flags;
3042 char * name;
3043 char * type;
3044 } volume_info_data;
3046 /* Global referenced by various functions. */
3047 static volume_info_data volume_info;
3049 /* Vector to indicate which drives are local and fixed (for which cached
3050 data never expires). */
3051 static BOOL fixed_drives[26];
3053 /* Consider cached volume information to be stale if older than 10s,
3054 at least for non-local drives. Info for fixed drives is never stale. */
3055 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
3056 #define VOLINFO_STILL_VALID( root_dir, info ) \
3057 ( ( isalpha (root_dir[0]) && \
3058 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
3059 || GetTickCount () - info->timestamp < 10000 )
3061 /* Cache support functions. */
3063 /* Simple linked list with linear search is sufficient. */
3064 static volume_info_data *volume_cache = NULL;
3066 static volume_info_data *
3067 lookup_volume_info (char * root_dir)
3069 volume_info_data * info;
3071 for (info = volume_cache; info; info = info->next)
3072 if (xstrcasecmp (info->root_dir, root_dir) == 0)
3073 break;
3074 return info;
3077 static void
3078 add_volume_info (char * root_dir, volume_info_data * info)
3080 info->root_dir = xstrdup (root_dir);
3081 unixtodos_filename (info->root_dir);
3082 info->next = volume_cache;
3083 volume_cache = info;
3087 /* Wrapper for GetVolumeInformation, which uses caching to avoid
3088 performance penalty (~2ms on 486 for local drives, 7.5ms for local
3089 cdrom drive, ~5-10ms or more for remote drives on LAN). */
3090 static volume_info_data *
3091 GetCachedVolumeInformation (char * root_dir)
3093 volume_info_data * info;
3094 char default_root[ MAX_UTF8_PATH ];
3095 char name[MAX_PATH+1];
3096 char type[MAX_PATH+1];
3098 /* NULL for root_dir means use root from current directory. */
3099 if (root_dir == NULL)
3101 if (w32_unicode_filenames)
3103 wchar_t curdirw[MAX_PATH];
3105 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
3106 return NULL;
3107 filename_from_utf16 (curdirw, default_root);
3109 else
3111 char curdira[MAX_PATH];
3113 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
3114 return NULL;
3115 filename_from_ansi (curdira, default_root);
3117 parse_root (default_root, (const char **)&root_dir);
3118 *root_dir = 0;
3119 root_dir = default_root;
3122 /* Local fixed drives can be cached permanently. Removable drives
3123 cannot be cached permanently, since the volume name and serial
3124 number (if nothing else) can change. Remote drives should be
3125 treated as if they are removable, since there is no sure way to
3126 tell whether they are or not. Also, the UNC association of drive
3127 letters mapped to remote volumes can be changed at any time (even
3128 by other processes) without notice.
3130 As a compromise, so we can benefit from caching info for remote
3131 volumes, we use a simple expiry mechanism to invalidate cache
3132 entries that are more than ten seconds old. */
3134 #if 0
3135 /* No point doing this, because WNetGetConnection is even slower than
3136 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
3137 GetDriveType is about the only call of this type which does not
3138 involve network access, and so is extremely quick). */
3140 /* Map drive letter to UNC if remote. */
3141 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
3143 char remote_name[ 256 ];
3144 char drive[3] = { root_dir[0], ':' };
3146 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
3147 == NO_ERROR)
3148 /* do something */ ;
3150 #endif
3152 info = lookup_volume_info (root_dir);
3154 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
3156 DWORD serialnum;
3157 DWORD maxcomp;
3158 DWORD flags;
3160 /* Info is not cached, or is stale. */
3161 if (w32_unicode_filenames)
3163 wchar_t root_w[MAX_PATH];
3164 wchar_t name_w[MAX_PATH+1];
3165 wchar_t type_w[MAX_PATH+1];
3167 filename_to_utf16 (root_dir, root_w);
3168 if (!GetVolumeInformationW (root_w,
3169 name_w, sizeof (name_w),
3170 &serialnum,
3171 &maxcomp,
3172 &flags,
3173 type_w, sizeof (type_w)))
3174 return NULL;
3175 /* Hmm... not really 100% correct, as these 2 are not file
3176 names... */
3177 filename_from_utf16 (name_w, name);
3178 filename_from_utf16 (type_w, type);
3180 else
3182 char root_a[MAX_PATH];
3183 char name_a[MAX_PATH+1];
3184 char type_a[MAX_PATH+1];
3186 filename_to_ansi (root_dir, root_a);
3187 if (!GetVolumeInformationA (root_a,
3188 name_a, sizeof (name_a),
3189 &serialnum,
3190 &maxcomp,
3191 &flags,
3192 type_a, sizeof (type_a)))
3193 return NULL;
3194 filename_from_ansi (name_a, name);
3195 filename_from_ansi (type_a, type);
3198 /* Cache the volume information for future use, overwriting existing
3199 entry if present. */
3200 if (info == NULL)
3202 info = xmalloc (sizeof (volume_info_data));
3203 add_volume_info (root_dir, info);
3205 else
3207 xfree (info->name);
3208 xfree (info->type);
3211 info->name = xstrdup (name);
3212 unixtodos_filename (info->name);
3213 info->serialnum = serialnum;
3214 info->maxcomp = maxcomp;
3215 info->flags = flags;
3216 info->type = xstrdup (type);
3217 info->timestamp = GetTickCount ();
3220 return info;
3223 /* Get information on the volume where NAME is held; set path pointer to
3224 start of pathname in NAME (past UNC header\volume header if present),
3225 if pPath is non-NULL.
3227 Note: if NAME includes symlinks, the information is for the volume
3228 of the symlink, not of its target. That's because, even though
3229 GetVolumeInformation returns information about the symlink target
3230 of its argument, we only pass the root directory to
3231 GetVolumeInformation, not the full NAME. */
3232 static int
3233 get_volume_info (const char * name, const char ** pPath)
3235 char temp[MAX_UTF8_PATH];
3236 char *rootname = NULL; /* default to current volume */
3237 volume_info_data * info;
3238 int root_len = parse_root (name, pPath);
3240 if (name == NULL)
3241 return FALSE;
3243 /* Copy the root name of the volume, if given. */
3244 if (root_len)
3246 strncpy (temp, name, root_len);
3247 temp[root_len] = '\0';
3248 unixtodos_filename (temp);
3249 rootname = temp;
3252 info = GetCachedVolumeInformation (rootname);
3253 if (info != NULL)
3255 /* Set global referenced by other functions. */
3256 volume_info = *info;
3257 return TRUE;
3259 return FALSE;
3262 /* Determine if volume is FAT format (ie. only supports short 8.3
3263 names); also set path pointer to start of pathname in name, if
3264 pPath is non-NULL. */
3265 static int
3266 is_fat_volume (const char * name, const char ** pPath)
3268 if (get_volume_info (name, pPath))
3269 return (volume_info.maxcomp == 12);
3270 return FALSE;
3273 /* Convert all slashes in a filename to backslashes, and map filename
3274 to a valid 8.3 name if necessary. The result is a pointer to a
3275 static buffer, so CAVEAT EMPTOR! */
3276 const char *map_w32_filename (const char *, const char **);
3278 const char *
3279 map_w32_filename (const char * name, const char ** pPath)
3281 static char shortname[MAX_UTF8_PATH];
3282 char * str = shortname;
3283 char c;
3284 char * path;
3285 const char * save_name = name;
3287 if (strlen (name) >= sizeof (shortname))
3289 /* Return a filename which will cause callers to fail. */
3290 strcpy (shortname, "?");
3291 return shortname;
3294 if (!fatal_error_in_progress /* disable fancy processing during crash */
3295 && is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3297 register int left = 8; /* maximum number of chars in part */
3298 register int extn = 0; /* extension added? */
3299 register int dots = 2; /* maximum number of dots allowed */
3301 while (name < path)
3302 *str++ = *name++; /* skip past UNC header */
3304 while ((c = *name++))
3306 switch ( c )
3308 case ':':
3309 case '\\':
3310 case '/':
3311 *str++ = (c == ':' ? ':' : '\\');
3312 extn = 0; /* reset extension flags */
3313 dots = 2; /* max 2 dots */
3314 left = 8; /* max length 8 for main part */
3315 break;
3316 case '.':
3317 if ( dots )
3319 /* Convert path components of the form .xxx to _xxx,
3320 but leave . and .. as they are. This allows .emacs
3321 to be read as _emacs, for example. */
3323 if (! *name ||
3324 *name == '.' ||
3325 IS_DIRECTORY_SEP (*name))
3327 *str++ = '.';
3328 dots--;
3330 else
3332 *str++ = '_';
3333 left--;
3334 dots = 0;
3337 else if ( !extn )
3339 *str++ = '.';
3340 extn = 1; /* we've got an extension */
3341 left = 3; /* 3 chars in extension */
3343 else
3345 /* any embedded dots after the first are converted to _ */
3346 *str++ = '_';
3348 break;
3349 case '~':
3350 case '#': /* don't lose these, they're important */
3351 if ( ! left )
3352 str[-1] = c; /* replace last character of part */
3353 /* FALLTHRU */
3354 default:
3355 if ( left && 'A' <= c && c <= 'Z' )
3357 *str++ = tolower (c); /* map to lower case (looks nicer) */
3358 left--;
3359 dots = 0; /* started a path component */
3361 break;
3364 *str = '\0';
3366 else
3368 strcpy (shortname, name);
3369 unixtodos_filename (shortname);
3372 if (pPath)
3373 *pPath = shortname + (path - save_name);
3375 return shortname;
3378 static int
3379 is_exec (const char * name)
3381 char * p = strrchr (name, '.');
3382 return
3383 (p != NULL
3384 && (xstrcasecmp (p, ".exe") == 0 ||
3385 xstrcasecmp (p, ".com") == 0 ||
3386 xstrcasecmp (p, ".bat") == 0 ||
3387 xstrcasecmp (p, ".cmd") == 0));
3390 /* Emulate the Unix directory procedures opendir, closedir, and
3391 readdir. We rename them to sys_* names because some versions of
3392 MinGW startup code call opendir and readdir to glob wildcards, and
3393 the code that calls them doesn't grok UTF-8 encoded file names we
3394 produce in dirent->d_name[]. */
3396 struct dirent dir_static; /* simulated directory contents */
3397 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3398 static int dir_is_fat;
3399 static char dir_pathname[MAX_UTF8_PATH];
3400 static WIN32_FIND_DATAW dir_find_data_w;
3401 static WIN32_FIND_DATAA dir_find_data_a;
3402 #define DIR_FIND_DATA_W 1
3403 #define DIR_FIND_DATA_A 2
3404 static int last_dir_find_data = -1;
3406 /* Support shares on a network resource as subdirectories of a read-only
3407 root directory. */
3408 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3409 static HANDLE open_unc_volume (const char *);
3410 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3411 static void close_unc_volume (HANDLE);
3413 DIR *
3414 sys_opendir (const char *filename)
3416 DIR *dirp;
3418 /* Opening is done by FindFirstFile. However, a read is inherent to
3419 this operation, so we defer the open until read time. */
3421 if (dir_find_handle != INVALID_HANDLE_VALUE)
3422 return NULL;
3423 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3424 return NULL;
3426 /* Note: We don't support traversal of UNC volumes via symlinks.
3427 Doing so would mean punishing 99.99% of use cases by resolving
3428 all the possible symlinks in FILENAME, recursively. */
3429 if (is_unc_volume (filename))
3431 wnet_enum_handle = open_unc_volume (filename);
3432 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3433 return NULL;
3436 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3437 return NULL;
3439 dirp->dd_fd = 0;
3440 dirp->dd_loc = 0;
3441 dirp->dd_size = 0;
3443 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3444 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3445 /* Note: We don't support symlinks to file names on FAT volumes.
3446 Doing so would mean punishing 99.99% of use cases by resolving
3447 all the possible symlinks in FILENAME, recursively. */
3448 dir_is_fat = is_fat_volume (filename, NULL);
3450 return dirp;
3453 void
3454 sys_closedir (DIR *dirp)
3456 /* If we have a find-handle open, close it. */
3457 if (dir_find_handle != INVALID_HANDLE_VALUE)
3459 FindClose (dir_find_handle);
3460 dir_find_handle = INVALID_HANDLE_VALUE;
3462 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3464 close_unc_volume (wnet_enum_handle);
3465 wnet_enum_handle = INVALID_HANDLE_VALUE;
3467 xfree ((char *) dirp);
3470 struct dirent *
3471 sys_readdir (DIR *dirp)
3473 int downcase = !NILP (Vw32_downcase_file_names);
3475 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3477 if (!read_unc_volume (wnet_enum_handle,
3478 dir_find_data_w.cFileName,
3479 dir_find_data_a.cFileName,
3480 MAX_PATH))
3481 return NULL;
3483 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3484 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3486 char filename[MAX_UTF8_PATH];
3487 int ln;
3488 bool last_slash = true;
3490 /* Note: We don't need to worry about dir_pathname being longer
3491 than MAX_UTF8_PATH, as sys_opendir already took care of that
3492 when it called map_w32_filename: that function will put a "?"
3493 in its return value in that case, thus failing all the calls
3494 below. */
3495 strcpy (filename, dir_pathname);
3496 ln = strlen (filename);
3497 if (!IS_DIRECTORY_SEP (filename[ln - 1]))
3498 last_slash = false;
3500 /* Note: No need to resolve symlinks in FILENAME, because
3501 FindFirst opens the directory that is the target of a
3502 symlink. */
3503 if (w32_unicode_filenames)
3505 wchar_t fnw[MAX_PATH + 2];
3507 filename_to_utf16 (filename, fnw);
3508 if (!last_slash)
3509 wcscat (fnw, L"\\");
3510 wcscat (fnw, L"*");
3511 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3513 else
3515 char fna[MAX_PATH + 2];
3517 filename_to_ansi (filename, fna);
3518 if (!last_slash)
3519 strcat (fna, "\\");
3520 strcat (fna, "*");
3521 /* If FILENAME is not representable by the current ANSI
3522 codepage, we don't want FindFirstFileA to interpret the
3523 '?' characters as a wildcard. */
3524 if (_mbspbrk (fna, "?"))
3525 dir_find_handle = INVALID_HANDLE_VALUE;
3526 else
3527 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3530 if (dir_find_handle == INVALID_HANDLE_VALUE)
3532 /* Any changes in the value of errno here should be in sync
3533 with what directory_files_internal does when it calls
3534 readdir. */
3535 switch (GetLastError ())
3537 /* Windows uses this value when FindFirstFile finds no
3538 files that match the wildcard. This is not supposed
3539 to happen, since our wildcard is "*", but just in
3540 case, if there's some weird empty directory with not
3541 even "." and ".." entries... */
3542 case ERROR_FILE_NOT_FOUND:
3543 errno = 0;
3544 /* FALLTHRU */
3545 default:
3546 break;
3547 case ERROR_ACCESS_DENIED:
3548 case ERROR_NETWORK_ACCESS_DENIED:
3549 errno = EACCES;
3550 break;
3551 case ERROR_PATH_NOT_FOUND:
3552 case ERROR_INVALID_DRIVE:
3553 case ERROR_NOT_READY:
3554 case ERROR_BAD_NETPATH:
3555 case ERROR_BAD_NET_NAME:
3556 errno = ENOENT;
3557 break;
3559 return NULL;
3562 else if (w32_unicode_filenames)
3564 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3566 errno = 0;
3567 return NULL;
3570 else
3572 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3574 errno = 0;
3575 return NULL;
3579 /* Emacs never uses this value, so don't bother making it match
3580 value returned by stat(). */
3581 dir_static.d_ino = 1;
3583 if (w32_unicode_filenames)
3585 if (downcase || dir_is_fat)
3587 wchar_t tem[MAX_PATH];
3589 wcscpy (tem, dir_find_data_w.cFileName);
3590 CharLowerW (tem);
3591 filename_from_utf16 (tem, dir_static.d_name);
3593 else
3594 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3595 last_dir_find_data = DIR_FIND_DATA_W;
3597 else
3599 char tem[MAX_PATH];
3601 /* If the file name in cFileName[] includes `?' characters, it
3602 means the original file name used characters that cannot be
3603 represented by the current ANSI codepage. To avoid total
3604 lossage, retrieve the short 8+3 alias of the long file
3605 name. */
3606 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3608 strcpy (tem, dir_find_data_a.cAlternateFileName);
3609 /* 8+3 aliases are returned in all caps, which could break
3610 various alists that look at filenames' extensions. */
3611 downcase = 1;
3613 else if (downcase || dir_is_fat)
3614 strcpy (tem, dir_find_data_a.cFileName);
3615 else
3616 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3617 if (downcase || dir_is_fat)
3619 _mbslwr (tem);
3620 filename_from_ansi (tem, dir_static.d_name);
3622 last_dir_find_data = DIR_FIND_DATA_A;
3625 dir_static.d_namlen = strlen (dir_static.d_name);
3626 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3627 dir_static.d_namlen - dir_static.d_namlen % 4;
3629 return &dir_static;
3632 static HANDLE
3633 open_unc_volume (const char *path)
3635 const char *fn = map_w32_filename (path, NULL);
3636 DWORD result;
3637 HANDLE henum;
3639 if (w32_unicode_filenames)
3641 NETRESOURCEW nrw;
3642 wchar_t fnw[MAX_PATH];
3644 nrw.dwScope = RESOURCE_GLOBALNET;
3645 nrw.dwType = RESOURCETYPE_DISK;
3646 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3647 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3648 nrw.lpLocalName = NULL;
3649 filename_to_utf16 (fn, fnw);
3650 nrw.lpRemoteName = fnw;
3651 nrw.lpComment = NULL;
3652 nrw.lpProvider = NULL;
3654 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3655 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3657 else
3659 NETRESOURCEA nra;
3660 char fna[MAX_PATH];
3662 nra.dwScope = RESOURCE_GLOBALNET;
3663 nra.dwType = RESOURCETYPE_DISK;
3664 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3665 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3666 nra.lpLocalName = NULL;
3667 filename_to_ansi (fn, fna);
3668 nra.lpRemoteName = fna;
3669 nra.lpComment = NULL;
3670 nra.lpProvider = NULL;
3672 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3673 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3675 if (result == NO_ERROR)
3676 return henum;
3677 else
3679 /* Make sure directory_files_internal reports a sensible error. */
3680 errno = ENOENT;
3681 return INVALID_HANDLE_VALUE;
3685 static void *
3686 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3688 DWORD count;
3689 int result;
3690 char *buffer;
3691 DWORD bufsize = 512;
3692 void *retval;
3694 count = 1;
3695 if (w32_unicode_filenames)
3697 wchar_t *ptrw;
3699 bufsize *= 2;
3700 buffer = alloca (bufsize);
3701 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3702 if (result != NO_ERROR)
3703 return NULL;
3704 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3705 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3706 ptrw += 2;
3707 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3708 ptrw++;
3709 wcsncpy (fname_w, ptrw, size);
3710 retval = fname_w;
3712 else
3714 int dbcs_p = max_filename_mbslen () > 1;
3715 char *ptra;
3717 buffer = alloca (bufsize);
3718 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3719 if (result != NO_ERROR)
3720 return NULL;
3721 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3722 ptra += 2;
3723 if (!dbcs_p)
3724 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3725 else
3727 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3728 ptra = CharNextExA (file_name_codepage, ptra, 0);
3730 ptra++;
3731 strncpy (fname_a, ptra, size);
3732 retval = fname_a;
3735 return retval;
3738 static void
3739 close_unc_volume (HANDLE henum)
3741 if (henum != INVALID_HANDLE_VALUE)
3742 WNetCloseEnum (henum);
3745 static DWORD
3746 unc_volume_file_attributes (const char *path)
3748 HANDLE henum;
3749 DWORD attrs;
3751 henum = open_unc_volume (path);
3752 if (henum == INVALID_HANDLE_VALUE)
3753 return -1;
3755 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3757 close_unc_volume (henum);
3759 return attrs;
3762 /* Ensure a network connection is authenticated. */
3763 static void
3764 logon_network_drive (const char *path)
3766 char share[MAX_UTF8_PATH];
3767 int n_slashes;
3768 char drive[4];
3769 UINT drvtype;
3770 char *p;
3771 DWORD val;
3773 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3774 drvtype = DRIVE_REMOTE;
3775 else if (path[0] == '\0' || path[1] != ':')
3776 drvtype = GetDriveType (NULL);
3777 else
3779 drive[0] = path[0];
3780 drive[1] = ':';
3781 drive[2] = '\\';
3782 drive[3] = '\0';
3783 drvtype = GetDriveType (drive);
3786 /* Only logon to networked drives. */
3787 if (drvtype != DRIVE_REMOTE)
3788 return;
3790 n_slashes = 2;
3791 strncpy (share, path, MAX_UTF8_PATH);
3792 /* Truncate to just server and share name. */
3793 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3795 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3797 *p = '\0';
3798 break;
3802 if (w32_unicode_filenames)
3804 NETRESOURCEW resourcew;
3805 wchar_t share_w[MAX_PATH];
3807 resourcew.dwScope = RESOURCE_GLOBALNET;
3808 resourcew.dwType = RESOURCETYPE_DISK;
3809 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3810 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3811 resourcew.lpLocalName = NULL;
3812 filename_to_utf16 (share, share_w);
3813 resourcew.lpRemoteName = share_w;
3814 resourcew.lpProvider = NULL;
3816 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3818 else
3820 NETRESOURCEA resourcea;
3821 char share_a[MAX_PATH];
3823 resourcea.dwScope = RESOURCE_GLOBALNET;
3824 resourcea.dwType = RESOURCETYPE_DISK;
3825 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3826 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3827 resourcea.lpLocalName = NULL;
3828 filename_to_ansi (share, share_a);
3829 resourcea.lpRemoteName = share_a;
3830 resourcea.lpProvider = NULL;
3832 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3835 switch (val)
3837 case NO_ERROR:
3838 case ERROR_ALREADY_ASSIGNED:
3839 break;
3840 case ERROR_ACCESS_DENIED:
3841 case ERROR_LOGON_FAILURE:
3842 errno = EACCES;
3843 break;
3844 case ERROR_BUSY:
3845 errno = EAGAIN;
3846 break;
3847 case ERROR_BAD_NET_NAME:
3848 case ERROR_NO_NET_OR_BAD_PATH:
3849 case ERROR_NO_NETWORK:
3850 case ERROR_CANCELLED:
3851 default:
3852 errno = ENOENT;
3853 break;
3857 /* Emulate faccessat(2). */
3859 faccessat (int dirfd, const char * path, int mode, int flags)
3861 DWORD attributes;
3863 if (dirfd != AT_FDCWD
3864 && !(IS_DIRECTORY_SEP (path[0])
3865 || IS_DEVICE_SEP (path[1])))
3867 errno = EBADF;
3868 return -1;
3871 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3872 newer versions blow up when passed D_OK. */
3873 path = map_w32_filename (path, NULL);
3874 /* If the last element of PATH is a symlink, we need to resolve it
3875 to get the attributes of its target file. Note: any symlinks in
3876 PATH elements other than the last one are transparently resolved
3877 by GetFileAttributes below. */
3878 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3879 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3880 path = chase_symlinks (path);
3882 if (w32_unicode_filenames)
3884 wchar_t path_w[MAX_PATH];
3886 filename_to_utf16 (path, path_w);
3887 attributes = GetFileAttributesW (path_w);
3889 else
3891 char path_a[MAX_PATH];
3893 filename_to_ansi (path, path_a);
3894 attributes = GetFileAttributesA (path_a);
3897 if (attributes == -1)
3899 DWORD w32err = GetLastError ();
3901 switch (w32err)
3903 case ERROR_INVALID_NAME:
3904 case ERROR_BAD_PATHNAME:
3905 if (is_unc_volume (path))
3907 attributes = unc_volume_file_attributes (path);
3908 if (attributes == -1)
3910 errno = EACCES;
3911 return -1;
3913 goto check_attrs;
3915 /* FALLTHROUGH */
3916 case ERROR_FILE_NOT_FOUND:
3917 case ERROR_BAD_NETPATH:
3918 errno = ENOENT;
3919 break;
3920 default:
3921 errno = EACCES;
3922 break;
3924 return -1;
3927 check_attrs:
3928 if ((mode & X_OK) != 0
3929 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3931 errno = EACCES;
3932 return -1;
3934 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3936 errno = EACCES;
3937 return -1;
3939 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3941 errno = EACCES;
3942 return -1;
3944 return 0;
3947 /* A special test for DIRNAME being a directory accessible by the
3948 current user. This is needed because the security permissions in
3949 directory's ACLs are not visible in the Posix-style mode bits
3950 returned by 'stat' and in attributes returned by GetFileAttributes.
3951 So a directory would seem like it's readable by the current user,
3952 but will in fact error out with EACCES when they actually try. */
3954 w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
3956 char pattern[MAX_UTF8_PATH];
3957 bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
3958 HANDLE dh;
3960 /* Network volumes need a different reading method. */
3961 if (is_unc_volume (dirname))
3963 void *read_result = NULL;
3964 wchar_t fnw[MAX_PATH];
3965 char fna[MAX_PATH];
3967 dh = open_unc_volume (dirname);
3968 if (dh != INVALID_HANDLE_VALUE)
3970 read_result = read_unc_volume (dh, fnw, fna, MAX_PATH);
3971 close_unc_volume (dh);
3973 /* Treat empty volumes as accessible. */
3974 return read_result != NULL || GetLastError () == ERROR_NO_MORE_ITEMS;
3977 /* Note: map_w32_filename makes sure DIRNAME is not longer than
3978 MAX_UTF8_PATH. */
3979 strcpy (pattern, map_w32_filename (dirname, NULL));
3981 /* Note: No need to resolve symlinks in FILENAME, because FindFirst
3982 opens the directory that is the target of a symlink. */
3983 if (w32_unicode_filenames)
3985 wchar_t pat_w[MAX_PATH + 2];
3986 WIN32_FIND_DATAW dfd_w;
3988 filename_to_utf16 (pattern, pat_w);
3989 if (!last_slash)
3990 wcscat (pat_w, L"\\");
3991 wcscat (pat_w, L"*");
3992 dh = FindFirstFileW (pat_w, &dfd_w);
3994 else
3996 char pat_a[MAX_PATH + 2];
3997 WIN32_FIND_DATAA dfd_a;
3999 filename_to_ansi (pattern, pat_a);
4000 if (!last_slash)
4001 strcpy (pat_a, "\\");
4002 strcat (pat_a, "*");
4003 /* In case DIRNAME cannot be expressed in characters from the
4004 current ANSI codepage. */
4005 if (_mbspbrk (pat_a, "?"))
4006 dh = INVALID_HANDLE_VALUE;
4007 else
4008 dh = FindFirstFileA (pat_a, &dfd_a);
4011 if (dh == INVALID_HANDLE_VALUE)
4012 return 0;
4013 FindClose (dh);
4014 return 1;
4017 /* A version of 'access' to be used locally with file names in
4018 locale-specific encoding. Does not resolve symlinks and does not
4019 support file names on FAT12 and FAT16 volumes, but that's OK, since
4020 we only invoke this function for files inside the Emacs source or
4021 installation tree, on directories (so any symlinks should have the
4022 directory bit set), and on short file names such as "C:/.emacs". */
4023 static int
4024 sys_access (const char *fname, int mode)
4026 char fname_copy[MAX_PATH], *p;
4027 DWORD attributes;
4029 strcpy (fname_copy, fname);
4030 /* Do the equivalent of unixtodos_filename. */
4031 for (p = fname_copy; *p; p = CharNext (p))
4032 if (*p == '/')
4033 *p = '\\';
4035 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
4037 DWORD w32err = GetLastError ();
4039 switch (w32err)
4041 case ERROR_INVALID_NAME:
4042 case ERROR_BAD_PATHNAME:
4043 case ERROR_FILE_NOT_FOUND:
4044 case ERROR_BAD_NETPATH:
4045 errno = ENOENT;
4046 break;
4047 default:
4048 errno = EACCES;
4049 break;
4051 return -1;
4053 if ((mode & X_OK) != 0
4054 && !(is_exec (fname_copy)
4055 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
4057 errno = EACCES;
4058 return -1;
4060 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
4062 errno = EACCES;
4063 return -1;
4065 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
4067 errno = EACCES;
4068 return -1;
4070 return 0;
4073 /* Shadow some MSVC runtime functions to map requests for long filenames
4074 to reasonable short names if necessary. This was originally added to
4075 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
4076 long file names. */
4079 sys_chdir (const char * path)
4081 path = map_w32_filename (path, NULL);
4082 if (w32_unicode_filenames)
4084 wchar_t newdir_w[MAX_PATH];
4086 if (filename_to_utf16 (path, newdir_w) == 0)
4087 return _wchdir (newdir_w);
4088 return -1;
4090 else
4092 char newdir_a[MAX_PATH];
4094 if (filename_to_ansi (path, newdir_a) == 0)
4095 return _chdir (newdir_a);
4096 return -1;
4101 sys_chmod (const char * path, int mode)
4103 path = chase_symlinks (map_w32_filename (path, NULL));
4104 if (w32_unicode_filenames)
4106 wchar_t path_w[MAX_PATH];
4108 filename_to_utf16 (path, path_w);
4109 return _wchmod (path_w, mode);
4111 else
4113 char path_a[MAX_PATH];
4115 filename_to_ansi (path, path_a);
4116 return _chmod (path_a, mode);
4121 sys_creat (const char * path, int mode)
4123 path = map_w32_filename (path, NULL);
4124 if (w32_unicode_filenames)
4126 wchar_t path_w[MAX_PATH];
4128 filename_to_utf16 (path, path_w);
4129 return _wcreat (path_w, mode);
4131 else
4133 char path_a[MAX_PATH];
4135 filename_to_ansi (path, path_a);
4136 return _creat (path_a, mode);
4140 FILE *
4141 sys_fopen (const char * path, const char * mode)
4143 int fd;
4144 int oflag;
4145 const char * mode_save = mode;
4147 /* Force all file handles to be non-inheritable. This is necessary to
4148 ensure child processes don't unwittingly inherit handles that might
4149 prevent future file access. */
4151 if (mode[0] == 'r')
4152 oflag = O_RDONLY;
4153 else if (mode[0] == 'w' || mode[0] == 'a')
4154 oflag = O_WRONLY | O_CREAT | O_TRUNC;
4155 else
4156 return NULL;
4158 /* Only do simplistic option parsing. */
4159 while (*++mode)
4160 if (mode[0] == '+')
4162 oflag &= ~(O_RDONLY | O_WRONLY);
4163 oflag |= O_RDWR;
4165 else if (mode[0] == 'b')
4167 oflag &= ~O_TEXT;
4168 oflag |= O_BINARY;
4170 else if (mode[0] == 't')
4172 oflag &= ~O_BINARY;
4173 oflag |= O_TEXT;
4175 else break;
4177 path = map_w32_filename (path, NULL);
4178 if (w32_unicode_filenames)
4180 wchar_t path_w[MAX_PATH];
4182 filename_to_utf16 (path, path_w);
4183 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
4185 else
4187 char path_a[MAX_PATH];
4189 filename_to_ansi (path, path_a);
4190 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
4192 if (fd < 0)
4193 return NULL;
4195 return _fdopen (fd, mode_save);
4198 /* This only works on NTFS volumes, but is useful to have. */
4200 sys_link (const char * old, const char * new)
4202 HANDLE fileh;
4203 int result = -1;
4204 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
4205 wchar_t oldname_w[MAX_PATH];
4206 char oldname_a[MAX_PATH];
4208 if (old == NULL || new == NULL)
4210 errno = ENOENT;
4211 return -1;
4214 strcpy (oldname, map_w32_filename (old, NULL));
4215 strcpy (newname, map_w32_filename (new, NULL));
4217 if (w32_unicode_filenames)
4219 filename_to_utf16 (oldname, oldname_w);
4220 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
4221 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4223 else
4225 filename_to_ansi (oldname, oldname_a);
4226 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
4227 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4229 if (fileh != INVALID_HANDLE_VALUE)
4231 int wlen;
4233 /* Confusingly, the "alternate" stream name field does not apply
4234 when restoring a hard link, and instead contains the actual
4235 stream data for the link (ie. the name of the link to create).
4236 The WIN32_STREAM_ID structure before the cStreamName field is
4237 the stream header, which is then immediately followed by the
4238 stream data. */
4240 struct {
4241 WIN32_STREAM_ID wid;
4242 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
4243 } data;
4245 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
4246 indicates that flag is unsupported for CP_UTF8, and OTOH says
4247 it is the default anyway. */
4248 wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
4249 data.wid.cStreamName, MAX_PATH);
4250 if (wlen > 0)
4252 LPVOID context = NULL;
4253 DWORD wbytes = 0;
4255 data.wid.dwStreamId = BACKUP_LINK;
4256 data.wid.dwStreamAttributes = 0;
4257 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
4258 data.wid.Size.HighPart = 0;
4259 data.wid.dwStreamNameSize = 0;
4261 if (BackupWrite (fileh, (LPBYTE)&data,
4262 offsetof (WIN32_STREAM_ID, cStreamName)
4263 + data.wid.Size.LowPart,
4264 &wbytes, FALSE, FALSE, &context)
4265 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
4267 /* succeeded */
4268 result = 0;
4270 else
4272 DWORD err = GetLastError ();
4273 DWORD attributes;
4275 switch (err)
4277 case ERROR_ACCESS_DENIED:
4278 /* This is what happens when OLDNAME is a directory,
4279 since Windows doesn't support hard links to
4280 directories. Posix says to set errno to EPERM in
4281 that case. */
4282 if (w32_unicode_filenames)
4283 attributes = GetFileAttributesW (oldname_w);
4284 else
4285 attributes = GetFileAttributesA (oldname_a);
4286 if (attributes != -1
4287 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
4288 errno = EPERM;
4289 else if (attributes == -1
4290 && is_unc_volume (oldname)
4291 && unc_volume_file_attributes (oldname) != -1)
4292 errno = EPERM;
4293 else
4294 errno = EACCES;
4295 break;
4296 case ERROR_TOO_MANY_LINKS:
4297 errno = EMLINK;
4298 break;
4299 case ERROR_NOT_SAME_DEVICE:
4300 errno = EXDEV;
4301 break;
4302 default:
4303 errno = EINVAL;
4304 break;
4309 CloseHandle (fileh);
4311 else
4312 errno = ENOENT;
4314 return result;
4318 sys_mkdir (const char * path)
4320 path = map_w32_filename (path, NULL);
4322 if (w32_unicode_filenames)
4324 wchar_t path_w[MAX_PATH];
4326 filename_to_utf16 (path, path_w);
4327 return _wmkdir (path_w);
4329 else
4331 char path_a[MAX_PATH];
4333 filename_to_ansi (path, path_a);
4334 return _mkdir (path_a);
4339 sys_open (const char * path, int oflag, int mode)
4341 const char* mpath = map_w32_filename (path, NULL);
4342 int res = -1;
4344 if (w32_unicode_filenames)
4346 wchar_t mpath_w[MAX_PATH];
4348 filename_to_utf16 (mpath, mpath_w);
4349 /* If possible, try to open file without _O_CREAT, to be able to
4350 write to existing hidden and system files. Force all file
4351 handles to be non-inheritable. */
4352 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4353 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4354 if (res < 0)
4355 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4357 else
4359 char mpath_a[MAX_PATH];
4361 filename_to_ansi (mpath, mpath_a);
4362 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4363 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4364 if (res < 0)
4365 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4368 return res;
4371 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
4372 when using mktemp.
4374 Standard algorithm for generating a temporary file name seems to be
4375 use pid or tid with a letter on the front (in place of the 6 X's)
4376 and cycle through the letters to find a unique name. We extend
4377 that to allow any reasonable character as the first of the 6 X's,
4378 so that the number of simultaneously used temporary files will be
4379 greater. */
4382 mkostemp (char * template, int flags)
4384 char * p;
4385 int i, fd = -1;
4386 unsigned uid = GetCurrentThreadId ();
4387 int save_errno = errno;
4388 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
4390 errno = EINVAL;
4391 if (template == NULL)
4392 return -1;
4394 p = template + strlen (template);
4395 i = 5;
4396 /* replace up to the last 5 X's with uid in decimal */
4397 while (--p >= template && p[0] == 'X' && --i >= 0)
4399 p[0] = '0' + uid % 10;
4400 uid /= 10;
4403 if (i < 0 && p[0] == 'X')
4405 i = 0;
4408 p[0] = first_char[i];
4409 if ((fd = sys_open (template,
4410 flags | _O_CREAT | _O_EXCL | _O_RDWR,
4411 S_IRUSR | S_IWUSR)) >= 0
4412 || errno != EEXIST)
4414 if (fd >= 0)
4415 errno = save_errno;
4416 return fd;
4419 while (++i < sizeof (first_char));
4422 /* Template is badly formed or else we can't generate a unique name. */
4423 return -1;
4427 fchmod (int fd, mode_t mode)
4429 return 0;
4433 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4435 BOOL result;
4436 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4437 int newname_dev;
4438 int oldname_dev;
4439 bool have_temp_a = false;
4441 /* MoveFile on Windows 95 doesn't correctly change the short file name
4442 alias in a number of circumstances (it is not easy to predict when
4443 just by looking at oldname and newname, unfortunately). In these
4444 cases, renaming through a temporary name avoids the problem.
4446 A second problem on Windows 95 is that renaming through a temp name when
4447 newname is uppercase fails (the final long name ends up in
4448 lowercase, although the short alias might be uppercase) UNLESS the
4449 long temp name is not 8.3.
4451 So, on Windows 95 we always rename through a temp name, and we make sure
4452 the temp name has a long extension to ensure correct renaming. */
4454 strcpy (temp, map_w32_filename (oldname, NULL));
4456 /* volume_info is set indirectly by map_w32_filename. */
4457 oldname_dev = volume_info.serialnum;
4459 if (os_subtype == OS_9X)
4461 char * o;
4462 char * p;
4463 int i = 0;
4464 char oldname_a[MAX_PATH];
4466 oldname = map_w32_filename (oldname, NULL);
4467 filename_to_ansi (oldname, oldname_a);
4468 filename_to_ansi (temp, temp_a);
4469 if ((o = strrchr (oldname_a, '\\')))
4470 o++;
4471 else
4472 o = (char *) oldname_a;
4474 if ((p = strrchr (temp_a, '\\')))
4475 p++;
4476 else
4477 p = temp_a;
4481 /* Force temp name to require a manufactured 8.3 alias - this
4482 seems to make the second rename work properly. */
4483 sprintf (p, "_.%s.%d", o, i);
4484 i++;
4485 result = rename (oldname_a, temp_a);
4487 /* This loop must surely terminate! */
4488 while (result < 0 && errno == EEXIST);
4489 if (result < 0)
4490 return -1;
4491 have_temp_a = true;
4494 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4495 (at least if it is a file; don't do this for directories).
4497 Since we mustn't do this if we are just changing the case of the
4498 file name (we would end up deleting the file we are trying to
4499 rename!), we let rename detect if the destination file already
4500 exists - that way we avoid the possible pitfalls of trying to
4501 determine ourselves whether two names really refer to the same
4502 file, which is not always possible in the general case. (Consider
4503 all the permutations of shared or subst'd drives, etc.) */
4505 newname = map_w32_filename (newname, NULL);
4507 /* volume_info is set indirectly by map_w32_filename. */
4508 newname_dev = volume_info.serialnum;
4510 if (w32_unicode_filenames)
4512 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4514 filename_to_utf16 (temp, temp_w);
4515 filename_to_utf16 (newname, newname_w);
4516 result = _wrename (temp_w, newname_w);
4517 if (result < 0 && force)
4519 DWORD w32err = GetLastError ();
4521 if (errno == EACCES
4522 && newname_dev != oldname_dev)
4524 /* The implementation of `rename' on Windows does not return
4525 errno = EXDEV when you are moving a directory to a
4526 different storage device (ex. logical disk). It returns
4527 EACCES instead. So here we handle such situations and
4528 return EXDEV. */
4529 DWORD attributes;
4531 if ((attributes = GetFileAttributesW (temp_w)) != -1
4532 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4533 errno = EXDEV;
4535 else if (errno == EEXIST)
4537 if (_wchmod (newname_w, 0666) != 0)
4538 return result;
4539 if (_wunlink (newname_w) != 0)
4540 return result;
4541 result = _wrename (temp_w, newname_w);
4543 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4544 && is_symlink (temp))
4546 /* This is Windows prohibiting the user from creating a
4547 symlink in another place, since that requires
4548 privileges. */
4549 errno = EPERM;
4553 else
4555 char newname_a[MAX_PATH];
4557 if (!have_temp_a)
4558 filename_to_ansi (temp, temp_a);
4559 filename_to_ansi (newname, newname_a);
4560 result = rename (temp_a, newname_a);
4561 if (result < 0 && force)
4563 DWORD w32err = GetLastError ();
4565 if (errno == EACCES
4566 && newname_dev != oldname_dev)
4568 DWORD attributes;
4570 if ((attributes = GetFileAttributesA (temp_a)) != -1
4571 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4572 errno = EXDEV;
4574 else if (errno == EEXIST)
4576 if (_chmod (newname_a, 0666) != 0)
4577 return result;
4578 if (_unlink (newname_a) != 0)
4579 return result;
4580 result = rename (temp_a, newname_a);
4582 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4583 && is_symlink (temp))
4584 errno = EPERM;
4588 return result;
4592 sys_rename (char const *old, char const *new)
4594 return sys_rename_replace (old, new, TRUE);
4598 sys_rmdir (const char * path)
4600 path = map_w32_filename (path, NULL);
4602 if (w32_unicode_filenames)
4604 wchar_t path_w[MAX_PATH];
4606 filename_to_utf16 (path, path_w);
4607 return _wrmdir (path_w);
4609 else
4611 char path_a[MAX_PATH];
4613 filename_to_ansi (path, path_a);
4614 return _rmdir (path_a);
4619 sys_unlink (const char * path)
4621 int rmstatus, e;
4623 path = map_w32_filename (path, NULL);
4625 if (w32_unicode_filenames)
4627 wchar_t path_w[MAX_PATH];
4629 filename_to_utf16 (path, path_w);
4630 /* On Unix, unlink works without write permission. */
4631 _wchmod (path_w, 0666);
4632 rmstatus = _wunlink (path_w);
4633 e = errno;
4634 /* Symlinks to directories can only be deleted by _rmdir;
4635 _unlink returns EACCES. */
4636 if (rmstatus != 0
4637 && errno == EACCES
4638 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4639 rmstatus = _wrmdir (path_w);
4640 else
4641 errno = e;
4643 else
4645 char path_a[MAX_PATH];
4647 filename_to_ansi (path, path_a);
4648 _chmod (path_a, 0666);
4649 rmstatus = _unlink (path_a);
4650 e = errno;
4651 if (rmstatus != 0
4652 && errno == EACCES
4653 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4654 rmstatus = _rmdir (path_a);
4655 else
4656 errno = e;
4659 return rmstatus;
4662 static FILETIME utc_base_ft;
4663 static ULONGLONG utc_base; /* In 100ns units */
4664 static int init = 0;
4666 #define FILETIME_TO_U64(result, ft) \
4667 do { \
4668 ULARGE_INTEGER uiTemp; \
4669 uiTemp.LowPart = (ft).dwLowDateTime; \
4670 uiTemp.HighPart = (ft).dwHighDateTime; \
4671 result = uiTemp.QuadPart; \
4672 } while (0)
4674 static void
4675 initialize_utc_base (void)
4677 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4678 SYSTEMTIME st;
4680 st.wYear = 1970;
4681 st.wMonth = 1;
4682 st.wDay = 1;
4683 st.wHour = 0;
4684 st.wMinute = 0;
4685 st.wSecond = 0;
4686 st.wMilliseconds = 0;
4688 SystemTimeToFileTime (&st, &utc_base_ft);
4689 FILETIME_TO_U64 (utc_base, utc_base_ft);
4692 static time_t
4693 convert_time (FILETIME ft)
4695 ULONGLONG tmp;
4697 if (!init)
4699 initialize_utc_base ();
4700 init = 1;
4703 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4704 return 0;
4706 FILETIME_TO_U64 (tmp, ft);
4707 return (time_t) ((tmp - utc_base) / 10000000L);
4710 static void
4711 convert_from_time_t (time_t time, FILETIME * pft)
4713 ULARGE_INTEGER tmp;
4715 if (!init)
4717 initialize_utc_base ();
4718 init = 1;
4721 /* time in 100ns units since 1-Jan-1601 */
4722 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4723 pft->dwHighDateTime = tmp.HighPart;
4724 pft->dwLowDateTime = tmp.LowPart;
4727 static PSECURITY_DESCRIPTOR
4728 get_file_security_desc_by_handle (HANDLE h)
4730 PSECURITY_DESCRIPTOR psd = NULL;
4731 DWORD err;
4732 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4733 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4735 err = get_security_info (h, SE_FILE_OBJECT, si,
4736 NULL, NULL, NULL, NULL, &psd);
4737 if (err != ERROR_SUCCESS)
4738 return NULL;
4740 return psd;
4743 static PSECURITY_DESCRIPTOR
4744 get_file_security_desc_by_name (const char *fname)
4746 PSECURITY_DESCRIPTOR psd = NULL;
4747 DWORD sd_len, err;
4748 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4749 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4751 if (!get_file_security (fname, si, psd, 0, &sd_len))
4753 err = GetLastError ();
4754 if (err != ERROR_INSUFFICIENT_BUFFER)
4755 return NULL;
4758 psd = xmalloc (sd_len);
4759 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4761 xfree (psd);
4762 return NULL;
4765 return psd;
4768 static DWORD
4769 get_rid (PSID sid)
4771 unsigned n_subauthorities;
4773 /* Use the last sub-authority value of the RID, the relative
4774 portion of the SID, as user/group ID. */
4775 n_subauthorities = *get_sid_sub_authority_count (sid);
4776 if (n_subauthorities < 1)
4777 return 0; /* the "World" RID */
4778 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4781 /* Caching SID and account values for faster lokup. */
4783 struct w32_id {
4784 unsigned rid;
4785 struct w32_id *next;
4786 char name[GNLEN+1];
4787 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4790 static struct w32_id *w32_idlist;
4792 static int
4793 w32_cached_id (PSID sid, unsigned *id, char *name)
4795 struct w32_id *tail, *found;
4797 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4799 if (equal_sid ((PSID)tail->sid, sid))
4801 found = tail;
4802 break;
4805 if (found)
4807 *id = found->rid;
4808 strcpy (name, found->name);
4809 return 1;
4811 else
4812 return 0;
4815 static void
4816 w32_add_to_cache (PSID sid, unsigned id, char *name)
4818 DWORD sid_len;
4819 struct w32_id *new_entry;
4821 /* We don't want to leave behind stale cache from when Emacs was
4822 dumped. */
4823 if (initialized)
4825 sid_len = get_length_sid (sid);
4826 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4827 if (new_entry)
4829 new_entry->rid = id;
4830 strcpy (new_entry->name, name);
4831 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4832 new_entry->next = w32_idlist;
4833 w32_idlist = new_entry;
4838 #define UID 1
4839 #define GID 2
4841 static int
4842 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4844 PSID sid = NULL;
4845 BOOL dflt;
4846 SID_NAME_USE ignore;
4847 char name[UNLEN+1];
4848 DWORD name_len = sizeof (name);
4849 char domain[1024];
4850 DWORD domain_len = sizeof (domain);
4851 int use_dflt = 0;
4852 int result;
4854 if (what == UID)
4855 result = get_security_descriptor_owner (psd, &sid, &dflt);
4856 else if (what == GID)
4857 result = get_security_descriptor_group (psd, &sid, &dflt);
4858 else
4859 result = 0;
4861 if (!result || !is_valid_sid (sid))
4862 use_dflt = 1;
4863 else if (!w32_cached_id (sid, id, nm))
4865 if (!lookup_account_sid (NULL, sid, name, &name_len,
4866 domain, &domain_len, &ignore)
4867 || name_len > UNLEN+1)
4868 use_dflt = 1;
4869 else
4871 *id = get_rid (sid);
4872 strcpy (nm, name);
4873 w32_add_to_cache (sid, *id, name);
4876 return use_dflt;
4879 static void
4880 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4882 int dflt_usr = 0, dflt_grp = 0;
4884 if (!psd)
4886 dflt_usr = 1;
4887 dflt_grp = 1;
4889 else
4891 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4892 dflt_usr = 1;
4893 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4894 dflt_grp = 1;
4896 /* Consider files to belong to current user/group, if we cannot get
4897 more accurate information. */
4898 if (dflt_usr)
4900 st->st_uid = dflt_passwd.pw_uid;
4901 strcpy (st->st_uname, dflt_passwd.pw_name);
4903 if (dflt_grp)
4905 st->st_gid = dflt_passwd.pw_gid;
4906 strcpy (st->st_gname, dflt_group.gr_name);
4910 /* Return non-zero if NAME is a potentially slow filesystem. */
4911 int is_slow_fs (const char *);
4914 is_slow_fs (const char *name)
4916 char drive_root[4];
4917 UINT devtype;
4919 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4920 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4921 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4922 devtype = GetDriveType (NULL); /* use root of current drive */
4923 else
4925 /* GetDriveType needs the root directory of the drive. */
4926 strncpy (drive_root, name, 2);
4927 drive_root[2] = '\\';
4928 drive_root[3] = '\0';
4929 devtype = GetDriveType (drive_root);
4931 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4934 /* If this is non-zero, the caller wants accurate information about
4935 file's owner and group, which could be expensive to get. dired.c
4936 uses this flag when needed for the job at hand. */
4937 int w32_stat_get_owner_group;
4939 /* MSVC stat function can't cope with UNC names and has other bugs, so
4940 replace it with our own. This also allows us to calculate consistent
4941 inode values and owner/group without hacks in the main Emacs code,
4942 and support file names encoded in UTF-8. */
4944 static int
4945 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4947 char *name, *save_name, *r;
4948 WIN32_FIND_DATAW wfd_w;
4949 WIN32_FIND_DATAA wfd_a;
4950 HANDLE fh;
4951 unsigned __int64 fake_inode = 0;
4952 int permission;
4953 int len;
4954 int rootdir = FALSE;
4955 PSECURITY_DESCRIPTOR psd = NULL;
4956 int is_a_symlink = 0;
4957 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4958 DWORD access_rights = 0;
4959 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4960 FILETIME ctime, atime, wtime;
4961 wchar_t name_w[MAX_PATH];
4962 char name_a[MAX_PATH];
4964 if (path == NULL || buf == NULL)
4966 errno = EFAULT;
4967 return -1;
4970 save_name = name = (char *) map_w32_filename (path, &path);
4971 /* Must be valid filename, no wild cards or other invalid
4972 characters. */
4973 if (strpbrk (name, "*?|<>\""))
4975 errno = ENOENT;
4976 return -1;
4979 len = strlen (name);
4980 /* Allocate 1 extra byte so that we could append a slash to a root
4981 directory, down below. */
4982 name = strcpy (alloca (len + 2), name);
4984 /* Avoid a somewhat costly call to is_symlink if the filesystem
4985 doesn't support symlinks. */
4986 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4987 is_a_symlink = is_symlink (name);
4989 /* Plan A: Open the file and get all the necessary information via
4990 the resulting handle. This solves several issues in one blow:
4992 . retrieves attributes for the target of a symlink, if needed
4993 . gets attributes of root directories and symlinks pointing to
4994 root directories, thus avoiding the need for special-casing
4995 these and detecting them by examining the file-name format
4996 . retrieves more accurate attributes (e.g., non-zero size for
4997 some directories, esp. directories that are junction points)
4998 . correctly resolves "c:/..", "/.." and similar file names
4999 . avoids run-time penalties for 99% of use cases
5001 Plan A is always tried first, unless the user asked not to (but
5002 if the file is a symlink and we need to follow links, we try Plan
5003 A even if the user asked not to).
5005 If Plan A fails, we go to Plan B (below), where various
5006 potentially expensive techniques must be used to handle "special"
5007 files such as UNC volumes etc. */
5008 if (!(NILP (Vw32_get_true_file_attributes)
5009 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
5010 /* Following symlinks requires getting the info by handle. */
5011 || (is_a_symlink && follow_symlinks))
5013 BY_HANDLE_FILE_INFORMATION info;
5015 if (is_a_symlink && !follow_symlinks)
5016 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
5017 /* READ_CONTROL access rights are required to get security info
5018 by handle. But if the OS doesn't support security in the
5019 first place, we don't need to try. */
5020 if (is_windows_9x () != TRUE)
5021 access_rights |= READ_CONTROL;
5023 if (w32_unicode_filenames)
5025 filename_to_utf16 (name, name_w);
5026 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
5027 file_flags, NULL);
5028 /* If CreateFile fails with READ_CONTROL, try again with
5029 zero as access rights. */
5030 if (fh == INVALID_HANDLE_VALUE && access_rights)
5031 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
5032 file_flags, NULL);
5034 else
5036 filename_to_ansi (name, name_a);
5037 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
5038 file_flags, NULL);
5039 if (fh == INVALID_HANDLE_VALUE && access_rights)
5040 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
5041 file_flags, NULL);
5043 if (fh == INVALID_HANDLE_VALUE)
5044 goto no_true_file_attributes;
5046 /* This is more accurate in terms of getting the correct number
5047 of links, but is quite slow (it is noticeable when Emacs is
5048 making a list of file name completions). */
5049 if (GetFileInformationByHandle (fh, &info))
5051 nlinks = info.nNumberOfLinks;
5052 /* Might as well use file index to fake inode values, but this
5053 is not guaranteed to be unique unless we keep a handle open
5054 all the time (even then there are situations where it is
5055 not unique). Reputedly, there are at most 48 bits of info
5056 (on NTFS, presumably less on FAT). */
5057 fake_inode = info.nFileIndexHigh;
5058 fake_inode <<= 32;
5059 fake_inode += info.nFileIndexLow;
5060 serialnum = info.dwVolumeSerialNumber;
5061 fs_high = info.nFileSizeHigh;
5062 fs_low = info.nFileSizeLow;
5063 ctime = info.ftCreationTime;
5064 atime = info.ftLastAccessTime;
5065 wtime = info.ftLastWriteTime;
5066 fattrs = info.dwFileAttributes;
5068 else
5070 /* We don't go to Plan B here, because it's not clear that
5071 it's a good idea. The only known use case where
5072 CreateFile succeeds, but GetFileInformationByHandle fails
5073 (with ERROR_INVALID_FUNCTION) is for character devices
5074 such as NUL, PRN, etc. For these, switching to Plan B is
5075 a net loss, because we lose the character device
5076 attribute returned by GetFileType below (FindFirstFile
5077 doesn't set that bit in the attributes), and the other
5078 fields don't make sense for character devices anyway.
5079 Emacs doesn't really care for non-file entities in the
5080 context of l?stat, so neither do we. */
5082 /* w32err is assigned so one could put a breakpoint here and
5083 examine its value, when GetFileInformationByHandle
5084 fails. */
5085 DWORD w32err = GetLastError ();
5087 switch (w32err)
5089 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
5090 errno = ENOENT;
5091 return -1;
5095 /* Test for a symlink before testing for a directory, since
5096 symlinks to directories have the directory bit set, but we
5097 don't want them to appear as directories. */
5098 if (is_a_symlink && !follow_symlinks)
5099 buf->st_mode = S_IFLNK;
5100 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5101 buf->st_mode = S_IFDIR;
5102 else
5104 DWORD ftype = GetFileType (fh);
5106 switch (ftype)
5108 case FILE_TYPE_DISK:
5109 buf->st_mode = S_IFREG;
5110 break;
5111 case FILE_TYPE_PIPE:
5112 buf->st_mode = S_IFIFO;
5113 break;
5114 case FILE_TYPE_CHAR:
5115 case FILE_TYPE_UNKNOWN:
5116 default:
5117 buf->st_mode = S_IFCHR;
5120 /* We produce the fallback owner and group data, based on the
5121 current user that runs Emacs, in the following cases:
5123 . caller didn't request owner and group info
5124 . this is Windows 9X
5125 . getting security by handle failed, and we need to produce
5126 information for the target of a symlink (this is better
5127 than producing a potentially misleading info about the
5128 symlink itself)
5130 If getting security by handle fails, and we don't need to
5131 resolve symlinks, we try getting security by name. */
5132 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5133 get_file_owner_and_group (NULL, buf);
5134 else
5136 psd = get_file_security_desc_by_handle (fh);
5137 if (psd)
5139 get_file_owner_and_group (psd, buf);
5140 LocalFree (psd);
5142 else if (!(is_a_symlink && follow_symlinks))
5144 psd = get_file_security_desc_by_name (name);
5145 get_file_owner_and_group (psd, buf);
5146 xfree (psd);
5148 else
5149 get_file_owner_and_group (NULL, buf);
5151 CloseHandle (fh);
5153 else
5155 no_true_file_attributes:
5156 /* Plan B: Either getting a handle on the file failed, or the
5157 caller explicitly asked us to not bother making this
5158 information more accurate.
5160 Implementation note: In Plan B, we never bother to resolve
5161 symlinks, even if we got here because we tried Plan A and
5162 failed. That's because, even if the caller asked for extra
5163 precision by setting Vw32_get_true_file_attributes to t,
5164 resolving symlinks requires acquiring a file handle to the
5165 symlink, which we already know will fail. And if the user
5166 did not ask for extra precision, resolving symlinks will fly
5167 in the face of that request, since the user then wants the
5168 lightweight version of the code. */
5169 rootdir = (path >= save_name + len - 1
5170 && (IS_DIRECTORY_SEP (*path) || *path == 0));
5172 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
5173 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
5174 if (IS_DIRECTORY_SEP (r[0])
5175 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
5176 r[1] = r[2] = '\0';
5178 /* Note: If NAME is a symlink to the root of a UNC volume
5179 (i.e. "\\SERVER"), we will not detect that here, and we will
5180 return data about the symlink as result of FindFirst below.
5181 This is unfortunate, but that marginal use case does not
5182 justify a call to chase_symlinks which would impose a penalty
5183 on all the other use cases. (We get here for symlinks to
5184 roots of UNC volumes because CreateFile above fails for them,
5185 unlike with symlinks to root directories X:\ of drives.) */
5186 if (is_unc_volume (name))
5188 fattrs = unc_volume_file_attributes (name);
5189 if (fattrs == -1)
5190 return -1;
5192 ctime = atime = wtime = utc_base_ft;
5194 else if (rootdir)
5196 /* Make sure root directories end in a slash. */
5197 if (!IS_DIRECTORY_SEP (name[len-1]))
5198 strcpy (name + len, "\\");
5199 if (GetDriveType (name) < 2)
5201 errno = ENOENT;
5202 return -1;
5205 fattrs = FILE_ATTRIBUTE_DIRECTORY;
5206 ctime = atime = wtime = utc_base_ft;
5208 else
5210 int have_wfd = -1;
5212 /* Make sure non-root directories do NOT end in a slash,
5213 otherwise FindFirstFile might fail. */
5214 if (IS_DIRECTORY_SEP (name[len-1]))
5215 name[len - 1] = 0;
5217 /* (This is hacky, but helps when doing file completions on
5218 network drives.) Optimize by using information available from
5219 active readdir if possible. */
5220 len = strlen (dir_pathname);
5221 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
5222 len--;
5223 if (dir_find_handle != INVALID_HANDLE_VALUE
5224 && last_dir_find_data != -1
5225 && !(is_a_symlink && follow_symlinks)
5226 /* The 2 file-name comparisons below support only ASCII
5227 characters, and will lose (compare not equal) when
5228 the file names include non-ASCII characters that are
5229 the same but for the case. However, doing this
5230 properly involves: (a) converting both file names to
5231 UTF-16, (b) lower-casing both names using CharLowerW,
5232 and (c) comparing the results; this would be quite a
5233 bit slower, whereas Plan B is for users who want
5234 lightweight albeit inaccurate version of 'stat'. */
5235 && c_strncasecmp (save_name, dir_pathname, len) == 0
5236 && IS_DIRECTORY_SEP (name[len])
5237 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
5239 have_wfd = last_dir_find_data;
5240 /* This was the last entry returned by readdir. */
5241 if (last_dir_find_data == DIR_FIND_DATA_W)
5242 wfd_w = dir_find_data_w;
5243 else
5244 wfd_a = dir_find_data_a;
5246 else
5248 logon_network_drive (name);
5250 if (w32_unicode_filenames)
5252 filename_to_utf16 (name, name_w);
5253 fh = FindFirstFileW (name_w, &wfd_w);
5254 have_wfd = DIR_FIND_DATA_W;
5256 else
5258 filename_to_ansi (name, name_a);
5259 /* If NAME includes characters not representable by
5260 the current ANSI codepage, filename_to_ansi
5261 usually replaces them with a '?'. We don't want
5262 to let FindFirstFileA interpret those as wildcards,
5263 and "succeed", returning us data from some random
5264 file in the same directory. */
5265 if (_mbspbrk (name_a, "?"))
5266 fh = INVALID_HANDLE_VALUE;
5267 else
5268 fh = FindFirstFileA (name_a, &wfd_a);
5269 have_wfd = DIR_FIND_DATA_A;
5271 if (fh == INVALID_HANDLE_VALUE)
5273 errno = ENOENT;
5274 return -1;
5276 FindClose (fh);
5278 /* Note: if NAME is a symlink, the information we get from
5279 FindFirstFile is for the symlink, not its target. */
5280 if (have_wfd == DIR_FIND_DATA_W)
5282 fattrs = wfd_w.dwFileAttributes;
5283 ctime = wfd_w.ftCreationTime;
5284 atime = wfd_w.ftLastAccessTime;
5285 wtime = wfd_w.ftLastWriteTime;
5286 fs_high = wfd_w.nFileSizeHigh;
5287 fs_low = wfd_w.nFileSizeLow;
5289 else
5291 fattrs = wfd_a.dwFileAttributes;
5292 ctime = wfd_a.ftCreationTime;
5293 atime = wfd_a.ftLastAccessTime;
5294 wtime = wfd_a.ftLastWriteTime;
5295 fs_high = wfd_a.nFileSizeHigh;
5296 fs_low = wfd_a.nFileSizeLow;
5298 fake_inode = 0;
5299 nlinks = 1;
5300 serialnum = volume_info.serialnum;
5302 if (is_a_symlink && !follow_symlinks)
5303 buf->st_mode = S_IFLNK;
5304 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5305 buf->st_mode = S_IFDIR;
5306 else
5307 buf->st_mode = S_IFREG;
5309 get_file_owner_and_group (NULL, buf);
5312 buf->st_ino = fake_inode;
5314 buf->st_dev = serialnum;
5315 buf->st_rdev = serialnum;
5317 buf->st_size = fs_high;
5318 buf->st_size <<= 32;
5319 buf->st_size += fs_low;
5320 buf->st_nlink = nlinks;
5322 /* Convert timestamps to Unix format. */
5323 buf->st_mtime = convert_time (wtime);
5324 buf->st_atime = convert_time (atime);
5325 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5326 buf->st_ctime = convert_time (ctime);
5327 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5329 /* determine rwx permissions */
5330 if (is_a_symlink && !follow_symlinks)
5331 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5332 else
5334 if (fattrs & FILE_ATTRIBUTE_READONLY)
5335 permission = S_IREAD;
5336 else
5337 permission = S_IREAD | S_IWRITE;
5339 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5340 permission |= S_IEXEC;
5341 else if (is_exec (name))
5342 permission |= S_IEXEC;
5345 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5347 return 0;
5351 stat (const char * path, struct stat * buf)
5353 return stat_worker (path, buf, 1);
5357 lstat (const char * path, struct stat * buf)
5359 return stat_worker (path, buf, 0);
5363 fstatat (int fd, char const *name, struct stat *st, int flags)
5365 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5366 This is good enough for the current usage in Emacs, but is fragile.
5368 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5369 Gnulib does this and can serve as a model. */
5370 char fullname[MAX_UTF8_PATH];
5372 if (fd != AT_FDCWD)
5374 char lastc = dir_pathname[strlen (dir_pathname) - 1];
5376 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
5377 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
5378 < 0)
5380 errno = ENAMETOOLONG;
5381 return -1;
5383 name = fullname;
5386 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5389 /* Provide fstat and utime as well as stat for consistent handling of
5390 file timestamps. */
5392 fstat (int desc, struct stat * buf)
5394 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5395 BY_HANDLE_FILE_INFORMATION info;
5396 unsigned __int64 fake_inode;
5397 int permission;
5399 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5401 case FILE_TYPE_DISK:
5402 buf->st_mode = S_IFREG;
5403 if (!GetFileInformationByHandle (fh, &info))
5405 errno = EACCES;
5406 return -1;
5408 break;
5409 case FILE_TYPE_PIPE:
5410 buf->st_mode = S_IFIFO;
5411 goto non_disk;
5412 case FILE_TYPE_CHAR:
5413 case FILE_TYPE_UNKNOWN:
5414 default:
5415 buf->st_mode = S_IFCHR;
5416 non_disk:
5417 memset (&info, 0, sizeof (info));
5418 info.dwFileAttributes = 0;
5419 info.ftCreationTime = utc_base_ft;
5420 info.ftLastAccessTime = utc_base_ft;
5421 info.ftLastWriteTime = utc_base_ft;
5424 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5425 buf->st_mode = S_IFDIR;
5427 buf->st_nlink = info.nNumberOfLinks;
5428 /* Might as well use file index to fake inode values, but this
5429 is not guaranteed to be unique unless we keep a handle open
5430 all the time (even then there are situations where it is
5431 not unique). Reputedly, there are at most 48 bits of info
5432 (on NTFS, presumably less on FAT). */
5433 fake_inode = info.nFileIndexHigh;
5434 fake_inode <<= 32;
5435 fake_inode += info.nFileIndexLow;
5437 /* MSVC defines _ino_t to be short; other libc's might not. */
5438 if (sizeof (buf->st_ino) == 2)
5439 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5440 else
5441 buf->st_ino = fake_inode;
5443 /* If the caller so requested, get the true file owner and group.
5444 Otherwise, consider the file to belong to the current user. */
5445 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5446 get_file_owner_and_group (NULL, buf);
5447 else
5449 PSECURITY_DESCRIPTOR psd = NULL;
5451 psd = get_file_security_desc_by_handle (fh);
5452 if (psd)
5454 get_file_owner_and_group (psd, buf);
5455 LocalFree (psd);
5457 else
5458 get_file_owner_and_group (NULL, buf);
5461 buf->st_dev = info.dwVolumeSerialNumber;
5462 buf->st_rdev = info.dwVolumeSerialNumber;
5464 buf->st_size = info.nFileSizeHigh;
5465 buf->st_size <<= 32;
5466 buf->st_size += info.nFileSizeLow;
5468 /* Convert timestamps to Unix format. */
5469 buf->st_mtime = convert_time (info.ftLastWriteTime);
5470 buf->st_atime = convert_time (info.ftLastAccessTime);
5471 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5472 buf->st_ctime = convert_time (info.ftCreationTime);
5473 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5475 /* determine rwx permissions */
5476 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5477 permission = S_IREAD;
5478 else
5479 permission = S_IREAD | S_IWRITE;
5481 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5482 permission |= S_IEXEC;
5483 else
5485 #if 0 /* no way of knowing the filename */
5486 char * p = strrchr (name, '.');
5487 if (p != NULL &&
5488 (xstrcasecmp (p, ".exe") == 0 ||
5489 xstrcasecmp (p, ".com") == 0 ||
5490 xstrcasecmp (p, ".bat") == 0 ||
5491 xstrcasecmp (p, ".cmd") == 0))
5492 permission |= S_IEXEC;
5493 #endif
5496 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5498 return 0;
5501 /* A version of 'utime' which handles directories as well as
5502 files. */
5505 utime (const char *name, struct utimbuf *times)
5507 struct utimbuf deftime;
5508 HANDLE fh;
5509 FILETIME mtime;
5510 FILETIME atime;
5512 if (times == NULL)
5514 deftime.modtime = deftime.actime = time (NULL);
5515 times = &deftime;
5518 if (w32_unicode_filenames)
5520 wchar_t name_utf16[MAX_PATH];
5522 if (filename_to_utf16 (name, name_utf16) != 0)
5523 return -1; /* errno set by filename_to_utf16 */
5525 /* Need write access to set times. */
5526 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5527 /* If NAME specifies a directory, FILE_SHARE_DELETE
5528 allows other processes to delete files inside it,
5529 while we have the directory open. */
5530 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5531 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5533 else
5535 char name_ansi[MAX_PATH];
5537 if (filename_to_ansi (name, name_ansi) != 0)
5538 return -1; /* errno set by filename_to_ansi */
5540 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5541 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5542 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5544 if (fh != INVALID_HANDLE_VALUE)
5546 convert_from_time_t (times->actime, &atime);
5547 convert_from_time_t (times->modtime, &mtime);
5548 if (!SetFileTime (fh, NULL, &atime, &mtime))
5550 CloseHandle (fh);
5551 errno = EACCES;
5552 return -1;
5554 CloseHandle (fh);
5556 else
5558 DWORD err = GetLastError ();
5560 switch (err)
5562 case ERROR_FILE_NOT_FOUND:
5563 case ERROR_PATH_NOT_FOUND:
5564 case ERROR_INVALID_DRIVE:
5565 case ERROR_BAD_NETPATH:
5566 case ERROR_DEV_NOT_EXIST:
5567 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5568 file name includes ?s, i.e. translation to ANSI failed. */
5569 case ERROR_INVALID_NAME:
5570 errno = ENOENT;
5571 break;
5572 case ERROR_TOO_MANY_OPEN_FILES:
5573 errno = ENFILE;
5574 break;
5575 case ERROR_ACCESS_DENIED:
5576 case ERROR_SHARING_VIOLATION:
5577 errno = EACCES;
5578 break;
5579 default:
5580 errno = EINVAL;
5581 break;
5583 return -1;
5585 return 0;
5589 sys_umask (int mode)
5591 static int current_mask;
5592 int retval, arg = 0;
5594 /* The only bit we really support is the write bit. Files are
5595 always readable on MS-Windows, and the execute bit does not exist
5596 at all. */
5597 /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
5598 to prevent access by other users on NTFS. */
5599 if ((mode & S_IWRITE) != 0)
5600 arg |= S_IWRITE;
5602 retval = _umask (arg);
5603 /* Merge into the return value the bits they've set the last time,
5604 which msvcrt.dll ignores and never returns. Emacs insists on its
5605 notion of mask being identical to what we return. */
5606 retval |= (current_mask & ~S_IWRITE);
5607 current_mask = mode;
5609 return retval;
5613 /* Symlink-related functions. */
5614 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5615 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5616 #endif
5619 symlink (char const *filename, char const *linkname)
5621 char linkfn[MAX_UTF8_PATH], *tgtfn;
5622 DWORD flags = 0;
5623 int dir_access, filename_ends_in_slash;
5625 /* Diagnostics follows Posix as much as possible. */
5626 if (filename == NULL || linkname == NULL)
5628 errno = EFAULT;
5629 return -1;
5631 if (!*filename)
5633 errno = ENOENT;
5634 return -1;
5636 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5638 errno = ENAMETOOLONG;
5639 return -1;
5642 strcpy (linkfn, map_w32_filename (linkname, NULL));
5643 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5645 errno = EPERM;
5646 return -1;
5649 /* Note: since empty FILENAME was already rejected, we can safely
5650 refer to FILENAME[1]. */
5651 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5653 /* Non-absolute FILENAME is understood as being relative to
5654 LINKNAME's directory. We need to prepend that directory to
5655 FILENAME to get correct results from faccessat below, since
5656 otherwise it will interpret FILENAME relative to the
5657 directory where the Emacs process runs. Note that
5658 make-symbolic-link always makes sure LINKNAME is a fully
5659 expanded file name. */
5660 char tem[MAX_UTF8_PATH];
5661 char *p = linkfn + strlen (linkfn);
5663 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5664 p--;
5665 if (p > linkfn)
5666 strncpy (tem, linkfn, p - linkfn);
5667 strcpy (tem + (p - linkfn), filename);
5668 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5670 else
5671 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5673 /* Since Windows distinguishes between symlinks to directories and
5674 to files, we provide a kludgy feature: if FILENAME doesn't
5675 exist, but ends in a slash, we create a symlink to directory. If
5676 FILENAME exists and is a directory, we always create a symlink to
5677 directory. */
5678 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5679 if (dir_access == 0 || filename_ends_in_slash)
5680 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5682 tgtfn = (char *)map_w32_filename (filename, NULL);
5683 if (filename_ends_in_slash)
5684 tgtfn[strlen (tgtfn) - 1] = '\0';
5686 errno = 0;
5687 if (!create_symbolic_link (linkfn, tgtfn, flags))
5689 /* ENOSYS is set by create_symbolic_link, when it detects that
5690 the OS doesn't support the CreateSymbolicLink API. */
5691 if (errno != ENOSYS)
5693 DWORD w32err = GetLastError ();
5695 switch (w32err)
5697 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5698 TGTFN point to the same file name, go figure. */
5699 case ERROR_SUCCESS:
5700 case ERROR_FILE_EXISTS:
5701 errno = EEXIST;
5702 break;
5703 case ERROR_ACCESS_DENIED:
5704 errno = EACCES;
5705 break;
5706 case ERROR_FILE_NOT_FOUND:
5707 case ERROR_PATH_NOT_FOUND:
5708 case ERROR_BAD_NETPATH:
5709 case ERROR_INVALID_REPARSE_DATA:
5710 errno = ENOENT;
5711 break;
5712 case ERROR_DIRECTORY:
5713 errno = EISDIR;
5714 break;
5715 case ERROR_PRIVILEGE_NOT_HELD:
5716 case ERROR_NOT_ALL_ASSIGNED:
5717 errno = EPERM;
5718 break;
5719 case ERROR_DISK_FULL:
5720 errno = ENOSPC;
5721 break;
5722 default:
5723 errno = EINVAL;
5724 break;
5727 return -1;
5729 return 0;
5732 /* A quick inexpensive test of whether FILENAME identifies a file that
5733 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5734 must already be in the normalized form returned by
5735 map_w32_filename. If the symlink is to a directory, the
5736 FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
5738 Note: for repeated operations on many files, it is best to test
5739 whether the underlying volume actually supports symlinks, by
5740 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5741 avoid the call to this function if it doesn't. That's because the
5742 call to GetFileAttributes takes a non-negligible time, especially
5743 on non-local or removable filesystems. See stat_worker for an
5744 example of how to do that. */
5745 static int
5746 is_symlink (const char *filename)
5748 DWORD attrs;
5749 wchar_t filename_w[MAX_PATH];
5750 char filename_a[MAX_PATH];
5751 WIN32_FIND_DATAW wfdw;
5752 WIN32_FIND_DATAA wfda;
5753 HANDLE fh;
5754 int attrs_mean_symlink;
5756 if (w32_unicode_filenames)
5758 filename_to_utf16 (filename, filename_w);
5759 attrs = GetFileAttributesW (filename_w);
5761 else
5763 filename_to_ansi (filename, filename_a);
5764 attrs = GetFileAttributesA (filename_a);
5766 if (attrs == -1)
5768 DWORD w32err = GetLastError ();
5770 switch (w32err)
5772 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5773 break;
5774 case ERROR_ACCESS_DENIED:
5775 errno = EACCES;
5776 break;
5777 case ERROR_FILE_NOT_FOUND:
5778 case ERROR_PATH_NOT_FOUND:
5779 default:
5780 errno = ENOENT;
5781 break;
5783 return 0;
5785 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5786 return 0;
5787 logon_network_drive (filename);
5788 if (w32_unicode_filenames)
5790 fh = FindFirstFileW (filename_w, &wfdw);
5791 attrs_mean_symlink =
5792 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5793 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5794 if (attrs_mean_symlink)
5795 attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5797 else if (_mbspbrk (filename_a, "?"))
5799 /* filename_to_ansi failed to convert the file name. */
5800 errno = ENOENT;
5801 return 0;
5803 else
5805 fh = FindFirstFileA (filename_a, &wfda);
5806 attrs_mean_symlink =
5807 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5808 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5809 if (attrs_mean_symlink)
5810 attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5812 if (fh == INVALID_HANDLE_VALUE)
5813 return 0;
5814 FindClose (fh);
5815 return attrs_mean_symlink;
5818 /* If NAME identifies a symbolic link, copy into BUF the file name of
5819 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5820 null-terminate the target name, even if it fits. Return the number
5821 of bytes copied, or -1 if NAME is not a symlink or any error was
5822 encountered while resolving it. The file name copied into BUF is
5823 encoded in the current ANSI codepage. */
5824 ssize_t
5825 readlink (const char *name, char *buf, size_t buf_size)
5827 const char *path;
5828 TOKEN_PRIVILEGES privs;
5829 int restore_privs = 0;
5830 HANDLE sh;
5831 ssize_t retval;
5832 char resolved[MAX_UTF8_PATH];
5834 if (name == NULL)
5836 errno = EFAULT;
5837 return -1;
5839 if (!*name)
5841 errno = ENOENT;
5842 return -1;
5845 path = map_w32_filename (name, NULL);
5847 if (strlen (path) > MAX_UTF8_PATH)
5849 errno = ENAMETOOLONG;
5850 return -1;
5853 errno = 0;
5854 if (is_windows_9x () == TRUE
5855 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5856 || !is_symlink (path))
5858 if (!errno)
5859 errno = EINVAL; /* not a symlink */
5860 return -1;
5863 /* Done with simple tests, now we're in for some _real_ work. */
5864 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5865 restore_privs = 1;
5866 /* Implementation note: From here and onward, don't return early,
5867 since that will fail to restore the original set of privileges of
5868 the calling thread. */
5870 retval = -1; /* not too optimistic, are we? */
5872 /* Note: In the next call to CreateFile, we use zero as the 2nd
5873 argument because, when the symlink is a hidden/system file,
5874 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5875 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5876 and directory symlinks. */
5877 if (w32_unicode_filenames)
5879 wchar_t path_w[MAX_PATH];
5881 filename_to_utf16 (path, path_w);
5882 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5883 FILE_FLAG_OPEN_REPARSE_POINT
5884 | FILE_FLAG_BACKUP_SEMANTICS,
5885 NULL);
5887 else
5889 char path_a[MAX_PATH];
5891 filename_to_ansi (path, path_a);
5892 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5893 FILE_FLAG_OPEN_REPARSE_POINT
5894 | FILE_FLAG_BACKUP_SEMANTICS,
5895 NULL);
5897 if (sh != INVALID_HANDLE_VALUE)
5899 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5900 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5901 DWORD retbytes;
5903 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5904 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5905 &retbytes, NULL))
5906 errno = EIO;
5907 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5908 errno = EINVAL;
5909 else
5911 /* Copy the link target name, in wide characters, from
5912 reparse_data, then convert it to multibyte encoding in
5913 the current locale's codepage. */
5914 WCHAR *lwname;
5915 size_t lname_size;
5916 USHORT lwname_len =
5917 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5918 WCHAR *lwname_src =
5919 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5920 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5921 size_t size_to_copy = buf_size;
5923 /* According to MSDN, PrintNameLength does not include the
5924 terminating null character. */
5925 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5926 memcpy (lwname, lwname_src, lwname_len);
5927 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5928 filename_from_utf16 (lwname, resolved);
5929 dostounix_filename (resolved);
5930 lname_size = strlen (resolved) + 1;
5931 if (lname_size <= buf_size)
5932 size_to_copy = lname_size;
5933 strncpy (buf, resolved, size_to_copy);
5934 /* Success! */
5935 retval = size_to_copy;
5937 CloseHandle (sh);
5939 else
5941 /* CreateFile failed. */
5942 DWORD w32err2 = GetLastError ();
5944 switch (w32err2)
5946 case ERROR_FILE_NOT_FOUND:
5947 case ERROR_PATH_NOT_FOUND:
5948 errno = ENOENT;
5949 break;
5950 case ERROR_ACCESS_DENIED:
5951 case ERROR_TOO_MANY_OPEN_FILES:
5952 errno = EACCES;
5953 break;
5954 default:
5955 errno = EPERM;
5956 break;
5959 if (restore_privs)
5961 restore_privilege (&privs);
5962 revert_to_self ();
5965 return retval;
5968 ssize_t
5969 readlinkat (int fd, char const *name, char *buffer,
5970 size_t buffer_size)
5972 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5973 as in fstatat. FIXME: Add proper support for readlinkat. */
5974 char fullname[MAX_UTF8_PATH];
5976 if (fd != AT_FDCWD)
5978 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5979 < 0)
5981 errno = ENAMETOOLONG;
5982 return -1;
5984 name = fullname;
5987 return readlink (name, buffer, buffer_size);
5990 /* If FILE is a symlink, return its target (stored in a static
5991 buffer); otherwise return FILE.
5993 This function repeatedly resolves symlinks in the last component of
5994 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5995 until it arrives at a file whose last component is not a symlink,
5996 or some error occurs. It returns the target of the last
5997 successfully resolved symlink in the chain. If it succeeds to
5998 resolve even a single symlink, the value returned is an absolute
5999 file name with backslashes (result of GetFullPathName). By
6000 contrast, if the original FILE is returned, it is unaltered.
6002 Note: This function can set errno even if it succeeds.
6004 Implementation note: we only resolve the last portion ("basename")
6005 of the argument FILE and of each following file in the chain,
6006 disregarding any possible symlinks in its leading directories.
6007 This is because Windows system calls and library functions
6008 transparently resolve symlinks in leading directories and return
6009 correct information, as long as the basename is not a symlink. */
6010 static char *
6011 chase_symlinks (const char *file)
6013 static char target[MAX_UTF8_PATH];
6014 char link[MAX_UTF8_PATH];
6015 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
6016 char target_a[MAX_PATH], link_a[MAX_PATH];
6017 ssize_t res, link_len;
6018 int loop_count = 0;
6020 if (is_windows_9x () == TRUE || !is_symlink (file))
6021 return (char *)file;
6023 if (w32_unicode_filenames)
6025 wchar_t file_w[MAX_PATH];
6027 filename_to_utf16 (file, file_w);
6028 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
6029 return (char *)file;
6030 filename_from_utf16 (link_w, link);
6032 else
6034 char file_a[MAX_PATH];
6036 filename_to_ansi (file, file_a);
6037 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
6038 return (char *)file;
6039 filename_from_ansi (link_a, link);
6041 link_len = strlen (link);
6043 target[0] = '\0';
6044 do {
6046 /* Remove trailing slashes, as we want to resolve the last
6047 non-trivial part of the link name. */
6048 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
6049 link[link_len--] = '\0';
6051 res = readlink (link, target, MAX_UTF8_PATH);
6052 if (res > 0)
6054 target[res] = '\0';
6055 if (!(IS_DEVICE_SEP (target[1])
6056 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
6058 /* Target is relative. Append it to the directory part of
6059 the symlink, then copy the result back to target. */
6060 char *p = link + link_len;
6062 while (p > link && !IS_ANY_SEP (p[-1]))
6063 p--;
6064 strcpy (p, target);
6065 strcpy (target, link);
6067 /* Resolve any "." and ".." to get a fully-qualified file name
6068 in link[] again. */
6069 if (w32_unicode_filenames)
6071 filename_to_utf16 (target, target_w);
6072 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
6073 if (link_len > 0)
6074 filename_from_utf16 (link_w, link);
6076 else
6078 filename_to_ansi (target, target_a);
6079 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
6080 if (link_len > 0)
6081 filename_from_ansi (link_a, link);
6083 link_len = strlen (link);
6085 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
6087 if (loop_count > 100)
6088 errno = ELOOP;
6090 if (target[0] == '\0') /* not a single call to readlink succeeded */
6091 return (char *)file;
6092 return target;
6096 /* Posix ACL emulation. */
6099 acl_valid (acl_t acl)
6101 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
6104 char *
6105 acl_to_text (acl_t acl, ssize_t *size)
6107 LPTSTR str_acl;
6108 SECURITY_INFORMATION flags =
6109 OWNER_SECURITY_INFORMATION |
6110 GROUP_SECURITY_INFORMATION |
6111 DACL_SECURITY_INFORMATION;
6112 char *retval = NULL;
6113 ULONG local_size;
6114 int e = errno;
6116 errno = 0;
6118 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
6120 errno = e;
6121 /* We don't want to mix heaps, so we duplicate the string in our
6122 heap and free the one allocated by the API. */
6123 retval = xstrdup (str_acl);
6124 if (size)
6125 *size = local_size;
6126 LocalFree (str_acl);
6128 else if (errno != ENOTSUP)
6129 errno = EINVAL;
6131 return retval;
6134 acl_t
6135 acl_from_text (const char *acl_str)
6137 PSECURITY_DESCRIPTOR psd, retval = NULL;
6138 ULONG sd_size;
6139 int e = errno;
6141 errno = 0;
6143 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
6145 errno = e;
6146 retval = xmalloc (sd_size);
6147 memcpy (retval, psd, sd_size);
6148 LocalFree (psd);
6150 else if (errno != ENOTSUP)
6151 errno = EINVAL;
6153 return retval;
6157 acl_free (void *ptr)
6159 xfree (ptr);
6160 return 0;
6163 acl_t
6164 acl_get_file (const char *fname, acl_type_t type)
6166 PSECURITY_DESCRIPTOR psd = NULL;
6167 const char *filename;
6169 if (type == ACL_TYPE_ACCESS)
6171 DWORD sd_len, err;
6172 SECURITY_INFORMATION si =
6173 OWNER_SECURITY_INFORMATION |
6174 GROUP_SECURITY_INFORMATION |
6175 DACL_SECURITY_INFORMATION ;
6176 int e = errno;
6178 filename = map_w32_filename (fname, NULL);
6179 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6180 fname = chase_symlinks (filename);
6181 else
6182 fname = filename;
6184 errno = 0;
6185 if (!get_file_security (fname, si, psd, 0, &sd_len)
6186 && errno != ENOTSUP)
6188 err = GetLastError ();
6189 if (err == ERROR_INSUFFICIENT_BUFFER)
6191 psd = xmalloc (sd_len);
6192 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
6194 xfree (psd);
6195 errno = EIO;
6196 psd = NULL;
6199 else if (err == ERROR_FILE_NOT_FOUND
6200 || err == ERROR_PATH_NOT_FOUND
6201 /* ERROR_INVALID_NAME is what we get if
6202 w32-unicode-filenames is nil and the file cannot
6203 be encoded in the current ANSI codepage. */
6204 || err == ERROR_INVALID_NAME)
6205 errno = ENOENT;
6206 else
6207 errno = EIO;
6209 else if (!errno)
6210 errno = e;
6212 else if (type != ACL_TYPE_DEFAULT)
6213 errno = EINVAL;
6215 return psd;
6219 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
6221 TOKEN_PRIVILEGES old1, old2;
6222 DWORD err;
6223 int st = 0, retval = -1;
6224 SECURITY_INFORMATION flags = 0;
6225 PSID psidOwner, psidGroup;
6226 PACL pacl;
6227 BOOL dflt;
6228 BOOL dacl_present;
6229 int e;
6230 const char *filename;
6232 if (acl_valid (acl) != 0
6233 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
6235 errno = EINVAL;
6236 return -1;
6239 if (type == ACL_TYPE_DEFAULT)
6241 errno = ENOSYS;
6242 return -1;
6245 filename = map_w32_filename (fname, NULL);
6246 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6247 fname = chase_symlinks (filename);
6248 else
6249 fname = filename;
6251 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
6252 &dflt)
6253 && psidOwner)
6254 flags |= OWNER_SECURITY_INFORMATION;
6255 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
6256 &dflt)
6257 && psidGroup)
6258 flags |= GROUP_SECURITY_INFORMATION;
6259 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
6260 &pacl, &dflt)
6261 && dacl_present)
6262 flags |= DACL_SECURITY_INFORMATION;
6263 if (!flags)
6264 return 0;
6266 /* According to KB-245153, setting the owner will succeed if either:
6267 (1) the caller is the user who will be the new owner, and has the
6268 SE_TAKE_OWNERSHIP privilege, or
6269 (2) the caller has the SE_RESTORE privilege, in which case she can
6270 set any valid user or group as the owner
6272 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
6273 privileges, and disregard any failures in obtaining them. If
6274 these privileges cannot be obtained, and do not already exist in
6275 the calling thread's security token, this function could fail
6276 with EPERM. */
6277 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
6278 st++;
6279 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
6280 st++;
6282 e = errno;
6283 errno = 0;
6284 /* SetFileSecurity is deprecated by MS, and sometimes fails when
6285 DACL inheritance is involved, but it seems to preserve ownership
6286 better than SetNamedSecurityInfo, which is important e.g., in
6287 copy-file. */
6288 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
6290 err = GetLastError ();
6292 if (errno != ENOTSUP)
6293 err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
6294 psidOwner, psidGroup, pacl, NULL);
6296 else
6297 err = ERROR_SUCCESS;
6298 if (err != ERROR_SUCCESS)
6300 if (errno == ENOTSUP)
6302 else if (err == ERROR_INVALID_OWNER
6303 || err == ERROR_NOT_ALL_ASSIGNED
6304 || err == ERROR_ACCESS_DENIED)
6306 /* Maybe the requested ACL and the one the file already has
6307 are identical, in which case we can silently ignore the
6308 failure. (And no, Windows doesn't.) */
6309 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
6311 errno = EPERM;
6312 if (current_acl)
6314 char *acl_from = acl_to_text (current_acl, NULL);
6315 char *acl_to = acl_to_text (acl, NULL);
6317 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
6319 retval = 0;
6320 errno = e;
6322 if (acl_from)
6323 acl_free (acl_from);
6324 if (acl_to)
6325 acl_free (acl_to);
6326 acl_free (current_acl);
6329 else if (err == ERROR_FILE_NOT_FOUND
6330 || err == ERROR_PATH_NOT_FOUND
6331 /* ERROR_INVALID_NAME is what we get if
6332 w32-unicode-filenames is nil and the file cannot be
6333 encoded in the current ANSI codepage. */
6334 || err == ERROR_INVALID_NAME)
6335 errno = ENOENT;
6336 else
6337 errno = EACCES;
6339 else
6341 retval = 0;
6342 errno = e;
6345 if (st)
6347 if (st >= 2)
6348 restore_privilege (&old2);
6349 restore_privilege (&old1);
6350 revert_to_self ();
6353 return retval;
6357 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
6358 have a fixed max size for file names, so we don't need the kind of
6359 alloc/malloc/realloc dance the gnulib version does. We also don't
6360 support FD-relative symlinks. */
6361 char *
6362 careadlinkat (int fd, char const *filename,
6363 char *buffer, size_t buffer_size,
6364 struct allocator const *alloc,
6365 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6367 char linkname[MAX_UTF8_PATH];
6368 ssize_t link_size;
6370 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6372 if (link_size > 0)
6374 char *retval = buffer;
6376 linkname[link_size++] = '\0';
6377 if (link_size > buffer_size)
6378 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6379 if (retval)
6380 memcpy (retval, linkname, link_size);
6382 return retval;
6384 return NULL;
6388 w32_copy_file (const char *from, const char *to,
6389 int keep_time, int preserve_ownership, int copy_acls)
6391 acl_t acl = NULL;
6392 BOOL copy_result;
6393 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6394 char from_a[MAX_PATH], to_a[MAX_PATH];
6396 /* We ignore preserve_ownership for now. */
6397 preserve_ownership = preserve_ownership;
6399 if (copy_acls)
6401 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6402 if (acl == NULL && acl_errno_valid (errno))
6403 return -2;
6405 if (w32_unicode_filenames)
6407 filename_to_utf16 (from, from_w);
6408 filename_to_utf16 (to, to_w);
6409 copy_result = CopyFileW (from_w, to_w, FALSE);
6411 else
6413 filename_to_ansi (from, from_a);
6414 filename_to_ansi (to, to_a);
6415 copy_result = CopyFileA (from_a, to_a, FALSE);
6417 if (!copy_result)
6419 /* CopyFile doesn't set errno when it fails. By far the most
6420 "popular" reason is that the target is read-only. */
6421 DWORD err = GetLastError ();
6423 switch (err)
6425 case ERROR_FILE_NOT_FOUND:
6426 errno = ENOENT;
6427 break;
6428 case ERROR_ACCESS_DENIED:
6429 errno = EACCES;
6430 break;
6431 case ERROR_ENCRYPTION_FAILED:
6432 errno = EIO;
6433 break;
6434 default:
6435 errno = EPERM;
6436 break;
6439 if (acl)
6440 acl_free (acl);
6441 return -1;
6443 /* CopyFile retains the timestamp by default. However, see
6444 "Community Additions" for CopyFile: it sounds like that is not
6445 entirely true. Testing on Windows XP confirms that modified time
6446 is copied, but creation and last-access times are not.
6447 FIXME? */
6448 else if (!keep_time)
6450 struct timespec now;
6451 DWORD attributes;
6453 if (w32_unicode_filenames)
6455 /* Ensure file is writable while its times are set. */
6456 attributes = GetFileAttributesW (to_w);
6457 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6458 now = current_timespec ();
6459 if (set_file_times (-1, to, now, now))
6461 /* Restore original attributes. */
6462 SetFileAttributesW (to_w, attributes);
6463 if (acl)
6464 acl_free (acl);
6465 return -3;
6467 /* Restore original attributes. */
6468 SetFileAttributesW (to_w, attributes);
6470 else
6472 attributes = GetFileAttributesA (to_a);
6473 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6474 now = current_timespec ();
6475 if (set_file_times (-1, to, now, now))
6477 SetFileAttributesA (to_a, attributes);
6478 if (acl)
6479 acl_free (acl);
6480 return -3;
6482 SetFileAttributesA (to_a, attributes);
6485 if (acl != NULL)
6487 bool fail =
6488 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6489 acl_free (acl);
6490 if (fail && acl_errno_valid (errno))
6491 return -4;
6494 return 0;
6498 /* Support for browsing other processes and their attributes. See
6499 process.c for the Lisp bindings. */
6501 /* Helper wrapper functions. */
6503 static HANDLE WINAPI
6504 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6506 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6508 if (g_b_init_create_toolhelp32_snapshot == 0)
6510 g_b_init_create_toolhelp32_snapshot = 1;
6511 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6512 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6513 "CreateToolhelp32Snapshot");
6515 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6517 return INVALID_HANDLE_VALUE;
6519 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6522 static BOOL WINAPI
6523 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6525 static Process32First_Proc s_pfn_Process32_First = NULL;
6527 if (g_b_init_process32_first == 0)
6529 g_b_init_process32_first = 1;
6530 s_pfn_Process32_First = (Process32First_Proc)
6531 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6532 "Process32First");
6534 if (s_pfn_Process32_First == NULL)
6536 return FALSE;
6538 return (s_pfn_Process32_First (hSnapshot, lppe));
6541 static BOOL WINAPI
6542 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6544 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6546 if (g_b_init_process32_next == 0)
6548 g_b_init_process32_next = 1;
6549 s_pfn_Process32_Next = (Process32Next_Proc)
6550 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6551 "Process32Next");
6553 if (s_pfn_Process32_Next == NULL)
6555 return FALSE;
6557 return (s_pfn_Process32_Next (hSnapshot, lppe));
6560 static BOOL WINAPI
6561 open_thread_token (HANDLE ThreadHandle,
6562 DWORD DesiredAccess,
6563 BOOL OpenAsSelf,
6564 PHANDLE TokenHandle)
6566 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6567 HMODULE hm_advapi32 = NULL;
6568 if (is_windows_9x () == TRUE)
6570 SetLastError (ERROR_NOT_SUPPORTED);
6571 return FALSE;
6573 if (g_b_init_open_thread_token == 0)
6575 g_b_init_open_thread_token = 1;
6576 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6577 s_pfn_Open_Thread_Token =
6578 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6580 if (s_pfn_Open_Thread_Token == NULL)
6582 SetLastError (ERROR_NOT_SUPPORTED);
6583 return FALSE;
6585 return (
6586 s_pfn_Open_Thread_Token (
6587 ThreadHandle,
6588 DesiredAccess,
6589 OpenAsSelf,
6590 TokenHandle)
6594 static BOOL WINAPI
6595 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6597 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6598 HMODULE hm_advapi32 = NULL;
6599 if (is_windows_9x () == TRUE)
6601 return FALSE;
6603 if (g_b_init_impersonate_self == 0)
6605 g_b_init_impersonate_self = 1;
6606 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6607 s_pfn_Impersonate_Self =
6608 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6610 if (s_pfn_Impersonate_Self == NULL)
6612 return FALSE;
6614 return s_pfn_Impersonate_Self (ImpersonationLevel);
6617 static BOOL WINAPI
6618 revert_to_self (void)
6620 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6621 HMODULE hm_advapi32 = NULL;
6622 if (is_windows_9x () == TRUE)
6624 return FALSE;
6626 if (g_b_init_revert_to_self == 0)
6628 g_b_init_revert_to_self = 1;
6629 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6630 s_pfn_Revert_To_Self =
6631 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6633 if (s_pfn_Revert_To_Self == NULL)
6635 return FALSE;
6637 return s_pfn_Revert_To_Self ();
6640 static BOOL WINAPI
6641 get_process_memory_info (HANDLE h_proc,
6642 PPROCESS_MEMORY_COUNTERS mem_counters,
6643 DWORD bufsize)
6645 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6646 HMODULE hm_psapi = NULL;
6647 if (is_windows_9x () == TRUE)
6649 return FALSE;
6651 if (g_b_init_get_process_memory_info == 0)
6653 g_b_init_get_process_memory_info = 1;
6654 hm_psapi = LoadLibrary ("Psapi.dll");
6655 if (hm_psapi)
6656 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6657 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6659 if (s_pfn_Get_Process_Memory_Info == NULL)
6661 return FALSE;
6663 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6666 static BOOL WINAPI
6667 get_process_working_set_size (HANDLE h_proc,
6668 PSIZE_T minrss,
6669 PSIZE_T maxrss)
6671 static GetProcessWorkingSetSize_Proc
6672 s_pfn_Get_Process_Working_Set_Size = NULL;
6674 if (is_windows_9x () == TRUE)
6676 return FALSE;
6678 if (g_b_init_get_process_working_set_size == 0)
6680 g_b_init_get_process_working_set_size = 1;
6681 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6682 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6683 "GetProcessWorkingSetSize");
6685 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6687 return FALSE;
6689 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6692 static BOOL WINAPI
6693 global_memory_status (MEMORYSTATUS *buf)
6695 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6697 if (is_windows_9x () == TRUE)
6699 return FALSE;
6701 if (g_b_init_global_memory_status == 0)
6703 g_b_init_global_memory_status = 1;
6704 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6705 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6706 "GlobalMemoryStatus");
6708 if (s_pfn_Global_Memory_Status == NULL)
6710 return FALSE;
6712 return s_pfn_Global_Memory_Status (buf);
6715 static BOOL WINAPI
6716 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6718 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6720 if (is_windows_9x () == TRUE)
6722 return FALSE;
6724 if (g_b_init_global_memory_status_ex == 0)
6726 g_b_init_global_memory_status_ex = 1;
6727 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6728 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6729 "GlobalMemoryStatusEx");
6731 if (s_pfn_Global_Memory_Status_Ex == NULL)
6733 return FALSE;
6735 return s_pfn_Global_Memory_Status_Ex (buf);
6738 Lisp_Object
6739 list_system_processes (void)
6741 Lisp_Object proclist = Qnil;
6742 HANDLE h_snapshot;
6744 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6746 if (h_snapshot != INVALID_HANDLE_VALUE)
6748 PROCESSENTRY32 proc_entry;
6749 DWORD proc_id;
6750 BOOL res;
6752 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6753 for (res = process32_first (h_snapshot, &proc_entry); res;
6754 res = process32_next (h_snapshot, &proc_entry))
6756 proc_id = proc_entry.th32ProcessID;
6757 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6760 CloseHandle (h_snapshot);
6761 proclist = Fnreverse (proclist);
6764 return proclist;
6767 static int
6768 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6770 TOKEN_PRIVILEGES priv;
6771 DWORD priv_size = sizeof (priv);
6772 DWORD opriv_size = sizeof (*old_priv);
6773 HANDLE h_token = NULL;
6774 HANDLE h_thread = GetCurrentThread ();
6775 int ret_val = 0;
6776 BOOL res;
6778 res = open_thread_token (h_thread,
6779 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6780 FALSE, &h_token);
6781 if (!res && GetLastError () == ERROR_NO_TOKEN)
6783 if (impersonate_self (SecurityImpersonation))
6784 res = open_thread_token (h_thread,
6785 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6786 FALSE, &h_token);
6788 if (res)
6790 priv.PrivilegeCount = 1;
6791 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6792 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6793 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6794 old_priv, &opriv_size)
6795 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6796 ret_val = 1;
6798 if (h_token)
6799 CloseHandle (h_token);
6801 return ret_val;
6804 static int
6805 restore_privilege (TOKEN_PRIVILEGES *priv)
6807 DWORD priv_size = sizeof (*priv);
6808 HANDLE h_token = NULL;
6809 int ret_val = 0;
6811 if (open_thread_token (GetCurrentThread (),
6812 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6813 FALSE, &h_token))
6815 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6816 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6817 ret_val = 1;
6819 if (h_token)
6820 CloseHandle (h_token);
6822 return ret_val;
6825 static Lisp_Object
6826 ltime (ULONGLONG time_100ns)
6828 ULONGLONG time_sec = time_100ns / 10000000;
6829 int subsec = time_100ns % 10000000;
6830 return list4i (time_sec >> 16, time_sec & 0xffff,
6831 subsec / 10, subsec % 10 * 100000);
6834 #define U64_TO_LISP_TIME(time) ltime (time)
6836 static int
6837 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6838 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6839 double *pcpu)
6841 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6842 ULONGLONG tem1, tem2, tem3, tem;
6844 if (!h_proc
6845 || !get_process_times_fn
6846 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6847 &ft_kernel, &ft_user))
6848 return 0;
6850 GetSystemTimeAsFileTime (&ft_current);
6852 FILETIME_TO_U64 (tem1, ft_kernel);
6853 *stime = U64_TO_LISP_TIME (tem1);
6855 FILETIME_TO_U64 (tem2, ft_user);
6856 *utime = U64_TO_LISP_TIME (tem2);
6858 tem3 = tem1 + tem2;
6859 *ttime = U64_TO_LISP_TIME (tem3);
6861 FILETIME_TO_U64 (tem, ft_creation);
6862 /* Process no 4 (System) returns zero creation time. */
6863 if (tem)
6864 tem -= utc_base;
6865 *ctime = U64_TO_LISP_TIME (tem);
6867 if (tem)
6869 FILETIME_TO_U64 (tem3, ft_current);
6870 tem = (tem3 - utc_base) - tem;
6872 *etime = U64_TO_LISP_TIME (tem);
6874 if (tem)
6876 *pcpu = 100.0 * (tem1 + tem2) / tem;
6877 if (*pcpu > 100)
6878 *pcpu = 100.0;
6880 else
6881 *pcpu = 0;
6883 return 1;
6886 Lisp_Object
6887 system_process_attributes (Lisp_Object pid)
6889 Lisp_Object attrs = Qnil;
6890 Lisp_Object cmd_str, decoded_cmd, tem;
6891 HANDLE h_snapshot, h_proc;
6892 DWORD proc_id;
6893 int found_proc = 0;
6894 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
6895 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
6896 DWORD glength = sizeof (gname);
6897 HANDLE token = NULL;
6898 SID_NAME_USE user_type;
6899 unsigned char *buf = NULL;
6900 DWORD blen = 0;
6901 TOKEN_USER user_token;
6902 TOKEN_PRIMARY_GROUP group_token;
6903 unsigned euid;
6904 unsigned egid;
6905 PROCESS_MEMORY_COUNTERS mem;
6906 PROCESS_MEMORY_COUNTERS_EX mem_ex;
6907 SIZE_T minrss, maxrss;
6908 MEMORYSTATUS memst;
6909 MEMORY_STATUS_EX memstex;
6910 double totphys = 0.0;
6911 Lisp_Object ctime, stime, utime, etime, ttime;
6912 double pcpu;
6913 BOOL result = FALSE;
6915 CHECK_NUMBER_OR_FLOAT (pid);
6916 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
6918 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6920 if (h_snapshot != INVALID_HANDLE_VALUE)
6922 PROCESSENTRY32 pe;
6923 BOOL res;
6925 pe.dwSize = sizeof (PROCESSENTRY32);
6926 for (res = process32_first (h_snapshot, &pe); res;
6927 res = process32_next (h_snapshot, &pe))
6929 if (proc_id == pe.th32ProcessID)
6931 if (proc_id == 0)
6932 decoded_cmd = build_string ("Idle");
6933 else
6935 /* Decode the command name from locale-specific
6936 encoding. */
6937 cmd_str = build_unibyte_string (pe.szExeFile);
6939 decoded_cmd =
6940 code_convert_string_norecord (cmd_str,
6941 Vlocale_coding_system, 0);
6943 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
6944 attrs = Fcons (Fcons (Qppid,
6945 make_fixnum_or_float (pe.th32ParentProcessID)),
6946 attrs);
6947 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
6948 attrs);
6949 attrs = Fcons (Fcons (Qthcount,
6950 make_fixnum_or_float (pe.cntThreads)),
6951 attrs);
6952 found_proc = 1;
6953 break;
6957 CloseHandle (h_snapshot);
6960 if (!found_proc)
6961 return Qnil;
6963 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6964 FALSE, proc_id);
6965 /* If we were denied a handle to the process, try again after
6966 enabling the SeDebugPrivilege in our process. */
6967 if (!h_proc)
6969 TOKEN_PRIVILEGES priv_current;
6971 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
6973 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6974 FALSE, proc_id);
6975 restore_privilege (&priv_current);
6976 revert_to_self ();
6979 if (h_proc)
6981 result = open_process_token (h_proc, TOKEN_QUERY, &token);
6982 if (result)
6984 result = get_token_information (token, TokenUser, NULL, 0, &blen);
6985 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6987 buf = xmalloc (blen);
6988 result = get_token_information (token, TokenUser,
6989 (LPVOID)buf, blen, &needed);
6990 if (result)
6992 memcpy (&user_token, buf, sizeof (user_token));
6993 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
6995 euid = get_rid (user_token.User.Sid);
6996 result = lookup_account_sid (NULL, user_token.User.Sid,
6997 uname, &ulength,
6998 domain, &dlength,
6999 &user_type);
7000 if (result)
7001 w32_add_to_cache (user_token.User.Sid, euid, uname);
7002 else
7004 strcpy (uname, "unknown");
7005 result = TRUE;
7008 ulength = strlen (uname);
7012 if (result)
7014 /* Determine a reasonable euid and gid values. */
7015 if (xstrcasecmp ("administrator", uname) == 0)
7017 euid = 500; /* well-known Administrator uid */
7018 egid = 513; /* well-known None gid */
7020 else
7022 /* Get group id and name. */
7023 result = get_token_information (token, TokenPrimaryGroup,
7024 (LPVOID)buf, blen, &needed);
7025 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7027 buf = xrealloc (buf, blen = needed);
7028 result = get_token_information (token, TokenPrimaryGroup,
7029 (LPVOID)buf, blen, &needed);
7031 if (result)
7033 memcpy (&group_token, buf, sizeof (group_token));
7034 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
7036 egid = get_rid (group_token.PrimaryGroup);
7037 dlength = sizeof (domain);
7038 result =
7039 lookup_account_sid (NULL, group_token.PrimaryGroup,
7040 gname, &glength, NULL, &dlength,
7041 &user_type);
7042 if (result)
7043 w32_add_to_cache (group_token.PrimaryGroup,
7044 egid, gname);
7045 else
7047 strcpy (gname, "None");
7048 result = TRUE;
7051 glength = strlen (gname);
7055 xfree (buf);
7057 if (!result)
7059 if (!is_windows_9x ())
7061 /* We couldn't open the process token, presumably because of
7062 insufficient access rights. Assume this process is run
7063 by the system. */
7064 strcpy (uname, "SYSTEM");
7065 strcpy (gname, "None");
7066 euid = 18; /* SYSTEM */
7067 egid = 513; /* None */
7068 glength = strlen (gname);
7069 ulength = strlen (uname);
7071 /* If we are running under Windows 9X, where security calls are
7072 not supported, we assume all processes are run by the current
7073 user. */
7074 else if (GetUserName (uname, &ulength))
7076 if (xstrcasecmp ("administrator", uname) == 0)
7077 euid = 0;
7078 else
7079 euid = 123;
7080 egid = euid;
7081 strcpy (gname, "None");
7082 glength = strlen (gname);
7083 ulength = strlen (uname);
7085 else
7087 euid = 123;
7088 egid = 123;
7089 strcpy (uname, "administrator");
7090 ulength = strlen (uname);
7091 strcpy (gname, "None");
7092 glength = strlen (gname);
7094 if (token)
7095 CloseHandle (token);
7098 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
7099 tem = make_unibyte_string (uname, ulength);
7100 attrs = Fcons (Fcons (Quser,
7101 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7102 attrs);
7103 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
7104 tem = make_unibyte_string (gname, glength);
7105 attrs = Fcons (Fcons (Qgroup,
7106 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7107 attrs);
7109 if (global_memory_status_ex (&memstex))
7110 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
7111 totphys = memstex.ullTotalPhys / 1024.0;
7112 #else
7113 /* Visual Studio 6 cannot convert an unsigned __int64 type to
7114 double, so we need to do this for it... */
7116 DWORD tot_hi = memstex.ullTotalPhys >> 32;
7117 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
7118 DWORD tot_lo = memstex.ullTotalPhys % 1024;
7120 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
7122 #endif /* __GNUC__ || _MSC_VER >= 1300 */
7123 else if (global_memory_status (&memst))
7124 totphys = memst.dwTotalPhys / 1024.0;
7126 if (h_proc
7127 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
7128 sizeof (mem_ex)))
7130 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7132 attrs = Fcons (Fcons (Qmajflt,
7133 make_fixnum_or_float (mem_ex.PageFaultCount)),
7134 attrs);
7135 attrs = Fcons (Fcons (Qvsize,
7136 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
7137 attrs);
7138 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7139 if (totphys)
7140 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7142 else if (h_proc
7143 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
7145 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7147 attrs = Fcons (Fcons (Qmajflt,
7148 make_fixnum_or_float (mem.PageFaultCount)),
7149 attrs);
7150 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7151 if (totphys)
7152 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7154 else if (h_proc
7155 && get_process_working_set_size (h_proc, &minrss, &maxrss))
7157 DWORD rss = maxrss / 1024;
7159 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
7160 if (totphys)
7161 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7164 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
7166 attrs = Fcons (Fcons (Qutime, utime), attrs);
7167 attrs = Fcons (Fcons (Qstime, stime), attrs);
7168 attrs = Fcons (Fcons (Qtime, ttime), attrs);
7169 attrs = Fcons (Fcons (Qstart, ctime), attrs);
7170 attrs = Fcons (Fcons (Qetime, etime), attrs);
7171 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
7174 /* FIXME: Retrieve command line by walking the PEB of the process. */
7176 if (h_proc)
7177 CloseHandle (h_proc);
7178 return attrs;
7182 w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
7183 unsigned long long *totalswap, unsigned long long *freeswap)
7185 MEMORYSTATUS memst;
7186 MEMORY_STATUS_EX memstex;
7188 /* Use GlobalMemoryStatusEx if available, as it can report more than
7189 2GB of memory. */
7190 if (global_memory_status_ex (&memstex))
7192 *totalram = memstex.ullTotalPhys;
7193 *freeram = memstex.ullAvailPhys;
7194 *totalswap = memstex.ullTotalPageFile;
7195 *freeswap = memstex.ullAvailPageFile;
7196 return 0;
7198 else if (global_memory_status (&memst))
7200 *totalram = memst.dwTotalPhys;
7201 *freeram = memst.dwAvailPhys;
7202 *totalswap = memst.dwTotalPageFile;
7203 *freeswap = memst.dwAvailPageFile;
7204 return 0;
7206 else
7207 return -1;
7211 /* Wrappers for winsock functions to map between our file descriptors
7212 and winsock's handles; also set h_errno for convenience.
7214 To allow Emacs to run on systems which don't have winsock support
7215 installed, we dynamically link to winsock on startup if present, and
7216 otherwise provide the minimum necessary functionality
7217 (eg. gethostname). */
7219 /* function pointers for relevant socket functions */
7220 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
7221 void (PASCAL *pfn_WSASetLastError) (int iError);
7222 int (PASCAL *pfn_WSAGetLastError) (void);
7223 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
7224 int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject,
7225 WSANETWORKEVENTS *NetworkEvents);
7227 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
7228 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
7229 int (PASCAL *pfn_socket) (int af, int type, int protocol);
7230 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
7231 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
7232 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
7233 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
7234 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
7235 int (PASCAL *pfn_closesocket) (SOCKET s);
7236 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
7237 int (PASCAL *pfn_WSACleanup) (void);
7239 u_short (PASCAL *pfn_htons) (u_short hostshort);
7240 u_short (PASCAL *pfn_ntohs) (u_short netshort);
7241 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
7242 int (PASCAL *pfn_gethostname) (char * name, int namelen);
7243 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
7244 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
7245 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
7246 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
7247 const char * optval, int optlen);
7248 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
7249 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
7250 int * namelen);
7251 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
7252 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
7253 struct sockaddr * from, int * fromlen);
7254 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
7255 const struct sockaddr * to, int tolen);
7257 int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
7258 const struct addrinfo *, struct addrinfo **);
7259 void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
7261 /* SetHandleInformation is only needed to make sockets non-inheritable. */
7262 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7263 #ifndef HANDLE_FLAG_INHERIT
7264 #define HANDLE_FLAG_INHERIT 1
7265 #endif
7267 HANDLE winsock_lib;
7268 static int winsock_inuse;
7270 BOOL term_winsock (void);
7272 BOOL
7273 term_winsock (void)
7275 if (winsock_lib != NULL && winsock_inuse == 0)
7277 release_listen_threads ();
7278 /* Not sure what would cause WSAENETDOWN, or even if it can happen
7279 after WSAStartup returns successfully, but it seems reasonable
7280 to allow unloading winsock anyway in that case. */
7281 if (pfn_WSACleanup () == 0 ||
7282 pfn_WSAGetLastError () == WSAENETDOWN)
7284 if (FreeLibrary (winsock_lib))
7285 winsock_lib = NULL;
7286 return TRUE;
7289 return FALSE;
7292 BOOL
7293 init_winsock (int load_now)
7295 WSADATA winsockData;
7297 if (winsock_lib != NULL)
7298 return TRUE;
7300 pfn_SetHandleInformation
7301 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
7302 "SetHandleInformation");
7304 winsock_lib = LoadLibrary ("Ws2_32.dll");
7306 if (winsock_lib != NULL)
7308 /* dynamically link to socket functions */
7310 #define LOAD_PROC(fn) \
7311 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
7312 goto fail;
7314 LOAD_PROC (WSAStartup);
7315 LOAD_PROC (WSASetLastError);
7316 LOAD_PROC (WSAGetLastError);
7317 LOAD_PROC (WSAEventSelect);
7318 LOAD_PROC (WSAEnumNetworkEvents);
7319 LOAD_PROC (WSACreateEvent);
7320 LOAD_PROC (WSACloseEvent);
7321 LOAD_PROC (socket);
7322 LOAD_PROC (bind);
7323 LOAD_PROC (connect);
7324 LOAD_PROC (ioctlsocket);
7325 LOAD_PROC (recv);
7326 LOAD_PROC (send);
7327 LOAD_PROC (closesocket);
7328 LOAD_PROC (shutdown);
7329 LOAD_PROC (htons);
7330 LOAD_PROC (ntohs);
7331 LOAD_PROC (inet_addr);
7332 LOAD_PROC (gethostname);
7333 LOAD_PROC (gethostbyname);
7334 LOAD_PROC (getservbyname);
7335 LOAD_PROC (getpeername);
7336 LOAD_PROC (WSACleanup);
7337 LOAD_PROC (setsockopt);
7338 LOAD_PROC (listen);
7339 LOAD_PROC (getsockname);
7340 LOAD_PROC (accept);
7341 LOAD_PROC (recvfrom);
7342 LOAD_PROC (sendto);
7343 #undef LOAD_PROC
7345 /* Try loading functions not available before XP. */
7346 pfn_getaddrinfo = (void *) GetProcAddress (winsock_lib, "getaddrinfo");
7347 pfn_freeaddrinfo = (void *) GetProcAddress (winsock_lib, "freeaddrinfo");
7348 /* Paranoia: these two functions should go together, so if one
7349 is absent, we cannot use the other. */
7350 if (pfn_getaddrinfo == NULL)
7351 pfn_freeaddrinfo = NULL;
7352 else if (pfn_freeaddrinfo == NULL)
7353 pfn_getaddrinfo = NULL;
7355 /* specify version 1.1 of winsock */
7356 if (pfn_WSAStartup (0x101, &winsockData) == 0)
7358 if (winsockData.wVersion != 0x101)
7359 goto fail;
7361 if (!load_now)
7363 /* Report that winsock exists and is usable, but leave
7364 socket functions disabled. I am assuming that calling
7365 WSAStartup does not require any network interaction,
7366 and in particular does not cause or require a dial-up
7367 connection to be established. */
7369 pfn_WSACleanup ();
7370 FreeLibrary (winsock_lib);
7371 winsock_lib = NULL;
7373 winsock_inuse = 0;
7374 return TRUE;
7377 fail:
7378 FreeLibrary (winsock_lib);
7379 winsock_lib = NULL;
7382 return FALSE;
7386 int h_errno = 0;
7388 /* Function to map winsock error codes to errno codes for those errno
7389 code defined in errno.h (errno values not defined by errno.h are
7390 already in nt/inc/sys/socket.h). */
7391 static void
7392 set_errno (void)
7394 int wsa_err;
7396 h_errno = 0;
7397 if (winsock_lib == NULL)
7398 wsa_err = EINVAL;
7399 else
7400 wsa_err = pfn_WSAGetLastError ();
7402 switch (wsa_err)
7404 case WSAEACCES: errno = EACCES; break;
7405 case WSAEBADF: errno = EBADF; break;
7406 case WSAEFAULT: errno = EFAULT; break;
7407 case WSAEINTR: errno = EINTR; break;
7408 case WSAEINVAL: errno = EINVAL; break;
7409 case WSAEMFILE: errno = EMFILE; break;
7410 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7411 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7412 case WSAEWOULDBLOCK: errno = EWOULDBLOCK; break;
7413 case WSAENOTCONN: errno = ENOTCONN; break;
7414 default: errno = wsa_err; break;
7418 static void
7419 check_errno (void)
7421 h_errno = 0;
7422 if (winsock_lib != NULL)
7423 pfn_WSASetLastError (0);
7426 /* Extend strerror to handle the winsock-specific error codes. */
7427 struct {
7428 int errnum;
7429 const char * msg;
7430 } _wsa_errlist[] = {
7431 {WSAEINTR , "Interrupted function call"},
7432 {WSAEBADF , "Bad file descriptor"},
7433 {WSAEACCES , "Permission denied"},
7434 {WSAEFAULT , "Bad address"},
7435 {WSAEINVAL , "Invalid argument"},
7436 {WSAEMFILE , "Too many open files"},
7438 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7439 {WSAEINPROGRESS , "Operation now in progress"},
7440 {WSAEALREADY , "Operation already in progress"},
7441 {WSAENOTSOCK , "Socket operation on non-socket"},
7442 {WSAEDESTADDRREQ , "Destination address required"},
7443 {WSAEMSGSIZE , "Message too long"},
7444 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7445 {WSAENOPROTOOPT , "Bad protocol option"},
7446 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7447 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7448 {WSAEOPNOTSUPP , "Operation not supported"},
7449 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7450 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7451 {WSAEADDRINUSE , "Address already in use"},
7452 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7453 {WSAENETDOWN , "Network is down"},
7454 {WSAENETUNREACH , "Network is unreachable"},
7455 {WSAENETRESET , "Network dropped connection on reset"},
7456 {WSAECONNABORTED , "Software caused connection abort"},
7457 {WSAECONNRESET , "Connection reset by peer"},
7458 {WSAENOBUFS , "No buffer space available"},
7459 {WSAEISCONN , "Socket is already connected"},
7460 {WSAENOTCONN , "Socket is not connected"},
7461 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7462 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7463 {WSAETIMEDOUT , "Connection timed out"},
7464 {WSAECONNREFUSED , "Connection refused"},
7465 {WSAELOOP , "Network loop"}, /* not sure */
7466 {WSAENAMETOOLONG , "Name is too long"},
7467 {WSAEHOSTDOWN , "Host is down"},
7468 {WSAEHOSTUNREACH , "No route to host"},
7469 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7470 {WSAEPROCLIM , "Too many processes"},
7471 {WSAEUSERS , "Too many users"}, /* not sure */
7472 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7473 {WSAESTALE , "Data is stale"}, /* not sure */
7474 {WSAEREMOTE , "Remote error"}, /* not sure */
7476 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7477 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7478 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7479 {WSAEDISCON , "Graceful shutdown in progress"},
7480 #ifdef WSAENOMORE
7481 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7482 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7483 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7484 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7485 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7486 {WSASYSCALLFAILURE , "System call failure"},
7487 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7488 {WSATYPE_NOT_FOUND , "Class type not found"},
7489 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7490 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7491 {WSAEREFUSED , "Operation refused"}, /* not sure */
7492 #endif
7494 {WSAHOST_NOT_FOUND , "Host not found"},
7495 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7496 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7497 {WSANO_DATA , "Valid name, no data record of requested type"},
7499 {-1, NULL}
7502 char *
7503 sys_strerror (int error_no)
7505 int i;
7506 static char unknown_msg[40];
7508 if (error_no >= 0 && error_no < sys_nerr)
7509 return sys_errlist[error_no];
7511 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7512 if (_wsa_errlist[i].errnum == error_no)
7513 return (char *)_wsa_errlist[i].msg;
7515 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7516 return unknown_msg;
7519 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7520 but I believe the method of keeping the socket handle separate (and
7521 insuring it is not inheritable) is the correct one. */
7523 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7525 static int socket_to_fd (SOCKET s);
7528 sys_socket (int af, int type, int protocol)
7530 SOCKET s;
7532 if (winsock_lib == NULL)
7534 errno = ENETDOWN;
7535 return -1;
7538 check_errno ();
7540 /* call the real socket function */
7541 s = pfn_socket (af, type, protocol);
7543 if (s != INVALID_SOCKET)
7544 return socket_to_fd (s);
7546 set_errno ();
7547 return -1;
7550 /* Convert a SOCKET to a file descriptor. */
7551 static int
7552 socket_to_fd (SOCKET s)
7554 int fd;
7555 child_process * cp;
7557 /* Although under NT 3.5 _open_osfhandle will accept a socket
7558 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7559 that does not work under NT 3.1. However, we can get the same
7560 effect by using a backdoor function to replace an existing
7561 descriptor handle with the one we want. */
7563 /* allocate a file descriptor (with appropriate flags) */
7564 fd = _open ("NUL:", _O_RDWR);
7565 if (fd >= 0)
7567 /* Make a non-inheritable copy of the socket handle. Note
7568 that it is possible that sockets aren't actually kernel
7569 handles, which appears to be the case on Windows 9x when
7570 the MS Proxy winsock client is installed. */
7572 /* Apparently there is a bug in NT 3.51 with some service
7573 packs, which prevents using DuplicateHandle to make a
7574 socket handle non-inheritable (causes WSACleanup to
7575 hang). The work-around is to use SetHandleInformation
7576 instead if it is available and implemented. */
7577 if (pfn_SetHandleInformation)
7579 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7581 else
7583 HANDLE parent = GetCurrentProcess ();
7584 HANDLE new_s = INVALID_HANDLE_VALUE;
7586 if (DuplicateHandle (parent,
7587 (HANDLE) s,
7588 parent,
7589 &new_s,
7591 FALSE,
7592 DUPLICATE_SAME_ACCESS))
7594 /* It is possible that DuplicateHandle succeeds even
7595 though the socket wasn't really a kernel handle,
7596 because a real handle has the same value. So
7597 test whether the new handle really is a socket. */
7598 unsigned long nonblocking = 0;
7599 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7601 pfn_closesocket (s);
7602 s = (SOCKET) new_s;
7604 else
7606 CloseHandle (new_s);
7611 eassert (fd < MAXDESC);
7612 fd_info[fd].hnd = (HANDLE) s;
7614 /* set our own internal flags */
7615 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7617 cp = new_child ();
7618 if (cp)
7620 cp->fd = fd;
7621 cp->status = STATUS_READ_ACKNOWLEDGED;
7623 /* attach child_process to fd_info */
7624 if (fd_info[ fd ].cp != NULL)
7626 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7627 emacs_abort ();
7630 fd_info[ fd ].cp = cp;
7632 /* success! */
7633 winsock_inuse++; /* count open sockets */
7634 return fd;
7637 /* clean up */
7638 _close (fd);
7640 else
7641 pfn_closesocket (s);
7642 errno = EMFILE;
7643 return -1;
7647 sys_bind (int s, const struct sockaddr * addr, int namelen)
7649 if (winsock_lib == NULL)
7651 errno = ENOTSOCK;
7652 return SOCKET_ERROR;
7655 check_errno ();
7656 if (fd_info[s].flags & FILE_SOCKET)
7658 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7659 if (rc == SOCKET_ERROR)
7660 set_errno ();
7661 return rc;
7663 errno = ENOTSOCK;
7664 return SOCKET_ERROR;
7668 sys_connect (int s, const struct sockaddr * name, int namelen)
7670 if (winsock_lib == NULL)
7672 errno = ENOTSOCK;
7673 return SOCKET_ERROR;
7676 check_errno ();
7677 if (fd_info[s].flags & FILE_SOCKET)
7679 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7680 if (rc == SOCKET_ERROR)
7682 set_errno ();
7683 /* If this is a non-blocking 'connect', set the bit in flags
7684 that will tell reader_thread to wait for connection
7685 before trying to read. */
7686 if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0)
7688 errno = EINPROGRESS; /* that's what process.c expects */
7689 fd_info[s].flags |= FILE_CONNECT;
7692 return rc;
7694 errno = ENOTSOCK;
7695 return SOCKET_ERROR;
7698 u_short
7699 sys_htons (u_short hostshort)
7701 return (winsock_lib != NULL) ?
7702 pfn_htons (hostshort) : hostshort;
7705 u_short
7706 sys_ntohs (u_short netshort)
7708 return (winsock_lib != NULL) ?
7709 pfn_ntohs (netshort) : netshort;
7712 unsigned long
7713 sys_inet_addr (const char * cp)
7715 return (winsock_lib != NULL) ?
7716 pfn_inet_addr (cp) : INADDR_NONE;
7720 sys_gethostname (char * name, int namelen)
7722 if (winsock_lib != NULL)
7724 int retval;
7726 check_errno ();
7727 retval = pfn_gethostname (name, namelen);
7728 if (retval == SOCKET_ERROR)
7729 set_errno ();
7730 return retval;
7733 if (namelen > MAX_COMPUTERNAME_LENGTH)
7734 return !GetComputerName (name, (DWORD *)&namelen);
7736 errno = EFAULT;
7737 return SOCKET_ERROR;
7740 struct hostent *
7741 sys_gethostbyname (const char * name)
7743 struct hostent * host;
7744 int h_err = h_errno;
7746 if (winsock_lib == NULL)
7748 h_errno = NO_RECOVERY;
7749 errno = ENETDOWN;
7750 return NULL;
7753 check_errno ();
7754 host = pfn_gethostbyname (name);
7755 if (!host)
7757 set_errno ();
7758 h_errno = errno;
7760 else
7761 h_errno = h_err;
7762 return host;
7765 struct servent *
7766 sys_getservbyname (const char * name, const char * proto)
7768 struct servent * serv;
7770 if (winsock_lib == NULL)
7772 errno = ENETDOWN;
7773 return NULL;
7776 check_errno ();
7777 serv = pfn_getservbyname (name, proto);
7778 if (!serv)
7779 set_errno ();
7780 return serv;
7784 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7786 if (winsock_lib == NULL)
7788 errno = ENETDOWN;
7789 return SOCKET_ERROR;
7792 check_errno ();
7793 if (fd_info[s].flags & FILE_SOCKET)
7795 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7796 if (rc == SOCKET_ERROR)
7797 set_errno ();
7798 return rc;
7800 errno = ENOTSOCK;
7801 return SOCKET_ERROR;
7805 sys_getaddrinfo (const char *node, const char *service,
7806 const struct addrinfo *hints, struct addrinfo **res)
7808 int rc;
7810 if (winsock_lib == NULL)
7812 errno = ENETDOWN;
7813 return SOCKET_ERROR;
7816 check_errno ();
7817 if (pfn_getaddrinfo)
7818 rc = pfn_getaddrinfo (node, service, hints, res);
7819 else
7821 int port = 0;
7822 struct hostent *host_info;
7823 struct gai_storage {
7824 struct addrinfo addrinfo;
7825 struct sockaddr_in sockaddr_in;
7826 } *gai_storage;
7828 /* We don't (yet) support any flags, as Emacs doesn't need that. */
7829 if (hints && hints->ai_flags != 0)
7830 return WSAEINVAL;
7831 /* NODE cannot be NULL, since process.c has fallbacks for that. */
7832 if (!node)
7833 return WSAHOST_NOT_FOUND;
7835 if (service)
7837 const char *protocol =
7838 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
7839 struct servent *srv = sys_getservbyname (service, protocol);
7841 if (srv)
7842 port = srv->s_port;
7843 else if (*service >= '0' && *service <= '9')
7845 char *endp;
7847 port = strtoul (service, &endp, 10);
7848 if (*endp || port > 65536)
7849 return WSAHOST_NOT_FOUND;
7850 port = sys_htons ((unsigned short) port);
7852 else
7853 return WSAHOST_NOT_FOUND;
7856 gai_storage = xzalloc (sizeof *gai_storage);
7857 gai_storage->sockaddr_in.sin_port = port;
7858 host_info = sys_gethostbyname (node);
7859 if (host_info)
7861 memcpy (&gai_storage->sockaddr_in.sin_addr,
7862 host_info->h_addr, host_info->h_length);
7863 gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
7865 else
7867 /* Attempt to interpret host as numeric inet address. */
7868 unsigned long numeric_addr = sys_inet_addr (node);
7870 if (numeric_addr == -1)
7872 free (gai_storage);
7873 return WSAHOST_NOT_FOUND;
7876 memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
7877 sizeof (gai_storage->sockaddr_in.sin_addr));
7878 gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
7881 gai_storage->addrinfo.ai_addr =
7882 (struct sockaddr *)&gai_storage->sockaddr_in;
7883 gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
7884 gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
7885 gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
7886 gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
7887 gai_storage->addrinfo.ai_next = NULL;
7889 *res = &gai_storage->addrinfo;
7890 rc = 0;
7893 return rc;
7896 void
7897 sys_freeaddrinfo (struct addrinfo *ai)
7899 if (winsock_lib == NULL)
7901 errno = ENETDOWN;
7902 return;
7905 check_errno ();
7906 if (pfn_freeaddrinfo)
7907 pfn_freeaddrinfo (ai);
7908 else
7910 eassert (ai->ai_next == NULL);
7911 xfree (ai);
7916 sys_shutdown (int s, int how)
7918 if (winsock_lib == NULL)
7920 errno = ENETDOWN;
7921 return SOCKET_ERROR;
7924 check_errno ();
7925 if (fd_info[s].flags & FILE_SOCKET)
7927 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
7928 if (rc == SOCKET_ERROR)
7929 set_errno ();
7930 return rc;
7932 errno = ENOTSOCK;
7933 return SOCKET_ERROR;
7937 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
7939 if (winsock_lib == NULL)
7941 errno = ENETDOWN;
7942 return SOCKET_ERROR;
7945 check_errno ();
7946 if (fd_info[s].flags & FILE_SOCKET)
7948 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
7949 (const char *)optval, optlen);
7950 if (rc == SOCKET_ERROR)
7951 set_errno ();
7952 return rc;
7954 errno = ENOTSOCK;
7955 return SOCKET_ERROR;
7959 sys_listen (int s, int backlog)
7961 if (winsock_lib == NULL)
7963 errno = ENETDOWN;
7964 return SOCKET_ERROR;
7967 check_errno ();
7968 if (fd_info[s].flags & FILE_SOCKET)
7970 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
7971 if (rc == SOCKET_ERROR)
7972 set_errno ();
7973 else
7974 fd_info[s].flags |= FILE_LISTEN;
7975 return rc;
7977 errno = ENOTSOCK;
7978 return SOCKET_ERROR;
7982 sys_getsockname (int s, struct sockaddr * name, int * namelen)
7984 if (winsock_lib == NULL)
7986 errno = ENETDOWN;
7987 return SOCKET_ERROR;
7990 check_errno ();
7991 if (fd_info[s].flags & FILE_SOCKET)
7993 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
7994 if (rc == SOCKET_ERROR)
7995 set_errno ();
7996 return rc;
7998 errno = ENOTSOCK;
7999 return SOCKET_ERROR;
8003 sys_accept (int s, struct sockaddr * addr, int * addrlen)
8005 if (winsock_lib == NULL)
8007 errno = ENETDOWN;
8008 return -1;
8011 check_errno ();
8012 if (fd_info[s].flags & FILE_LISTEN)
8014 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
8015 int fd = -1;
8016 if (t == INVALID_SOCKET)
8017 set_errno ();
8018 else
8019 fd = socket_to_fd (t);
8021 if (fd >= 0)
8023 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
8024 ResetEvent (fd_info[s].cp->char_avail);
8026 return fd;
8028 errno = ENOTSOCK;
8029 return -1;
8033 sys_recvfrom (int s, char * buf, int len, int flags,
8034 struct sockaddr * from, int * fromlen)
8036 if (winsock_lib == NULL)
8038 errno = ENETDOWN;
8039 return SOCKET_ERROR;
8042 check_errno ();
8043 if (fd_info[s].flags & FILE_SOCKET)
8045 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
8046 if (rc == SOCKET_ERROR)
8047 set_errno ();
8048 return rc;
8050 errno = ENOTSOCK;
8051 return SOCKET_ERROR;
8055 sys_sendto (int s, const char * buf, int len, int flags,
8056 const struct sockaddr * to, int tolen)
8058 if (winsock_lib == NULL)
8060 errno = ENETDOWN;
8061 return SOCKET_ERROR;
8064 check_errno ();
8065 if (fd_info[s].flags & FILE_SOCKET)
8067 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
8068 if (rc == SOCKET_ERROR)
8069 set_errno ();
8070 return rc;
8072 errno = ENOTSOCK;
8073 return SOCKET_ERROR;
8076 /* Windows does not have an fcntl function. Provide an implementation
8077 good enough for Emacs. */
8079 fcntl (int s, int cmd, int options)
8081 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
8082 invoked in a context where fd1 is closed and all descriptors less
8083 than fd1 are open, so sys_dup is an adequate implementation. */
8084 if (cmd == F_DUPFD_CLOEXEC)
8085 return sys_dup (s);
8087 check_errno ();
8088 if (fd_info[s].flags & FILE_SOCKET)
8090 if (winsock_lib == NULL)
8092 errno = ENETDOWN;
8093 return -1;
8096 if (cmd == F_SETFL && options == O_NONBLOCK)
8098 unsigned long nblock = 1;
8099 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
8100 if (rc == SOCKET_ERROR)
8101 set_errno ();
8102 /* Keep track of the fact that we set this to non-blocking. */
8103 fd_info[s].flags |= FILE_NDELAY;
8104 return rc;
8106 else
8108 errno = EINVAL;
8109 return SOCKET_ERROR;
8112 else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE))
8113 == (FILE_PIPE | FILE_WRITE))
8115 /* Force our writes to pipes be non-blocking. */
8116 if (cmd == F_SETFL && options == O_NONBLOCK)
8118 HANDLE h = (HANDLE)_get_osfhandle (s);
8119 DWORD pipe_mode = PIPE_NOWAIT;
8121 if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL))
8123 DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ()));
8124 return SOCKET_ERROR;
8126 fd_info[s].flags |= FILE_NDELAY;
8127 return 0;
8129 else
8131 errno = EINVAL;
8132 return SOCKET_ERROR;
8135 errno = ENOTSOCK;
8136 return SOCKET_ERROR;
8140 /* Shadow main io functions: we need to handle pipes and sockets more
8141 intelligently. */
8144 sys_close (int fd)
8146 int rc;
8148 if (fd < 0)
8150 errno = EBADF;
8151 return -1;
8154 if (fd < MAXDESC && fd_info[fd].cp)
8156 child_process * cp = fd_info[fd].cp;
8158 fd_info[fd].cp = NULL;
8160 if (CHILD_ACTIVE (cp))
8162 /* if last descriptor to active child_process then cleanup */
8163 int i;
8164 for (i = 0; i < MAXDESC; i++)
8166 if (i == fd)
8167 continue;
8168 if (fd_info[i].cp == cp)
8169 break;
8171 if (i == MAXDESC)
8173 if (fd_info[fd].flags & FILE_SOCKET)
8175 if (winsock_lib == NULL) emacs_abort ();
8177 pfn_shutdown (SOCK_HANDLE (fd), 2);
8178 rc = pfn_closesocket (SOCK_HANDLE (fd));
8180 winsock_inuse--; /* count open sockets */
8182 /* If the process handle is NULL, it's either a socket
8183 or serial connection, or a subprocess that was
8184 already reaped by reap_subprocess, but whose
8185 resources were not yet freed, because its output was
8186 not fully read yet by the time it was reaped. (This
8187 usually happens with async subprocesses whose output
8188 is being read by Emacs.) Otherwise, this process was
8189 not reaped yet, so we set its FD to a negative value
8190 to make sure sys_select will eventually get to
8191 calling the SIGCHLD handler for it, which will then
8192 invoke waitpid and reap_subprocess. */
8193 if (cp->procinfo.hProcess == NULL)
8194 delete_child (cp);
8195 else
8196 cp->fd = -1;
8201 if (fd >= 0 && fd < MAXDESC)
8202 fd_info[fd].flags = 0;
8204 /* Note that sockets do not need special treatment here (at least on
8205 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
8206 closesocket is equivalent to CloseHandle, which is to be expected
8207 because socket handles are fully fledged kernel handles. */
8208 rc = _close (fd);
8210 return rc;
8214 sys_dup (int fd)
8216 int new_fd;
8218 new_fd = _dup (fd);
8219 if (new_fd >= 0 && new_fd < MAXDESC)
8221 /* duplicate our internal info as well */
8222 fd_info[new_fd] = fd_info[fd];
8224 return new_fd;
8228 sys_dup2 (int src, int dst)
8230 int rc;
8232 if (dst < 0 || dst >= MAXDESC)
8234 errno = EBADF;
8235 return -1;
8238 /* MS _dup2 seems to have weird side effect when invoked with 2
8239 identical arguments: an attempt to fclose the corresponding stdio
8240 stream after that hangs (we do close standard streams in
8241 init_ntproc). Attempt to avoid that by not calling _dup2 that
8242 way: if SRC is valid, we know that dup2 should be a no-op, so do
8243 nothing and return DST. */
8244 if (src == dst)
8246 if ((HANDLE)_get_osfhandle (src) == INVALID_HANDLE_VALUE)
8248 errno = EBADF;
8249 return -1;
8251 return dst;
8254 /* Make sure we close the destination first if it's a pipe or socket. */
8255 if (fd_info[dst].flags != 0)
8256 sys_close (dst);
8258 rc = _dup2 (src, dst);
8259 if (rc == 0)
8261 /* Duplicate our internal info as well. */
8262 fd_info[dst] = fd_info[src];
8264 return rc == 0 ? dst : rc;
8268 pipe2 (int * phandles, int pipe2_flags)
8270 int rc;
8271 unsigned flags;
8272 unsigned pipe_size = 0;
8274 eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
8276 /* Allow Lisp to override the default buffer size of the pipe. */
8277 if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
8278 pipe_size = w32_pipe_buffer_size;
8280 /* make pipe handles non-inheritable; when we spawn a child, we
8281 replace the relevant handle with an inheritable one. Also put
8282 pipes into binary mode; we will do text mode translation ourselves
8283 if required. */
8284 rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
8286 if (rc == 0)
8288 /* Protect against overflow, since Windows can open more handles than
8289 our fd_info array has room for. */
8290 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
8292 _close (phandles[0]);
8293 _close (phandles[1]);
8294 errno = EMFILE;
8295 rc = -1;
8297 else
8299 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
8300 fd_info[phandles[0]].flags = flags;
8302 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
8303 fd_info[phandles[1]].flags = flags;
8307 return rc;
8310 /* Function to do blocking read of one byte, needed to implement
8311 select. It is only allowed on communication ports, sockets, or
8312 pipes. */
8314 _sys_read_ahead (int fd)
8316 child_process * cp;
8317 int rc;
8319 if (fd < 0 || fd >= MAXDESC)
8320 return STATUS_READ_ERROR;
8322 cp = fd_info[fd].cp;
8324 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8325 return STATUS_READ_ERROR;
8327 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
8328 || (fd_info[fd].flags & FILE_READ) == 0)
8330 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
8331 emacs_abort ();
8334 if ((fd_info[fd].flags & FILE_CONNECT) != 0)
8335 DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd));
8336 cp->status = STATUS_READ_IN_PROGRESS;
8338 if (fd_info[fd].flags & FILE_PIPE)
8340 rc = _read (fd, &cp->chr, sizeof (char));
8342 /* Give subprocess time to buffer some more output for us before
8343 reporting that input is available; we need this because Windows 95
8344 connects DOS programs to pipes by making the pipe appear to be
8345 the normal console stdout - as a result most DOS programs will
8346 write to stdout without buffering, ie. one character at a
8347 time. Even some W32 programs do this - "dir" in a command
8348 shell on NT is very slow if we don't do this. */
8349 if (rc > 0)
8351 int wait = w32_pipe_read_delay;
8353 if (wait > 0)
8354 Sleep (wait);
8355 else if (wait < 0)
8356 while (++wait <= 0)
8357 /* Yield remainder of our time slice, effectively giving a
8358 temporary priority boost to the child process. */
8359 Sleep (0);
8362 else if (fd_info[fd].flags & FILE_SERIAL)
8364 HANDLE hnd = fd_info[fd].hnd;
8365 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8366 COMMTIMEOUTS ct;
8368 /* Configure timeouts for blocking read. */
8369 if (!GetCommTimeouts (hnd, &ct))
8371 cp->status = STATUS_READ_ERROR;
8372 return STATUS_READ_ERROR;
8374 ct.ReadIntervalTimeout = 0;
8375 ct.ReadTotalTimeoutMultiplier = 0;
8376 ct.ReadTotalTimeoutConstant = 0;
8377 if (!SetCommTimeouts (hnd, &ct))
8379 cp->status = STATUS_READ_ERROR;
8380 return STATUS_READ_ERROR;
8383 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
8385 if (GetLastError () != ERROR_IO_PENDING)
8387 cp->status = STATUS_READ_ERROR;
8388 return STATUS_READ_ERROR;
8390 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8392 cp->status = STATUS_READ_ERROR;
8393 return STATUS_READ_ERROR;
8397 else if (fd_info[fd].flags & FILE_SOCKET)
8399 unsigned long nblock = 0;
8400 /* We always want this to block, so temporarily disable NDELAY. */
8401 if (fd_info[fd].flags & FILE_NDELAY)
8402 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8404 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
8406 if (fd_info[fd].flags & FILE_NDELAY)
8408 nblock = 1;
8409 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8413 if (rc == sizeof (char))
8414 cp->status = STATUS_READ_SUCCEEDED;
8415 else
8416 cp->status = STATUS_READ_FAILED;
8418 return cp->status;
8422 _sys_wait_accept (int fd)
8424 HANDLE hEv;
8425 child_process * cp;
8426 int rc;
8428 if (fd < 0 || fd >= MAXDESC)
8429 return STATUS_READ_ERROR;
8431 cp = fd_info[fd].cp;
8433 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8434 return STATUS_READ_ERROR;
8436 cp->status = STATUS_READ_FAILED;
8438 hEv = pfn_WSACreateEvent ();
8439 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
8440 if (rc != SOCKET_ERROR)
8442 do {
8443 rc = WaitForSingleObject (hEv, 500);
8444 Sleep (5);
8445 } while (rc == WAIT_TIMEOUT
8446 && cp->status != STATUS_READ_ERROR
8447 && cp->char_avail);
8448 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8449 if (rc == WAIT_OBJECT_0)
8450 cp->status = STATUS_READ_SUCCEEDED;
8452 pfn_WSACloseEvent (hEv);
8454 return cp->status;
8458 _sys_wait_connect (int fd)
8460 HANDLE hEv;
8461 child_process * cp;
8462 int rc;
8464 if (fd < 0 || fd >= MAXDESC)
8465 return STATUS_READ_ERROR;
8467 cp = fd_info[fd].cp;
8468 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8469 return STATUS_READ_ERROR;
8471 cp->status = STATUS_READ_FAILED;
8473 hEv = pfn_WSACreateEvent ();
8474 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT);
8475 if (rc != SOCKET_ERROR)
8477 do {
8478 rc = WaitForSingleObject (hEv, 500);
8479 Sleep (5);
8480 } while (rc == WAIT_TIMEOUT
8481 && cp->status != STATUS_READ_ERROR
8482 && cp->char_avail);
8483 if (rc == WAIT_OBJECT_0)
8485 /* We've got an event, but it could be a successful
8486 connection, or it could be a failure. Find out
8487 which one is it. */
8488 WSANETWORKEVENTS events;
8490 pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events);
8491 if ((events.lNetworkEvents & FD_CONNECT) != 0
8492 && events.iErrorCode[FD_CONNECT_BIT])
8494 cp->status = STATUS_CONNECT_FAILED;
8495 cp->errcode = events.iErrorCode[FD_CONNECT_BIT];
8497 else
8499 cp->status = STATUS_READ_SUCCEEDED;
8500 cp->errcode = 0;
8503 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8505 else
8506 pfn_WSACloseEvent (hEv);
8508 return cp->status;
8512 sys_read (int fd, char * buffer, unsigned int count)
8514 int nchars;
8515 int to_read;
8516 DWORD waiting;
8517 char * orig_buffer = buffer;
8519 if (fd < 0)
8521 errno = EBADF;
8522 return -1;
8525 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8527 child_process *cp = fd_info[fd].cp;
8529 if ((fd_info[fd].flags & FILE_READ) == 0)
8531 errno = EBADF;
8532 return -1;
8535 nchars = 0;
8537 /* re-read CR carried over from last read */
8538 if (fd_info[fd].flags & FILE_LAST_CR)
8540 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
8541 *buffer++ = 0x0d;
8542 count--;
8543 nchars++;
8544 fd_info[fd].flags &= ~FILE_LAST_CR;
8547 /* presence of a child_process structure means we are operating in
8548 non-blocking mode - otherwise we just call _read directly.
8549 Note that the child_process structure might be missing because
8550 reap_subprocess has been called; in this case the pipe is
8551 already broken, so calling _read on it is okay. */
8552 if (cp)
8554 int current_status = cp->status;
8556 switch (current_status)
8558 case STATUS_READ_FAILED:
8559 case STATUS_READ_ERROR:
8560 /* report normal EOF if nothing in buffer */
8561 if (nchars <= 0)
8562 fd_info[fd].flags |= FILE_AT_EOF;
8563 return nchars;
8565 case STATUS_READ_READY:
8566 case STATUS_READ_IN_PROGRESS:
8567 #if 0
8568 /* This happens all the time during GnuTLS handshake
8569 with the remote, evidently because GnuTLS waits for
8570 the read to complete by retrying the read operation
8571 upon EAGAIN. So I'm disabling the DebPrint to avoid
8572 wasting cycles on something that is not a real
8573 problem. Enable if you need to debug something that
8574 bumps into this. */
8575 DebPrint (("sys_read called when read is in progress %d\n",
8576 current_status));
8577 #endif
8578 errno = EWOULDBLOCK;
8579 return -1;
8581 case STATUS_READ_SUCCEEDED:
8582 /* consume read-ahead char */
8583 *buffer++ = cp->chr;
8584 count--;
8585 nchars++;
8586 cp->status = STATUS_READ_ACKNOWLEDGED;
8587 ResetEvent (cp->char_avail);
8589 case STATUS_READ_ACKNOWLEDGED:
8590 case STATUS_CONNECT_FAILED:
8591 break;
8593 default:
8594 DebPrint (("sys_read: bad status %d\n", current_status));
8595 errno = EBADF;
8596 return -1;
8599 if (fd_info[fd].flags & FILE_PIPE)
8601 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
8602 to_read = min (waiting, (DWORD) count);
8604 if (to_read > 0)
8605 nchars += _read (fd, buffer, to_read);
8607 else if (fd_info[fd].flags & FILE_SERIAL)
8609 HANDLE hnd = fd_info[fd].hnd;
8610 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8611 int rc = 0;
8612 COMMTIMEOUTS ct;
8614 if (count > 0)
8616 /* Configure timeouts for non-blocking read. */
8617 if (!GetCommTimeouts (hnd, &ct))
8619 errno = EIO;
8620 return -1;
8622 ct.ReadIntervalTimeout = MAXDWORD;
8623 ct.ReadTotalTimeoutMultiplier = 0;
8624 ct.ReadTotalTimeoutConstant = 0;
8625 if (!SetCommTimeouts (hnd, &ct))
8627 errno = EIO;
8628 return -1;
8631 if (!ResetEvent (ovl->hEvent))
8633 errno = EIO;
8634 return -1;
8636 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8638 if (GetLastError () != ERROR_IO_PENDING)
8640 errno = EIO;
8641 return -1;
8643 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8645 errno = EIO;
8646 return -1;
8649 nchars += rc;
8652 else /* FILE_SOCKET */
8654 if (winsock_lib == NULL) emacs_abort ();
8656 /* When a non-blocking 'connect' call fails,
8657 wait_reading_process_output detects this by calling
8658 'getpeername', and then attempts to obtain the connection
8659 error code by trying to read 1 byte from the socket. If
8660 we try to serve that read by calling 'recv' below, the
8661 error we get is a generic WSAENOTCONN, not the actual
8662 connection error. So instead, we use the actual error
8663 code stashed by '_sys_wait_connect' in cp->errcode.
8664 Alternatively, we could have used 'getsockopt', like on
8665 GNU/Linux, but: (a) I have no idea whether the winsock
8666 version could hang, as it does "on some systems" (see the
8667 comment in process.c); and (b) 'getsockopt' on Windows is
8668 documented to clear the socket error for the entire
8669 process, which I'm not sure is TRT; FIXME. */
8670 if (current_status == STATUS_CONNECT_FAILED
8671 && (fd_info[fd].flags & FILE_CONNECT) != 0
8672 && cp->errcode != 0)
8674 pfn_WSASetLastError (cp->errcode);
8675 set_errno ();
8676 return -1;
8678 /* Do the equivalent of a non-blocking read. */
8679 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8680 if (waiting == 0 && nchars == 0)
8682 errno = EWOULDBLOCK;
8683 return -1;
8686 if (waiting)
8688 /* always use binary mode for sockets */
8689 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8690 if (res == SOCKET_ERROR)
8692 set_errno ();
8693 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8694 errno, SOCK_HANDLE (fd)));
8695 return -1;
8697 nchars += res;
8701 else
8703 int nread = _read (fd, buffer, count);
8704 if (nread >= 0)
8705 nchars += nread;
8706 else if (nchars == 0)
8707 nchars = nread;
8710 if (nchars <= 0)
8711 fd_info[fd].flags |= FILE_AT_EOF;
8712 /* Perform text mode translation if required. */
8713 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8715 nchars = crlf_to_lf (nchars, orig_buffer);
8716 /* If buffer contains only CR, return that. To be absolutely
8717 sure we should attempt to read the next char, but in
8718 practice a CR to be followed by LF would not appear by
8719 itself in the buffer. */
8720 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8722 fd_info[fd].flags |= FILE_LAST_CR;
8723 nchars--;
8727 else
8728 nchars = _read (fd, buffer, count);
8730 return nchars;
8733 /* From w32xfns.c */
8734 extern HANDLE interrupt_handle;
8737 sys_write (int fd, const void * buffer, unsigned int count)
8739 int nchars;
8740 USE_SAFE_ALLOCA;
8742 if (fd < 0)
8744 errno = EBADF;
8745 return -1;
8748 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8750 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8752 errno = EBADF;
8753 return -1;
8756 /* Perform text mode translation if required. */
8757 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8759 char * tmpbuf;
8760 const unsigned char * src = buffer;
8761 unsigned char * dst;
8762 int nbytes = count;
8764 SAFE_NALLOCA (tmpbuf, 2, count);
8765 dst = (unsigned char *)tmpbuf;
8767 while (1)
8769 unsigned char *next;
8770 /* Copy next line or remaining bytes. */
8771 next = _memccpy (dst, src, '\n', nbytes);
8772 if (next)
8774 /* Copied one line ending with '\n'. */
8775 int copied = next - dst;
8776 nbytes -= copied;
8777 src += copied;
8778 /* Insert '\r' before '\n'. */
8779 next[-1] = '\r';
8780 next[0] = '\n';
8781 dst = next + 1;
8782 count++;
8784 else
8785 /* Copied remaining partial line -> now finished. */
8786 break;
8788 buffer = tmpbuf;
8792 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8794 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8795 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8796 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8797 DWORD active = 0;
8799 /* This is async (a.k.a. "overlapped") I/O, so the return value
8800 of FALSE from WriteFile means either an error or the output
8801 will be completed asynchronously (ERROR_IO_PENDING). */
8802 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8804 if (GetLastError () != ERROR_IO_PENDING)
8806 errno = EIO;
8807 nchars = -1;
8809 else
8811 /* Wait for the write to complete, and watch C-g while
8812 at that. */
8813 if (detect_input_pending ())
8814 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
8815 INFINITE, QS_ALLINPUT);
8816 else
8817 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8818 switch (active)
8820 case WAIT_OBJECT_0:
8821 /* User pressed C-g, cancel write, then leave.
8822 Don't bother cleaning up as we may only get stuck
8823 in buggy drivers. */
8824 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8825 CancelIo (hnd);
8826 errno = EIO; /* Why not EINTR? */
8827 nchars = -1;
8828 break;
8829 case WAIT_OBJECT_0 + 1:
8830 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8832 errno = EIO;
8833 nchars = -1;
8835 break;
8840 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8842 unsigned long nblock = 0;
8843 if (winsock_lib == NULL) emacs_abort ();
8845 child_process *cp = fd_info[fd].cp;
8847 /* If this is a non-blocking socket whose connection is in
8848 progress or terminated with an error already, return the
8849 proper error code to the caller. */
8850 if (cp != NULL && (fd_info[fd].flags & FILE_CONNECT) != 0)
8852 /* In case connection is in progress, ENOTCONN that would
8853 result from calling pfn_send is not what callers expect. */
8854 if (cp->status != STATUS_CONNECT_FAILED)
8856 errno = EWOULDBLOCK;
8857 return -1;
8859 /* In case connection failed, use the actual error code
8860 stashed by '_sys_wait_connect' in cp->errcode. */
8861 else if (cp->errcode != 0)
8863 pfn_WSASetLastError (cp->errcode);
8864 set_errno ();
8865 return -1;
8869 /* TODO: implement select() properly so non-blocking I/O works. */
8870 /* For now, make sure the write blocks. */
8871 if (fd_info[fd].flags & FILE_NDELAY)
8872 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8874 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
8876 if (nchars == SOCKET_ERROR)
8878 set_errno ();
8879 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
8880 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8883 /* Set the socket back to non-blocking if it was before,
8884 for other operations that support it. */
8885 if (fd_info[fd].flags & FILE_NDELAY)
8887 nblock = 1;
8888 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8891 else
8893 /* Some networked filesystems don't like too large writes, so
8894 break them into smaller chunks. See the Comments section of
8895 the MSDN documentation of WriteFile for details behind the
8896 choice of the value of CHUNK below. See also the thread
8897 http://thread.gmane.org/gmane.comp.version-control.git/145294
8898 in the git mailing list. */
8899 const unsigned char *p = buffer;
8900 const bool is_pipe = (fd < MAXDESC
8901 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
8902 == (FILE_PIPE | FILE_NDELAY)));
8903 /* Some programs, notably Node.js's node.exe, seem to never
8904 completely empty the pipe, so writing more than the size of
8905 the pipe's buffer always returns ENOSPC, and we loop forever
8906 between send_process and here. As a workaround, write no
8907 more than the pipe's buffer can hold. */
8908 DWORD pipe_buffer_size;
8909 if (is_pipe)
8911 if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
8912 NULL, &pipe_buffer_size, NULL, NULL))
8914 DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
8915 pipe_buffer_size = 4096;
8918 const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
8920 nchars = 0;
8921 errno = 0;
8922 while (count > 0)
8924 unsigned this_chunk = count < chunk ? count : chunk;
8925 int n = _write (fd, p, this_chunk);
8927 if (n > 0)
8928 nchars += n;
8929 if (n < 0)
8931 /* When there's no buffer space in a pipe that is in the
8932 non-blocking mode, _write returns ENOSPC. We return
8933 EAGAIN instead, which should trigger the logic in
8934 send_process that enters waiting loop and calls
8935 wait_reading_process_output to allow process input to
8936 be accepted during the wait. Those calls to
8937 wait_reading_process_output allow sys_select to
8938 notice when process input becomes available, thus
8939 avoiding deadlock whereby each side of the pipe is
8940 blocked on write, waiting for the other party to read
8941 its end of the pipe. */
8942 if (errno == ENOSPC && is_pipe)
8943 errno = EAGAIN;
8944 if (nchars == 0)
8945 nchars = -1;
8946 break;
8948 else if (n < this_chunk)
8949 break;
8950 count -= n;
8951 p += n;
8955 SAFE_FREE ();
8956 return nchars;
8960 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
8962 /* Return information about network interface IFNAME, or about all
8963 interfaces (if IFNAME is nil). */
8964 static Lisp_Object
8965 network_interface_get_info (Lisp_Object ifname)
8967 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
8968 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
8969 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
8970 Lisp_Object res = Qnil;
8972 if (retval == ERROR_BUFFER_OVERFLOW)
8974 ainfo = xrealloc (ainfo, ainfo_len);
8975 retval = get_adapters_info (ainfo, &ainfo_len);
8978 if (retval == ERROR_SUCCESS)
8980 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
8981 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
8982 int if_num;
8983 struct sockaddr_in sa;
8985 /* For the below, we need some winsock functions, so make sure
8986 the winsock DLL is loaded. If we cannot successfully load
8987 it, they will have no use of the information we provide,
8988 anyway, so punt. */
8989 if (!winsock_lib && !init_winsock (1))
8990 goto done;
8992 for (adapter = ainfo; adapter; adapter = adapter->Next)
8994 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
8995 u_long ip_addr;
8996 /* Present Unix-compatible interface names, instead of the
8997 Windows names, which are really GUIDs not readable by
8998 humans. */
8999 static const char *ifmt[] = {
9000 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
9001 "lo", "ifx%d"
9003 enum {
9004 NONE = -1,
9005 ETHERNET = 0,
9006 TOKENRING = 1,
9007 FDDI = 2,
9008 PPP = 3,
9009 SLIP = 4,
9010 WLAN = 5,
9011 LOOPBACK = 6,
9012 OTHER_IF = 7
9013 } ifmt_idx;
9015 switch (adapter->Type)
9017 case MIB_IF_TYPE_ETHERNET:
9018 /* Windows before Vista reports wireless adapters as
9019 Ethernet. Work around by looking at the Description
9020 string. */
9021 if (strstr (adapter->Description, "Wireless "))
9023 ifmt_idx = WLAN;
9024 if_num = wlan_count++;
9026 else
9028 ifmt_idx = ETHERNET;
9029 if_num = eth_count++;
9031 break;
9032 case MIB_IF_TYPE_TOKENRING:
9033 ifmt_idx = TOKENRING;
9034 if_num = tr_count++;
9035 break;
9036 case MIB_IF_TYPE_FDDI:
9037 ifmt_idx = FDDI;
9038 if_num = fddi_count++;
9039 break;
9040 case MIB_IF_TYPE_PPP:
9041 ifmt_idx = PPP;
9042 if_num = ppp_count++;
9043 break;
9044 case MIB_IF_TYPE_SLIP:
9045 ifmt_idx = SLIP;
9046 if_num = sl_count++;
9047 break;
9048 case IF_TYPE_IEEE80211:
9049 ifmt_idx = WLAN;
9050 if_num = wlan_count++;
9051 break;
9052 case MIB_IF_TYPE_LOOPBACK:
9053 if (lo_count < 0)
9055 ifmt_idx = LOOPBACK;
9056 if_num = lo_count++;
9058 else
9059 ifmt_idx = NONE;
9060 break;
9061 default:
9062 ifmt_idx = OTHER_IF;
9063 if_num = ifx_count++;
9064 break;
9066 if (ifmt_idx == NONE)
9067 continue;
9068 sprintf (namebuf, ifmt[ifmt_idx], if_num);
9070 sa.sin_family = AF_INET;
9071 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
9072 if (ip_addr == INADDR_NONE)
9074 /* Bogus address, skip this interface. */
9075 continue;
9077 sa.sin_addr.s_addr = ip_addr;
9078 sa.sin_port = 0;
9079 if (NILP (ifname))
9080 res = Fcons (Fcons (build_string (namebuf),
9081 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9082 sizeof (struct sockaddr))),
9083 res);
9084 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
9086 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
9087 register struct Lisp_Vector *p = XVECTOR (hwaddr);
9088 Lisp_Object flags = Qnil;
9089 int n;
9090 u_long net_mask;
9092 /* Flags. We guess most of them by type, since the
9093 Windows flags are different and hard to get by. */
9094 flags = Fcons (intern ("up"), flags);
9095 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
9097 flags = Fcons (intern ("broadcast"), flags);
9098 flags = Fcons (intern ("multicast"), flags);
9100 flags = Fcons (intern ("running"), flags);
9101 if (ifmt_idx == PPP)
9103 flags = Fcons (intern ("pointopoint"), flags);
9104 flags = Fcons (intern ("noarp"), flags);
9106 if (adapter->HaveWins)
9107 flags = Fcons (intern ("WINS"), flags);
9108 if (adapter->DhcpEnabled)
9109 flags = Fcons (intern ("dynamic"), flags);
9111 res = Fcons (flags, res);
9113 /* Hardware address and its family. */
9114 for (n = 0; n < adapter->AddressLength; n++)
9115 p->contents[n] = make_number ((int) adapter->Address[n]);
9116 /* Windows does not support AF_LINK or AF_PACKET family
9117 of addresses. Use an arbitrary family number that is
9118 identical to what GNU/Linux returns. */
9119 res = Fcons (Fcons (make_number (1), hwaddr), res);
9121 /* Network mask. */
9122 sa.sin_family = AF_INET;
9123 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
9124 if (net_mask != INADDR_NONE)
9126 sa.sin_addr.s_addr = net_mask;
9127 sa.sin_port = 0;
9128 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9129 sizeof (struct sockaddr)),
9130 res);
9132 else
9133 res = Fcons (Qnil, res);
9135 sa.sin_family = AF_INET;
9136 if (ip_addr != INADDR_NONE)
9138 /* Broadcast address is only reported by
9139 GetAdaptersAddresses, which is of limited
9140 availability. Generate it on our own. */
9141 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
9143 sa.sin_addr.s_addr = bcast_addr;
9144 sa.sin_port = 0;
9145 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9146 sizeof (struct sockaddr)),
9147 res);
9149 /* IP address. */
9150 sa.sin_addr.s_addr = ip_addr;
9151 sa.sin_port = 0;
9152 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9153 sizeof (struct sockaddr)),
9154 res);
9156 else
9157 res = Fcons (Qnil, Fcons (Qnil, res));
9160 /* GetAdaptersInfo is documented to not report loopback
9161 interfaces, so we generate one out of thin air. */
9162 if (!lo_count)
9164 sa.sin_family = AF_INET;
9165 sa.sin_port = 0;
9166 if (NILP (ifname))
9168 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9169 res = Fcons (Fcons (build_string ("lo"),
9170 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9171 sizeof (struct sockaddr))),
9172 res);
9174 else if (strcmp (SSDATA (ifname), "lo") == 0)
9176 res = Fcons (Fcons (intern ("running"),
9177 Fcons (intern ("loopback"),
9178 Fcons (intern ("up"), Qnil))), Qnil);
9179 /* 772 is what 3 different GNU/Linux systems report for
9180 the loopback interface. */
9181 res = Fcons (Fcons (make_number (772),
9182 Fmake_vector (make_number (6),
9183 make_number (0))),
9184 res);
9185 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
9186 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9187 sizeof (struct sockaddr)),
9188 res);
9189 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
9190 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9191 sizeof (struct sockaddr)),
9192 res);
9193 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9194 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9195 sizeof (struct sockaddr)),
9196 res);
9202 done:
9203 xfree (ainfo);
9204 return res;
9207 Lisp_Object
9208 network_interface_list (void)
9210 return network_interface_get_info (Qnil);
9213 Lisp_Object
9214 network_interface_info (Lisp_Object ifname)
9216 CHECK_STRING (ifname);
9217 return network_interface_get_info (ifname);
9221 /* The Windows CRT functions are "optimized for speed", so they don't
9222 check for timezone and DST changes if they were last called less
9223 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
9224 all Emacs features that repeatedly call time functions (e.g.,
9225 display-time) are in real danger of missing timezone and DST
9226 changes. Calling tzset before each localtime call fixes that. */
9227 struct tm *
9228 sys_localtime (const time_t *t)
9230 tzset ();
9231 return localtime (t);
9236 /* Try loading LIBRARY_ID from the file(s) specified in
9237 Vdynamic_library_alist. If the library is loaded successfully,
9238 return the handle of the DLL, and record the filename in the
9239 property :loaded-from of LIBRARY_ID. If the library could not be
9240 found, or when it was already loaded (because the handle is not
9241 recorded anywhere, and so is lost after use), return NULL.
9243 We could also save the handle in :loaded-from, but currently
9244 there's no use case for it. */
9245 HMODULE
9246 w32_delayed_load (Lisp_Object library_id)
9248 HMODULE dll_handle = NULL;
9250 CHECK_SYMBOL (library_id);
9252 if (CONSP (Vdynamic_library_alist)
9253 && NILP (Fassq (library_id, Vlibrary_cache)))
9255 Lisp_Object found = Qnil;
9256 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
9258 if (CONSP (dlls))
9259 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
9261 Lisp_Object dll = XCAR (dlls);
9262 char name[MAX_UTF8_PATH];
9263 DWORD res = -1;
9265 CHECK_STRING (dll);
9266 dll = ENCODE_FILE (dll);
9267 if (w32_unicode_filenames)
9269 wchar_t name_w[MAX_PATH];
9271 filename_to_utf16 (SSDATA (dll), name_w);
9272 dll_handle = LoadLibraryW (name_w);
9273 if (dll_handle)
9275 res = GetModuleFileNameW (dll_handle, name_w,
9276 sizeof (name_w));
9277 if (res > 0)
9278 filename_from_utf16 (name_w, name);
9281 else
9283 char name_a[MAX_PATH];
9285 filename_to_ansi (SSDATA (dll), name_a);
9286 dll_handle = LoadLibraryA (name_a);
9287 if (dll_handle)
9289 res = GetModuleFileNameA (dll_handle, name_a,
9290 sizeof (name_a));
9291 if (res > 0)
9292 filename_from_ansi (name_a, name);
9295 if (dll_handle)
9297 ptrdiff_t len = strlen (name);
9298 found = Fcons (dll,
9299 (res > 0)
9300 /* Possibly truncated */
9301 ? make_specified_string (name, -1, len, 1)
9302 : Qnil);
9303 /* This prevents thread start and end notifications
9304 from being sent to the DLL, for every thread we
9305 start. We don't need those notifications because
9306 threads we create never use any of these DLLs, only
9307 the main thread uses them. This is supposed to
9308 speed up thread creation. */
9309 DisableThreadLibraryCalls (dll_handle);
9310 break;
9314 Fput (library_id, QCloaded_from, found);
9317 return dll_handle;
9321 void
9322 check_windows_init_file (void)
9324 /* A common indication that Emacs is not installed properly is when
9325 it cannot find the Windows installation file. If this file does
9326 not exist in the expected place, tell the user. */
9328 if (!noninteractive && !inhibit_window_system
9329 /* Vload_path is not yet initialized when we are loading
9330 loadup.el. */
9331 && NILP (Vpurify_flag))
9333 Lisp_Object init_file;
9334 int fd;
9336 /* Implementation note: this function runs early during Emacs
9337 startup, before startup.el is run. So Vload_path is still in
9338 its initial unibyte form, but it holds UTF-8 encoded file
9339 names, since init_callproc was already called. So we do not
9340 need to ENCODE_FILE here, but we do need to convert the file
9341 names from UTF-8 to ANSI. */
9342 init_file = build_string ("term/w32-win");
9343 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
9344 if (fd < 0)
9346 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
9347 char *init_file_name = SSDATA (init_file);
9348 char *load_path = SSDATA (load_path_print);
9349 char *buffer = alloca (1024
9350 + strlen (init_file_name)
9351 + strlen (load_path));
9352 char *msg = buffer;
9353 int needed;
9355 sprintf (buffer,
9356 "The Emacs Windows initialization file \"%s.el\" "
9357 "could not be found in your Emacs installation. "
9358 "Emacs checked the following directories for this file:\n"
9359 "\n%s\n\n"
9360 "When Emacs cannot find this file, it usually means that it "
9361 "was not installed properly, or its distribution file was "
9362 "not unpacked properly.\nSee the README.W32 file in the "
9363 "top-level Emacs directory for more information.",
9364 init_file_name, load_path);
9365 needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
9366 buffer, -1, NULL, 0);
9367 if (needed > 0)
9369 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
9371 pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
9372 -1, msg_w, needed);
9373 needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
9374 NULL, 0, NULL, NULL);
9375 if (needed > 0)
9377 char *msg_a = alloca (needed + 1);
9379 pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
9380 NULL, NULL);
9381 msg = msg_a;
9384 MessageBox (NULL,
9385 msg,
9386 "Emacs Abort Dialog",
9387 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
9388 /* Use the low-level system abort. */
9389 abort ();
9391 else
9393 _close (fd);
9398 void
9399 term_ntproc (int ignored)
9401 (void)ignored;
9403 term_timers ();
9405 /* shutdown the socket interface if necessary */
9406 term_winsock ();
9408 term_w32select ();
9411 void
9412 init_ntproc (int dumping)
9414 sigset_t initial_mask = 0;
9416 /* Initialize the socket interface now if available and requested by
9417 the user by defining PRELOAD_WINSOCK; otherwise loading will be
9418 delayed until open-network-stream is called (w32-has-winsock can
9419 also be used to dynamically load or reload winsock).
9421 Conveniently, init_environment is called before us, so
9422 PRELOAD_WINSOCK can be set in the registry. */
9424 /* Always initialize this correctly. */
9425 winsock_lib = NULL;
9427 if (getenv ("PRELOAD_WINSOCK") != NULL)
9428 init_winsock (TRUE);
9430 /* Initial preparation for subprocess support: replace our standard
9431 handles with non-inheritable versions. */
9433 HANDLE parent;
9434 HANDLE stdin_save = INVALID_HANDLE_VALUE;
9435 HANDLE stdout_save = INVALID_HANDLE_VALUE;
9436 HANDLE stderr_save = INVALID_HANDLE_VALUE;
9438 parent = GetCurrentProcess ();
9440 /* ignore errors when duplicating and closing; typically the
9441 handles will be invalid when running as a gui program. */
9442 DuplicateHandle (parent,
9443 GetStdHandle (STD_INPUT_HANDLE),
9444 parent,
9445 &stdin_save,
9447 FALSE,
9448 DUPLICATE_SAME_ACCESS);
9450 DuplicateHandle (parent,
9451 GetStdHandle (STD_OUTPUT_HANDLE),
9452 parent,
9453 &stdout_save,
9455 FALSE,
9456 DUPLICATE_SAME_ACCESS);
9458 DuplicateHandle (parent,
9459 GetStdHandle (STD_ERROR_HANDLE),
9460 parent,
9461 &stderr_save,
9463 FALSE,
9464 DUPLICATE_SAME_ACCESS);
9466 fclose (stdin);
9467 fclose (stdout);
9468 fclose (stderr);
9470 if (stdin_save != INVALID_HANDLE_VALUE)
9471 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
9472 else
9473 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
9474 _fdopen (0, "r");
9476 if (stdout_save != INVALID_HANDLE_VALUE)
9477 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
9478 else
9479 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9480 _fdopen (1, "w");
9482 if (stderr_save != INVALID_HANDLE_VALUE)
9483 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
9484 else
9485 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9486 _fdopen (2, "w");
9489 /* unfortunately, atexit depends on implementation of malloc */
9490 /* atexit (term_ntproc); */
9491 if (!dumping)
9493 /* Make sure we start with all signals unblocked. */
9494 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
9495 signal (SIGABRT, term_ntproc);
9497 init_timers ();
9499 /* determine which drives are fixed, for GetCachedVolumeInformation */
9501 /* GetDriveType must have trailing backslash. */
9502 char drive[] = "A:\\";
9504 /* Loop over all possible drive letters */
9505 while (*drive <= 'Z')
9507 /* Record if this drive letter refers to a fixed drive. */
9508 fixed_drives[DRIVE_INDEX (*drive)] =
9509 (GetDriveType (drive) == DRIVE_FIXED);
9511 (*drive)++;
9514 /* Reset the volume info cache. */
9515 volume_cache = NULL;
9520 shutdown_handler ensures that buffers' autosave files are
9521 up to date when the user logs off, or the system shuts down.
9523 static BOOL WINAPI
9524 shutdown_handler (DWORD type)
9526 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
9527 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
9528 || type == CTRL_LOGOFF_EVENT /* User logs off. */
9529 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
9531 /* Shut down cleanly, making sure autosave files are up to date. */
9532 shut_down_emacs (0, Qnil);
9535 /* Allow other handlers to handle this signal. */
9536 return FALSE;
9539 /* On Windows 9X, load UNICOWS.DLL and return its handle, or die. On
9540 NT, return a handle to GDI32.DLL. */
9541 HANDLE
9542 maybe_load_unicows_dll (void)
9544 if (os_subtype == OS_9X)
9546 HANDLE ret = LoadLibrary ("Unicows.dll");
9547 if (ret)
9549 /* These two functions are present on Windows 9X as stubs
9550 that always fail. We need the real implementations from
9551 UNICOWS.DLL, so we must call these functions through
9552 pointers, and assign the correct addresses to these
9553 pointers at program startup (see emacs.c, which calls
9554 this function early on). */
9555 pMultiByteToWideChar =
9556 (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
9557 pWideCharToMultiByte =
9558 (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
9559 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9560 return ret;
9562 else
9564 int button;
9566 button = MessageBox (NULL,
9567 "Emacs cannot load the UNICOWS.DLL library.\n"
9568 "This library is essential for using Emacs\n"
9569 "on this system. You need to install it.\n\n"
9570 "Emacs will exit when you click OK.",
9571 "Emacs cannot load UNICOWS.DLL",
9572 MB_ICONERROR | MB_TASKMODAL
9573 | MB_SETFOREGROUND | MB_OK);
9574 switch (button)
9576 case IDOK:
9577 default:
9578 exit (1);
9582 else
9584 /* On NT family of Windows, these two functions are always
9585 linked in, so we just assign their addresses to the 2
9586 pointers; no need for the LoadLibrary dance. */
9587 pMultiByteToWideChar = MultiByteToWideChar;
9588 pWideCharToMultiByte = WideCharToMultiByte;
9589 /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported. */
9590 if (w32_major_version < 5)
9591 multiByteToWideCharFlags = 0;
9592 else
9593 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9594 return LoadLibrary ("Gdi32.dll");
9599 globals_of_w32 is used to initialize those global variables that
9600 must always be initialized on startup even when the global variable
9601 initialized is non zero (see the function main in emacs.c).
9603 void
9604 globals_of_w32 (void)
9606 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
9608 get_process_times_fn = (GetProcessTimes_Proc)
9609 GetProcAddress (kernel32, "GetProcessTimes");
9611 DEFSYM (QCloaded_from, ":loaded-from");
9613 g_b_init_is_windows_9x = 0;
9614 g_b_init_open_process_token = 0;
9615 g_b_init_get_token_information = 0;
9616 g_b_init_lookup_account_sid = 0;
9617 g_b_init_get_sid_sub_authority = 0;
9618 g_b_init_get_sid_sub_authority_count = 0;
9619 g_b_init_get_security_info = 0;
9620 g_b_init_get_file_security_w = 0;
9621 g_b_init_get_file_security_a = 0;
9622 g_b_init_get_security_descriptor_owner = 0;
9623 g_b_init_get_security_descriptor_group = 0;
9624 g_b_init_is_valid_sid = 0;
9625 g_b_init_create_toolhelp32_snapshot = 0;
9626 g_b_init_process32_first = 0;
9627 g_b_init_process32_next = 0;
9628 g_b_init_open_thread_token = 0;
9629 g_b_init_impersonate_self = 0;
9630 g_b_init_revert_to_self = 0;
9631 g_b_init_get_process_memory_info = 0;
9632 g_b_init_get_process_working_set_size = 0;
9633 g_b_init_global_memory_status = 0;
9634 g_b_init_global_memory_status_ex = 0;
9635 g_b_init_equal_sid = 0;
9636 g_b_init_copy_sid = 0;
9637 g_b_init_get_length_sid = 0;
9638 g_b_init_get_native_system_info = 0;
9639 g_b_init_get_system_times = 0;
9640 g_b_init_create_symbolic_link_w = 0;
9641 g_b_init_create_symbolic_link_a = 0;
9642 g_b_init_get_security_descriptor_dacl = 0;
9643 g_b_init_convert_sd_to_sddl = 0;
9644 g_b_init_convert_sddl_to_sd = 0;
9645 g_b_init_is_valid_security_descriptor = 0;
9646 g_b_init_set_file_security_w = 0;
9647 g_b_init_set_file_security_a = 0;
9648 g_b_init_set_named_security_info_w = 0;
9649 g_b_init_set_named_security_info_a = 0;
9650 g_b_init_get_adapters_info = 0;
9651 g_b_init_compare_string_w = 0;
9652 g_b_init_debug_break_process = 0;
9653 num_of_processors = 0;
9654 /* The following sets a handler for shutdown notifications for
9655 console apps. This actually applies to Emacs in both console and
9656 GUI modes, since we had to fool windows into thinking emacs is a
9657 console application to get console mode to work. */
9658 SetConsoleCtrlHandler (shutdown_handler, TRUE);
9660 /* "None" is the default group name on standalone workstations. */
9661 strcpy (dflt_group_name, "None");
9663 /* Reset, in case it has some value inherited from dump time. */
9664 w32_stat_get_owner_group = 0;
9666 /* If w32_unicode_filenames is non-zero, we will be using Unicode
9667 (a.k.a. "wide") APIs to invoke functions that accept file
9668 names. */
9669 if (is_windows_9x ())
9670 w32_unicode_filenames = 0;
9671 else
9672 w32_unicode_filenames = 1;
9674 #ifdef HAVE_MODULES
9675 dynlib_reset_last_error ();
9676 #endif
9678 w32_crypto_hprov = (HCRYPTPROV)0;
9681 /* For make-serial-process */
9683 serial_open (Lisp_Object port_obj)
9685 char *port = SSDATA (port_obj);
9686 HANDLE hnd;
9687 child_process *cp;
9688 int fd = -1;
9690 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
9691 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
9692 if (hnd == INVALID_HANDLE_VALUE)
9693 error ("Could not open %s", port);
9694 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
9695 if (fd == -1)
9696 error ("Could not open %s", port);
9698 cp = new_child ();
9699 if (!cp)
9700 error ("Could not create child process");
9701 cp->fd = fd;
9702 cp->status = STATUS_READ_ACKNOWLEDGED;
9703 fd_info[ fd ].hnd = hnd;
9704 fd_info[ fd ].flags |=
9705 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
9706 if (fd_info[ fd ].cp != NULL)
9708 error ("fd_info[fd = %d] is already in use", fd);
9710 fd_info[ fd ].cp = cp;
9711 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9712 if (cp->ovl_read.hEvent == NULL)
9713 error ("Could not create read event");
9714 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9715 if (cp->ovl_write.hEvent == NULL)
9716 error ("Could not create write event");
9718 return fd;
9721 /* For serial-process-configure */
9722 void
9723 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
9725 Lisp_Object childp2 = Qnil;
9726 Lisp_Object tem = Qnil;
9727 HANDLE hnd;
9728 DCB dcb;
9729 COMMTIMEOUTS ct;
9730 char summary[4] = "???"; /* This usually becomes "8N1". */
9732 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
9733 error ("Not a serial process");
9734 hnd = fd_info[ p->outfd ].hnd;
9736 childp2 = Fcopy_sequence (p->childp);
9738 /* Initialize timeouts for blocking read and blocking write. */
9739 if (!GetCommTimeouts (hnd, &ct))
9740 error ("GetCommTimeouts() failed");
9741 ct.ReadIntervalTimeout = 0;
9742 ct.ReadTotalTimeoutMultiplier = 0;
9743 ct.ReadTotalTimeoutConstant = 0;
9744 ct.WriteTotalTimeoutMultiplier = 0;
9745 ct.WriteTotalTimeoutConstant = 0;
9746 if (!SetCommTimeouts (hnd, &ct))
9747 error ("SetCommTimeouts() failed");
9748 /* Read port attributes and prepare default configuration. */
9749 memset (&dcb, 0, sizeof (dcb));
9750 dcb.DCBlength = sizeof (DCB);
9751 if (!GetCommState (hnd, &dcb))
9752 error ("GetCommState() failed");
9753 dcb.fBinary = TRUE;
9754 dcb.fNull = FALSE;
9755 dcb.fAbortOnError = FALSE;
9756 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
9757 dcb.ErrorChar = 0;
9758 dcb.EofChar = 0;
9759 dcb.EvtChar = 0;
9761 /* Configure speed. */
9762 if (!NILP (Fplist_member (contact, QCspeed)))
9763 tem = Fplist_get (contact, QCspeed);
9764 else
9765 tem = Fplist_get (p->childp, QCspeed);
9766 CHECK_NUMBER (tem);
9767 dcb.BaudRate = XINT (tem);
9768 childp2 = Fplist_put (childp2, QCspeed, tem);
9770 /* Configure bytesize. */
9771 if (!NILP (Fplist_member (contact, QCbytesize)))
9772 tem = Fplist_get (contact, QCbytesize);
9773 else
9774 tem = Fplist_get (p->childp, QCbytesize);
9775 if (NILP (tem))
9776 tem = make_number (8);
9777 CHECK_NUMBER (tem);
9778 if (XINT (tem) != 7 && XINT (tem) != 8)
9779 error (":bytesize must be nil (8), 7, or 8");
9780 dcb.ByteSize = XINT (tem);
9781 summary[0] = XINT (tem) + '0';
9782 childp2 = Fplist_put (childp2, QCbytesize, tem);
9784 /* Configure parity. */
9785 if (!NILP (Fplist_member (contact, QCparity)))
9786 tem = Fplist_get (contact, QCparity);
9787 else
9788 tem = Fplist_get (p->childp, QCparity);
9789 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
9790 error (":parity must be nil (no parity), `even', or `odd'");
9791 dcb.fParity = FALSE;
9792 dcb.Parity = NOPARITY;
9793 dcb.fErrorChar = FALSE;
9794 if (NILP (tem))
9796 summary[1] = 'N';
9798 else if (EQ (tem, Qeven))
9800 summary[1] = 'E';
9801 dcb.fParity = TRUE;
9802 dcb.Parity = EVENPARITY;
9803 dcb.fErrorChar = TRUE;
9805 else if (EQ (tem, Qodd))
9807 summary[1] = 'O';
9808 dcb.fParity = TRUE;
9809 dcb.Parity = ODDPARITY;
9810 dcb.fErrorChar = TRUE;
9812 childp2 = Fplist_put (childp2, QCparity, tem);
9814 /* Configure stopbits. */
9815 if (!NILP (Fplist_member (contact, QCstopbits)))
9816 tem = Fplist_get (contact, QCstopbits);
9817 else
9818 tem = Fplist_get (p->childp, QCstopbits);
9819 if (NILP (tem))
9820 tem = make_number (1);
9821 CHECK_NUMBER (tem);
9822 if (XINT (tem) != 1 && XINT (tem) != 2)
9823 error (":stopbits must be nil (1 stopbit), 1, or 2");
9824 summary[2] = XINT (tem) + '0';
9825 if (XINT (tem) == 1)
9826 dcb.StopBits = ONESTOPBIT;
9827 else if (XINT (tem) == 2)
9828 dcb.StopBits = TWOSTOPBITS;
9829 childp2 = Fplist_put (childp2, QCstopbits, tem);
9831 /* Configure flowcontrol. */
9832 if (!NILP (Fplist_member (contact, QCflowcontrol)))
9833 tem = Fplist_get (contact, QCflowcontrol);
9834 else
9835 tem = Fplist_get (p->childp, QCflowcontrol);
9836 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
9837 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
9838 dcb.fOutxCtsFlow = FALSE;
9839 dcb.fOutxDsrFlow = FALSE;
9840 dcb.fDtrControl = DTR_CONTROL_DISABLE;
9841 dcb.fDsrSensitivity = FALSE;
9842 dcb.fTXContinueOnXoff = FALSE;
9843 dcb.fOutX = FALSE;
9844 dcb.fInX = FALSE;
9845 dcb.fRtsControl = RTS_CONTROL_DISABLE;
9846 dcb.XonChar = 17; /* Control-Q */
9847 dcb.XoffChar = 19; /* Control-S */
9848 if (NILP (tem))
9850 /* Already configured. */
9852 else if (EQ (tem, Qhw))
9854 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
9855 dcb.fOutxCtsFlow = TRUE;
9857 else if (EQ (tem, Qsw))
9859 dcb.fOutX = TRUE;
9860 dcb.fInX = TRUE;
9862 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
9864 /* Activate configuration. */
9865 if (!SetCommState (hnd, &dcb))
9866 error ("SetCommState() failed");
9868 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
9869 pset_childp (p, childp2);
9872 /* For make-pipe-process */
9873 void
9874 register_aux_fd (int infd)
9876 child_process *cp;
9878 cp = new_child ();
9879 if (!cp)
9880 error ("Could not create child process");
9881 cp->fd = infd;
9882 cp->status = STATUS_READ_ACKNOWLEDGED;
9884 if (fd_info[ infd ].cp != NULL)
9886 error ("fd_info[fd = %d] is already in use", infd);
9888 fd_info[ infd ].cp = cp;
9889 fd_info[ infd ].hnd = (HANDLE) _get_osfhandle (infd);
9892 #ifdef HAVE_GNUTLS
9894 ssize_t
9895 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
9897 int n, err;
9898 struct Lisp_Process *process = (struct Lisp_Process *)p;
9899 int fd = process->infd;
9901 n = sys_read (fd, (char*)buf, sz);
9903 if (n >= 0)
9904 return n;
9906 err = errno;
9908 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9909 if (err == EWOULDBLOCK)
9910 err = EAGAIN;
9912 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
9914 return -1;
9917 ssize_t
9918 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
9920 struct Lisp_Process *process = (struct Lisp_Process *)p;
9921 int fd = process->outfd;
9922 ssize_t n = sys_write (fd, buf, sz);
9924 /* 0 or more bytes written means everything went fine. */
9925 if (n >= 0)
9926 return n;
9928 /* Negative bytes written means we got an error in errno.
9929 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9930 emacs_gnutls_transport_set_errno (process->gnutls_state,
9931 errno == EWOULDBLOCK ? EAGAIN : errno);
9933 return -1;
9935 #endif /* HAVE_GNUTLS */
9937 /* end of w32.c */