; Merge from origin/emacs-25
[emacs.git] / src / w32.c
blob71a38b91946d94ca8f94fb4cf165d21059d90360
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 #include <mingw_time.h>
25 #include <stddef.h> /* for offsetof */
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <float.h> /* for DBL_EPSILON */
29 #include <io.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <ctype.h>
33 #include <signal.h>
34 #include <sys/file.h>
35 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
36 #include <sys/time.h>
37 #include <sys/utime.h>
38 #include <math.h>
40 /* must include CRT headers *before* config.h */
42 #include <config.h>
43 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
45 #undef access
46 #undef chdir
47 #undef chmod
48 #undef creat
49 #undef ctime
50 #undef fopen
51 #undef link
52 #undef mkdir
53 #undef open
54 #undef rename
55 #undef rmdir
56 #undef unlink
58 #undef close
59 #undef dup
60 #undef dup2
61 #undef pipe
62 #undef read
63 #undef write
65 #undef strerror
67 #undef localtime
69 char *sys_ctime (const time_t *);
70 int sys_chdir (const char *);
71 int sys_creat (const char *, int);
72 FILE *sys_fopen (const char *, const char *);
73 int sys_mkdir (const char *);
74 int sys_open (const char *, int, int);
75 int sys_rename (char const *, char const *);
76 int sys_rmdir (const char *);
77 int sys_close (int);
78 int sys_dup2 (int, int);
79 int sys_read (int, char *, unsigned int);
80 int sys_write (int, const void *, unsigned int);
81 struct tm *sys_localtime (const time_t *);
83 #ifdef HAVE_MODULES
84 extern void dynlib_reset_last_error (void);
85 #endif
87 #include "lisp.h"
88 #include "epaths.h" /* for PATH_EXEC */
90 #include <pwd.h>
91 #include <grp.h>
93 /* MinGW64 defines these in its _mingw.h. */
94 #ifndef _ANONYMOUS_UNION
95 # define _ANONYMOUS_UNION
96 #endif
97 #ifndef _ANONYMOUS_STRUCT
98 # define _ANONYMOUS_STRUCT
99 #endif
100 #include <windows.h>
101 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
102 use a different name to avoid compilation problems. */
103 typedef struct _MEMORY_STATUS_EX {
104 DWORD dwLength;
105 DWORD dwMemoryLoad;
106 DWORDLONG ullTotalPhys;
107 DWORDLONG ullAvailPhys;
108 DWORDLONG ullTotalPageFile;
109 DWORDLONG ullAvailPageFile;
110 DWORDLONG ullTotalVirtual;
111 DWORDLONG ullAvailVirtual;
112 DWORDLONG ullAvailExtendedVirtual;
113 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
115 /* These are here so that GDB would know about these data types. This
116 allows attaching GDB to Emacs when a fatal exception is triggered
117 and Windows pops up the "application needs to be closed" dialog.
118 At that point, _gnu_exception_handler, the top-level exception
119 handler installed by the MinGW startup code, is somewhere on the
120 call-stack of the main thread, so going to that call frame and
121 looking at the argument to _gnu_exception_handler, which is a
122 PEXCEPTION_POINTERS pointer, can reveal the exception code
123 (excptr->ExceptionRecord->ExceptionCode) and the address where the
124 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
125 well as some additional information specific to the exception. */
126 PEXCEPTION_POINTERS excptr;
127 PEXCEPTION_RECORD excprec;
128 PCONTEXT ctxrec;
130 #include <lmcons.h>
131 #include <shlobj.h>
133 #include <tlhelp32.h>
134 #include <psapi.h>
135 #ifndef _MSC_VER
136 #include <w32api.h>
137 #endif
138 #if _WIN32_WINNT < 0x0500
139 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
140 /* This either is not in psapi.h or guarded by higher value of
141 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
142 defines it in psapi.h */
143 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
144 DWORD cb;
145 DWORD PageFaultCount;
146 SIZE_T PeakWorkingSetSize;
147 SIZE_T WorkingSetSize;
148 SIZE_T QuotaPeakPagedPoolUsage;
149 SIZE_T QuotaPagedPoolUsage;
150 SIZE_T QuotaPeakNonPagedPoolUsage;
151 SIZE_T QuotaNonPagedPoolUsage;
152 SIZE_T PagefileUsage;
153 SIZE_T PeakPagefileUsage;
154 SIZE_T PrivateUsage;
155 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
156 #endif
157 #endif
159 #include <winioctl.h>
160 #include <aclapi.h>
161 #include <sddl.h>
163 #include <sys/acl.h>
164 #include <acl.h>
166 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
167 define them by hand if not already defined. */
168 #ifndef SDDL_REVISION_1
169 #define SDDL_REVISION_1 1
170 #endif /* SDDL_REVISION_1 */
172 #if defined(_MSC_VER) || defined(MINGW_W64)
173 /* MSVC and MinGW64 don't provide the definition of
174 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
175 which cannot be included because it triggers conflicts with other
176 Windows API headers. So we define it here by hand. */
178 typedef struct _REPARSE_DATA_BUFFER {
179 ULONG ReparseTag;
180 USHORT ReparseDataLength;
181 USHORT Reserved;
182 union {
183 struct {
184 USHORT SubstituteNameOffset;
185 USHORT SubstituteNameLength;
186 USHORT PrintNameOffset;
187 USHORT PrintNameLength;
188 ULONG Flags;
189 WCHAR PathBuffer[1];
190 } SymbolicLinkReparseBuffer;
191 struct {
192 USHORT SubstituteNameOffset;
193 USHORT SubstituteNameLength;
194 USHORT PrintNameOffset;
195 USHORT PrintNameLength;
196 WCHAR PathBuffer[1];
197 } MountPointReparseBuffer;
198 struct {
199 UCHAR DataBuffer[1];
200 } GenericReparseBuffer;
201 } DUMMYUNIONNAME;
202 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
204 #ifndef FILE_DEVICE_FILE_SYSTEM
205 #define FILE_DEVICE_FILE_SYSTEM 9
206 #endif
207 #ifndef METHOD_BUFFERED
208 #define METHOD_BUFFERED 0
209 #endif
210 #ifndef FILE_ANY_ACCESS
211 #define FILE_ANY_ACCESS 0x00000000
212 #endif
213 #ifndef CTL_CODE
214 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
215 #endif
216 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
217 #ifndef FSCTL_GET_REPARSE_POINT
218 #define FSCTL_GET_REPARSE_POINT \
219 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
220 #endif
221 #endif
223 /* TCP connection support. */
224 #include <sys/socket.h>
225 #undef socket
226 #undef bind
227 #undef connect
228 #undef htons
229 #undef ntohs
230 #undef inet_addr
231 #undef gethostname
232 #undef gethostbyname
233 #undef getservbyname
234 #undef getpeername
235 #undef shutdown
236 #undef setsockopt
237 #undef listen
238 #undef getsockname
239 #undef accept
240 #undef recvfrom
241 #undef sendto
243 #include <iphlpapi.h> /* should be after winsock2.h */
245 #include <wincrypt.h>
247 #include <c-strcase.h>
248 #include <utimens.h> /* for fdutimens */
250 #include "w32.h"
251 #include <dirent.h>
252 #include "w32common.h"
253 #include "w32select.h"
254 #include "systime.h" /* for current_timespec, struct timespec */
255 #include "dispextern.h" /* for xstrcasecmp */
256 #include "coding.h" /* for Vlocale_coding_system */
258 #include "careadlinkat.h"
259 #include "allocator.h"
261 /* For Lisp_Process, serial_configure and serial_open. */
262 #include "process.h"
263 #include "systty.h"
265 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
266 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
268 static DWORD get_rid (PSID);
269 static int is_symlink (const char *);
270 static char * chase_symlinks (const char *);
271 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
272 static int restore_privilege (TOKEN_PRIVILEGES *);
273 static BOOL WINAPI revert_to_self (void);
275 static int sys_access (const char *, int);
276 extern void *e_malloc (size_t);
277 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
278 struct timespec *, void *);
279 extern int sys_dup (int);
284 /* Initialization states.
286 WARNING: If you add any more such variables for additional APIs,
287 you MUST add initialization for them to globals_of_w32
288 below. This is because these variables might get set
289 to non-NULL values during dumping, but the dumped Emacs
290 cannot reuse those values, because it could be run on a
291 different version of the OS, where API addresses are
292 different. */
293 static BOOL g_b_init_is_windows_9x;
294 static BOOL g_b_init_open_process_token;
295 static BOOL g_b_init_get_token_information;
296 static BOOL g_b_init_lookup_account_sid;
297 static BOOL g_b_init_get_sid_sub_authority;
298 static BOOL g_b_init_get_sid_sub_authority_count;
299 static BOOL g_b_init_get_security_info;
300 static BOOL g_b_init_get_file_security_w;
301 static BOOL g_b_init_get_file_security_a;
302 static BOOL g_b_init_get_security_descriptor_owner;
303 static BOOL g_b_init_get_security_descriptor_group;
304 static BOOL g_b_init_is_valid_sid;
305 static BOOL g_b_init_create_toolhelp32_snapshot;
306 static BOOL g_b_init_process32_first;
307 static BOOL g_b_init_process32_next;
308 static BOOL g_b_init_open_thread_token;
309 static BOOL g_b_init_impersonate_self;
310 static BOOL g_b_init_revert_to_self;
311 static BOOL g_b_init_get_process_memory_info;
312 static BOOL g_b_init_get_process_working_set_size;
313 static BOOL g_b_init_global_memory_status;
314 static BOOL g_b_init_global_memory_status_ex;
315 static BOOL g_b_init_get_length_sid;
316 static BOOL g_b_init_equal_sid;
317 static BOOL g_b_init_copy_sid;
318 static BOOL g_b_init_get_native_system_info;
319 static BOOL g_b_init_get_system_times;
320 static BOOL g_b_init_create_symbolic_link_w;
321 static BOOL g_b_init_create_symbolic_link_a;
322 static BOOL g_b_init_get_security_descriptor_dacl;
323 static BOOL g_b_init_convert_sd_to_sddl;
324 static BOOL g_b_init_convert_sddl_to_sd;
325 static BOOL g_b_init_is_valid_security_descriptor;
326 static BOOL g_b_init_set_file_security_w;
327 static BOOL g_b_init_set_file_security_a;
328 static BOOL g_b_init_set_named_security_info_w;
329 static BOOL g_b_init_set_named_security_info_a;
330 static BOOL g_b_init_get_adapters_info;
332 BOOL g_b_init_compare_string_w;
335 BEGIN: Wrapper functions around OpenProcessToken
336 and other functions in advapi32.dll that are only
337 supported in Windows NT / 2k / XP
339 /* ** Function pointer typedefs ** */
340 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
341 HANDLE ProcessHandle,
342 DWORD DesiredAccess,
343 PHANDLE TokenHandle);
344 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
345 HANDLE TokenHandle,
346 TOKEN_INFORMATION_CLASS TokenInformationClass,
347 LPVOID TokenInformation,
348 DWORD TokenInformationLength,
349 PDWORD ReturnLength);
350 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
351 HANDLE process_handle,
352 LPFILETIME creation_time,
353 LPFILETIME exit_time,
354 LPFILETIME kernel_time,
355 LPFILETIME user_time);
357 GetProcessTimes_Proc get_process_times_fn = NULL;
359 #ifdef _UNICODE
360 const char * const LookupAccountSid_Name = "LookupAccountSidW";
361 #else
362 const char * const LookupAccountSid_Name = "LookupAccountSidA";
363 #endif
364 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
365 LPCTSTR lpSystemName,
366 PSID Sid,
367 LPTSTR Name,
368 LPDWORD cbName,
369 LPTSTR DomainName,
370 LPDWORD cbDomainName,
371 PSID_NAME_USE peUse);
372 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
373 PSID pSid,
374 DWORD n);
375 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
376 PSID pSid);
377 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
378 HANDLE handle,
379 SE_OBJECT_TYPE ObjectType,
380 SECURITY_INFORMATION SecurityInfo,
381 PSID *ppsidOwner,
382 PSID *ppsidGroup,
383 PACL *ppDacl,
384 PACL *ppSacl,
385 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
386 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
387 LPCWSTR lpFileName,
388 SECURITY_INFORMATION RequestedInformation,
389 PSECURITY_DESCRIPTOR pSecurityDescriptor,
390 DWORD nLength,
391 LPDWORD lpnLengthNeeded);
392 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
393 LPCSTR lpFileName,
394 SECURITY_INFORMATION RequestedInformation,
395 PSECURITY_DESCRIPTOR pSecurityDescriptor,
396 DWORD nLength,
397 LPDWORD lpnLengthNeeded);
398 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
399 LPCWSTR lpFileName,
400 SECURITY_INFORMATION SecurityInformation,
401 PSECURITY_DESCRIPTOR pSecurityDescriptor);
402 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
403 LPCSTR lpFileName,
404 SECURITY_INFORMATION SecurityInformation,
405 PSECURITY_DESCRIPTOR pSecurityDescriptor);
406 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
407 LPCWSTR lpObjectName,
408 SE_OBJECT_TYPE ObjectType,
409 SECURITY_INFORMATION SecurityInformation,
410 PSID psidOwner,
411 PSID psidGroup,
412 PACL pDacl,
413 PACL pSacl);
414 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
415 LPCSTR lpObjectName,
416 SE_OBJECT_TYPE ObjectType,
417 SECURITY_INFORMATION SecurityInformation,
418 PSID psidOwner,
419 PSID psidGroup,
420 PACL pDacl,
421 PACL pSacl);
422 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
423 PSECURITY_DESCRIPTOR pSecurityDescriptor,
424 PSID *pOwner,
425 LPBOOL lpbOwnerDefaulted);
426 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
427 PSECURITY_DESCRIPTOR pSecurityDescriptor,
428 PSID *pGroup,
429 LPBOOL lpbGroupDefaulted);
430 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
431 PSECURITY_DESCRIPTOR pSecurityDescriptor,
432 LPBOOL lpbDaclPresent,
433 PACL *pDacl,
434 LPBOOL lpbDaclDefaulted);
435 typedef BOOL (WINAPI * IsValidSid_Proc) (
436 PSID sid);
437 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
438 DWORD dwFlags,
439 DWORD th32ProcessID);
440 typedef BOOL (WINAPI * Process32First_Proc) (
441 HANDLE hSnapshot,
442 LPPROCESSENTRY32 lppe);
443 typedef BOOL (WINAPI * Process32Next_Proc) (
444 HANDLE hSnapshot,
445 LPPROCESSENTRY32 lppe);
446 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
447 HANDLE ThreadHandle,
448 DWORD DesiredAccess,
449 BOOL OpenAsSelf,
450 PHANDLE TokenHandle);
451 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
452 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
453 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
454 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
455 HANDLE Process,
456 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
457 DWORD cb);
458 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
459 HANDLE hProcess,
460 PSIZE_T lpMinimumWorkingSetSize,
461 PSIZE_T lpMaximumWorkingSetSize);
462 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
463 LPMEMORYSTATUS lpBuffer);
464 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
465 LPMEMORY_STATUS_EX lpBuffer);
466 typedef BOOL (WINAPI * CopySid_Proc) (
467 DWORD nDestinationSidLength,
468 PSID pDestinationSid,
469 PSID pSourceSid);
470 typedef BOOL (WINAPI * EqualSid_Proc) (
471 PSID pSid1,
472 PSID pSid2);
473 typedef DWORD (WINAPI * GetLengthSid_Proc) (
474 PSID pSid);
475 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
476 LPSYSTEM_INFO lpSystemInfo);
477 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
478 LPFILETIME lpIdleTime,
479 LPFILETIME lpKernelTime,
480 LPFILETIME lpUserTime);
481 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
482 LPCWSTR lpSymlinkFileName,
483 LPCWSTR lpTargetFileName,
484 DWORD dwFlags);
485 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
486 LPCSTR lpSymlinkFileName,
487 LPCSTR lpTargetFileName,
488 DWORD dwFlags);
489 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
490 LPCTSTR StringSecurityDescriptor,
491 DWORD StringSDRevision,
492 PSECURITY_DESCRIPTOR *SecurityDescriptor,
493 PULONG SecurityDescriptorSize);
494 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
495 PSECURITY_DESCRIPTOR SecurityDescriptor,
496 DWORD RequestedStringSDRevision,
497 SECURITY_INFORMATION SecurityInformation,
498 LPTSTR *StringSecurityDescriptor,
499 PULONG StringSecurityDescriptorLen);
500 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
501 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
502 PIP_ADAPTER_INFO pAdapterInfo,
503 PULONG pOutBufLen);
505 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
506 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
507 DWORD multiByteToWideCharFlags;
509 /* ** A utility function ** */
510 static BOOL
511 is_windows_9x (void)
513 static BOOL s_b_ret = 0;
514 OSVERSIONINFO os_ver;
515 if (g_b_init_is_windows_9x == 0)
517 g_b_init_is_windows_9x = 1;
518 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
519 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
520 if (GetVersionEx (&os_ver))
522 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
525 return s_b_ret;
528 static Lisp_Object ltime (ULONGLONG);
530 /* Get total user and system times for get-internal-run-time.
531 Returns a list of integers if the times are provided by the OS
532 (NT derivatives), otherwise it returns the result of current-time. */
533 Lisp_Object w32_get_internal_run_time (void);
535 Lisp_Object
536 w32_get_internal_run_time (void)
538 if (get_process_times_fn)
540 FILETIME create, exit, kernel, user;
541 HANDLE proc = GetCurrentProcess ();
542 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
544 LARGE_INTEGER user_int, kernel_int, total;
545 user_int.LowPart = user.dwLowDateTime;
546 user_int.HighPart = user.dwHighDateTime;
547 kernel_int.LowPart = kernel.dwLowDateTime;
548 kernel_int.HighPart = kernel.dwHighDateTime;
549 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
550 return ltime (total.QuadPart);
554 return Fcurrent_time ();
557 /* ** The wrapper functions ** */
559 static BOOL WINAPI
560 open_process_token (HANDLE ProcessHandle,
561 DWORD DesiredAccess,
562 PHANDLE TokenHandle)
564 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
565 HMODULE hm_advapi32 = NULL;
566 if (is_windows_9x () == TRUE)
568 return FALSE;
570 if (g_b_init_open_process_token == 0)
572 g_b_init_open_process_token = 1;
573 hm_advapi32 = LoadLibrary ("Advapi32.dll");
574 s_pfn_Open_Process_Token =
575 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
577 if (s_pfn_Open_Process_Token == NULL)
579 return FALSE;
581 return (
582 s_pfn_Open_Process_Token (
583 ProcessHandle,
584 DesiredAccess,
585 TokenHandle)
589 static BOOL WINAPI
590 get_token_information (HANDLE TokenHandle,
591 TOKEN_INFORMATION_CLASS TokenInformationClass,
592 LPVOID TokenInformation,
593 DWORD TokenInformationLength,
594 PDWORD ReturnLength)
596 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
597 HMODULE hm_advapi32 = NULL;
598 if (is_windows_9x () == TRUE)
600 return FALSE;
602 if (g_b_init_get_token_information == 0)
604 g_b_init_get_token_information = 1;
605 hm_advapi32 = LoadLibrary ("Advapi32.dll");
606 s_pfn_Get_Token_Information =
607 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
609 if (s_pfn_Get_Token_Information == NULL)
611 return FALSE;
613 return (
614 s_pfn_Get_Token_Information (
615 TokenHandle,
616 TokenInformationClass,
617 TokenInformation,
618 TokenInformationLength,
619 ReturnLength)
623 static BOOL WINAPI
624 lookup_account_sid (LPCTSTR lpSystemName,
625 PSID Sid,
626 LPTSTR Name,
627 LPDWORD cbName,
628 LPTSTR DomainName,
629 LPDWORD cbDomainName,
630 PSID_NAME_USE peUse)
632 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
633 HMODULE hm_advapi32 = NULL;
634 if (is_windows_9x () == TRUE)
636 return FALSE;
638 if (g_b_init_lookup_account_sid == 0)
640 g_b_init_lookup_account_sid = 1;
641 hm_advapi32 = LoadLibrary ("Advapi32.dll");
642 s_pfn_Lookup_Account_Sid =
643 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
645 if (s_pfn_Lookup_Account_Sid == NULL)
647 return FALSE;
649 return (
650 s_pfn_Lookup_Account_Sid (
651 lpSystemName,
652 Sid,
653 Name,
654 cbName,
655 DomainName,
656 cbDomainName,
657 peUse)
661 static PDWORD WINAPI
662 get_sid_sub_authority (PSID pSid, DWORD n)
664 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
665 static DWORD zero = 0U;
666 HMODULE hm_advapi32 = NULL;
667 if (is_windows_9x () == TRUE)
669 return &zero;
671 if (g_b_init_get_sid_sub_authority == 0)
673 g_b_init_get_sid_sub_authority = 1;
674 hm_advapi32 = LoadLibrary ("Advapi32.dll");
675 s_pfn_Get_Sid_Sub_Authority =
676 (GetSidSubAuthority_Proc) GetProcAddress (
677 hm_advapi32, "GetSidSubAuthority");
679 if (s_pfn_Get_Sid_Sub_Authority == NULL)
681 return &zero;
683 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
686 static PUCHAR WINAPI
687 get_sid_sub_authority_count (PSID pSid)
689 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
690 static UCHAR zero = 0U;
691 HMODULE hm_advapi32 = NULL;
692 if (is_windows_9x () == TRUE)
694 return &zero;
696 if (g_b_init_get_sid_sub_authority_count == 0)
698 g_b_init_get_sid_sub_authority_count = 1;
699 hm_advapi32 = LoadLibrary ("Advapi32.dll");
700 s_pfn_Get_Sid_Sub_Authority_Count =
701 (GetSidSubAuthorityCount_Proc) GetProcAddress (
702 hm_advapi32, "GetSidSubAuthorityCount");
704 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
706 return &zero;
708 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
711 static DWORD WINAPI
712 get_security_info (HANDLE handle,
713 SE_OBJECT_TYPE ObjectType,
714 SECURITY_INFORMATION SecurityInfo,
715 PSID *ppsidOwner,
716 PSID *ppsidGroup,
717 PACL *ppDacl,
718 PACL *ppSacl,
719 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
721 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
722 HMODULE hm_advapi32 = NULL;
723 if (is_windows_9x () == TRUE)
725 return FALSE;
727 if (g_b_init_get_security_info == 0)
729 g_b_init_get_security_info = 1;
730 hm_advapi32 = LoadLibrary ("Advapi32.dll");
731 s_pfn_Get_Security_Info =
732 (GetSecurityInfo_Proc) GetProcAddress (
733 hm_advapi32, "GetSecurityInfo");
735 if (s_pfn_Get_Security_Info == NULL)
737 return FALSE;
739 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
740 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
741 ppSecurityDescriptor));
744 static BOOL WINAPI
745 get_file_security (const char *lpFileName,
746 SECURITY_INFORMATION RequestedInformation,
747 PSECURITY_DESCRIPTOR pSecurityDescriptor,
748 DWORD nLength,
749 LPDWORD lpnLengthNeeded)
751 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
752 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
753 HMODULE hm_advapi32 = NULL;
754 if (is_windows_9x () == TRUE)
756 errno = ENOTSUP;
757 return FALSE;
759 if (w32_unicode_filenames)
761 wchar_t filename_w[MAX_PATH];
763 if (g_b_init_get_file_security_w == 0)
765 g_b_init_get_file_security_w = 1;
766 hm_advapi32 = LoadLibrary ("Advapi32.dll");
767 s_pfn_Get_File_SecurityW =
768 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
769 "GetFileSecurityW");
771 if (s_pfn_Get_File_SecurityW == NULL)
773 errno = ENOTSUP;
774 return FALSE;
776 filename_to_utf16 (lpFileName, filename_w);
777 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
778 pSecurityDescriptor, nLength,
779 lpnLengthNeeded));
781 else
783 char filename_a[MAX_PATH];
785 if (g_b_init_get_file_security_a == 0)
787 g_b_init_get_file_security_a = 1;
788 hm_advapi32 = LoadLibrary ("Advapi32.dll");
789 s_pfn_Get_File_SecurityA =
790 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
791 "GetFileSecurityA");
793 if (s_pfn_Get_File_SecurityA == NULL)
795 errno = ENOTSUP;
796 return FALSE;
798 filename_to_ansi (lpFileName, filename_a);
799 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
800 pSecurityDescriptor, nLength,
801 lpnLengthNeeded));
805 static BOOL WINAPI
806 set_file_security (const char *lpFileName,
807 SECURITY_INFORMATION SecurityInformation,
808 PSECURITY_DESCRIPTOR pSecurityDescriptor)
810 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
811 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
812 HMODULE hm_advapi32 = NULL;
813 if (is_windows_9x () == TRUE)
815 errno = ENOTSUP;
816 return FALSE;
818 if (w32_unicode_filenames)
820 wchar_t filename_w[MAX_PATH];
822 if (g_b_init_set_file_security_w == 0)
824 g_b_init_set_file_security_w = 1;
825 hm_advapi32 = LoadLibrary ("Advapi32.dll");
826 s_pfn_Set_File_SecurityW =
827 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
828 "SetFileSecurityW");
830 if (s_pfn_Set_File_SecurityW == NULL)
832 errno = ENOTSUP;
833 return FALSE;
835 filename_to_utf16 (lpFileName, filename_w);
836 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
837 pSecurityDescriptor));
839 else
841 char filename_a[MAX_PATH];
843 if (g_b_init_set_file_security_a == 0)
845 g_b_init_set_file_security_a = 1;
846 hm_advapi32 = LoadLibrary ("Advapi32.dll");
847 s_pfn_Set_File_SecurityA =
848 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
849 "SetFileSecurityA");
851 if (s_pfn_Set_File_SecurityA == NULL)
853 errno = ENOTSUP;
854 return FALSE;
856 filename_to_ansi (lpFileName, filename_a);
857 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
858 pSecurityDescriptor));
862 static DWORD WINAPI
863 set_named_security_info (LPCTSTR lpObjectName,
864 SE_OBJECT_TYPE ObjectType,
865 SECURITY_INFORMATION SecurityInformation,
866 PSID psidOwner,
867 PSID psidGroup,
868 PACL pDacl,
869 PACL pSacl)
871 static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
872 static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
873 HMODULE hm_advapi32 = NULL;
874 if (is_windows_9x () == TRUE)
876 errno = ENOTSUP;
877 return ENOTSUP;
879 if (w32_unicode_filenames)
881 wchar_t filename_w[MAX_PATH];
883 if (g_b_init_set_named_security_info_w == 0)
885 g_b_init_set_named_security_info_w = 1;
886 hm_advapi32 = LoadLibrary ("Advapi32.dll");
887 s_pfn_Set_Named_Security_InfoW =
888 (SetNamedSecurityInfoW_Proc) GetProcAddress (hm_advapi32,
889 "SetNamedSecurityInfoW");
891 if (s_pfn_Set_Named_Security_InfoW == NULL)
893 errno = ENOTSUP;
894 return ENOTSUP;
896 filename_to_utf16 (lpObjectName, filename_w);
897 return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
898 SecurityInformation, psidOwner,
899 psidGroup, pDacl, pSacl));
901 else
903 char filename_a[MAX_PATH];
905 if (g_b_init_set_named_security_info_a == 0)
907 g_b_init_set_named_security_info_a = 1;
908 hm_advapi32 = LoadLibrary ("Advapi32.dll");
909 s_pfn_Set_Named_Security_InfoA =
910 (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
911 "SetNamedSecurityInfoA");
913 if (s_pfn_Set_Named_Security_InfoA == NULL)
915 errno = ENOTSUP;
916 return ENOTSUP;
918 filename_to_ansi (lpObjectName, filename_a);
919 return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
920 SecurityInformation, psidOwner,
921 psidGroup, pDacl, pSacl));
925 static BOOL WINAPI
926 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
927 PSID *pOwner,
928 LPBOOL lpbOwnerDefaulted)
930 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
931 HMODULE hm_advapi32 = NULL;
932 if (is_windows_9x () == TRUE)
934 errno = ENOTSUP;
935 return FALSE;
937 if (g_b_init_get_security_descriptor_owner == 0)
939 g_b_init_get_security_descriptor_owner = 1;
940 hm_advapi32 = LoadLibrary ("Advapi32.dll");
941 s_pfn_Get_Security_Descriptor_Owner =
942 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
943 hm_advapi32, "GetSecurityDescriptorOwner");
945 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
947 errno = ENOTSUP;
948 return FALSE;
950 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
951 lpbOwnerDefaulted));
954 static BOOL WINAPI
955 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
956 PSID *pGroup,
957 LPBOOL lpbGroupDefaulted)
959 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
960 HMODULE hm_advapi32 = NULL;
961 if (is_windows_9x () == TRUE)
963 errno = ENOTSUP;
964 return FALSE;
966 if (g_b_init_get_security_descriptor_group == 0)
968 g_b_init_get_security_descriptor_group = 1;
969 hm_advapi32 = LoadLibrary ("Advapi32.dll");
970 s_pfn_Get_Security_Descriptor_Group =
971 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
972 hm_advapi32, "GetSecurityDescriptorGroup");
974 if (s_pfn_Get_Security_Descriptor_Group == NULL)
976 errno = ENOTSUP;
977 return FALSE;
979 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
980 lpbGroupDefaulted));
983 static BOOL WINAPI
984 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
985 LPBOOL lpbDaclPresent,
986 PACL *pDacl,
987 LPBOOL lpbDaclDefaulted)
989 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
990 HMODULE hm_advapi32 = NULL;
991 if (is_windows_9x () == TRUE)
993 errno = ENOTSUP;
994 return FALSE;
996 if (g_b_init_get_security_descriptor_dacl == 0)
998 g_b_init_get_security_descriptor_dacl = 1;
999 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1000 s_pfn_Get_Security_Descriptor_Dacl =
1001 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
1002 hm_advapi32, "GetSecurityDescriptorDacl");
1004 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
1006 errno = ENOTSUP;
1007 return FALSE;
1009 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
1010 lpbDaclPresent, pDacl,
1011 lpbDaclDefaulted));
1014 static BOOL WINAPI
1015 is_valid_sid (PSID sid)
1017 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
1018 HMODULE hm_advapi32 = NULL;
1019 if (is_windows_9x () == TRUE)
1021 return FALSE;
1023 if (g_b_init_is_valid_sid == 0)
1025 g_b_init_is_valid_sid = 1;
1026 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1027 s_pfn_Is_Valid_Sid =
1028 (IsValidSid_Proc) GetProcAddress (
1029 hm_advapi32, "IsValidSid");
1031 if (s_pfn_Is_Valid_Sid == NULL)
1033 return FALSE;
1035 return (s_pfn_Is_Valid_Sid (sid));
1038 static BOOL WINAPI
1039 equal_sid (PSID sid1, PSID sid2)
1041 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
1042 HMODULE hm_advapi32 = NULL;
1043 if (is_windows_9x () == TRUE)
1045 return FALSE;
1047 if (g_b_init_equal_sid == 0)
1049 g_b_init_equal_sid = 1;
1050 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1051 s_pfn_Equal_Sid =
1052 (EqualSid_Proc) GetProcAddress (
1053 hm_advapi32, "EqualSid");
1055 if (s_pfn_Equal_Sid == NULL)
1057 return FALSE;
1059 return (s_pfn_Equal_Sid (sid1, sid2));
1062 static DWORD WINAPI
1063 get_length_sid (PSID sid)
1065 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
1066 HMODULE hm_advapi32 = NULL;
1067 if (is_windows_9x () == TRUE)
1069 return 0;
1071 if (g_b_init_get_length_sid == 0)
1073 g_b_init_get_length_sid = 1;
1074 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1075 s_pfn_Get_Length_Sid =
1076 (GetLengthSid_Proc) GetProcAddress (
1077 hm_advapi32, "GetLengthSid");
1079 if (s_pfn_Get_Length_Sid == NULL)
1081 return 0;
1083 return (s_pfn_Get_Length_Sid (sid));
1086 static BOOL WINAPI
1087 copy_sid (DWORD destlen, PSID dest, PSID src)
1089 static CopySid_Proc s_pfn_Copy_Sid = NULL;
1090 HMODULE hm_advapi32 = NULL;
1091 if (is_windows_9x () == TRUE)
1093 return FALSE;
1095 if (g_b_init_copy_sid == 0)
1097 g_b_init_copy_sid = 1;
1098 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1099 s_pfn_Copy_Sid =
1100 (CopySid_Proc) GetProcAddress (
1101 hm_advapi32, "CopySid");
1103 if (s_pfn_Copy_Sid == NULL)
1105 return FALSE;
1107 return (s_pfn_Copy_Sid (destlen, dest, src));
1111 END: Wrapper functions around OpenProcessToken
1112 and other functions in advapi32.dll that are only
1113 supported in Windows NT / 2k / XP
1116 static void WINAPI
1117 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1119 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1120 if (is_windows_9x () != TRUE)
1122 if (g_b_init_get_native_system_info == 0)
1124 g_b_init_get_native_system_info = 1;
1125 s_pfn_Get_Native_System_Info =
1126 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1127 "GetNativeSystemInfo");
1129 if (s_pfn_Get_Native_System_Info != NULL)
1130 s_pfn_Get_Native_System_Info (lpSystemInfo);
1132 else
1133 lpSystemInfo->dwNumberOfProcessors = -1;
1136 static BOOL WINAPI
1137 get_system_times (LPFILETIME lpIdleTime,
1138 LPFILETIME lpKernelTime,
1139 LPFILETIME lpUserTime)
1141 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1142 if (is_windows_9x () == TRUE)
1144 return FALSE;
1146 if (g_b_init_get_system_times == 0)
1148 g_b_init_get_system_times = 1;
1149 s_pfn_Get_System_times =
1150 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1151 "GetSystemTimes");
1153 if (s_pfn_Get_System_times == NULL)
1154 return FALSE;
1155 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1158 static BOOLEAN WINAPI
1159 create_symbolic_link (LPCSTR lpSymlinkFilename,
1160 LPCSTR lpTargetFileName,
1161 DWORD dwFlags)
1163 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1164 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1165 BOOLEAN retval;
1167 if (is_windows_9x () == TRUE)
1169 errno = ENOSYS;
1170 return 0;
1172 if (w32_unicode_filenames)
1174 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1176 if (g_b_init_create_symbolic_link_w == 0)
1178 g_b_init_create_symbolic_link_w = 1;
1179 s_pfn_Create_Symbolic_LinkW =
1180 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1181 "CreateSymbolicLinkW");
1183 if (s_pfn_Create_Symbolic_LinkW == NULL)
1185 errno = ENOSYS;
1186 return 0;
1189 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1190 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1191 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1192 /* If we were denied creation of the symlink, try again after
1193 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1194 if (!retval)
1196 TOKEN_PRIVILEGES priv_current;
1198 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1199 &priv_current))
1201 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1202 restore_privilege (&priv_current);
1203 revert_to_self ();
1207 else
1209 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1211 if (g_b_init_create_symbolic_link_a == 0)
1213 g_b_init_create_symbolic_link_a = 1;
1214 s_pfn_Create_Symbolic_LinkA =
1215 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1216 "CreateSymbolicLinkA");
1218 if (s_pfn_Create_Symbolic_LinkA == NULL)
1220 errno = ENOSYS;
1221 return 0;
1224 filename_to_ansi (lpSymlinkFilename, symfn_a);
1225 filename_to_ansi (lpTargetFileName, tgtfn_a);
1226 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1227 /* If we were denied creation of the symlink, try again after
1228 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1229 if (!retval)
1231 TOKEN_PRIVILEGES priv_current;
1233 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1234 &priv_current))
1236 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1237 restore_privilege (&priv_current);
1238 revert_to_self ();
1242 return retval;
1245 static BOOL WINAPI
1246 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1248 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1250 if (is_windows_9x () == TRUE)
1252 errno = ENOTSUP;
1253 return FALSE;
1256 if (g_b_init_is_valid_security_descriptor == 0)
1258 g_b_init_is_valid_security_descriptor = 1;
1259 s_pfn_Is_Valid_Security_Descriptor_Proc =
1260 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1261 "IsValidSecurityDescriptor");
1263 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1265 errno = ENOTSUP;
1266 return FALSE;
1269 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1272 static BOOL WINAPI
1273 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1274 DWORD RequestedStringSDRevision,
1275 SECURITY_INFORMATION SecurityInformation,
1276 LPTSTR *StringSecurityDescriptor,
1277 PULONG StringSecurityDescriptorLen)
1279 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1280 BOOL retval;
1282 if (is_windows_9x () == TRUE)
1284 errno = ENOTSUP;
1285 return FALSE;
1288 if (g_b_init_convert_sd_to_sddl == 0)
1290 g_b_init_convert_sd_to_sddl = 1;
1291 #ifdef _UNICODE
1292 s_pfn_Convert_SD_To_SDDL =
1293 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1294 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1295 #else
1296 s_pfn_Convert_SD_To_SDDL =
1297 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1298 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1299 #endif
1301 if (s_pfn_Convert_SD_To_SDDL == NULL)
1303 errno = ENOTSUP;
1304 return FALSE;
1307 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1308 RequestedStringSDRevision,
1309 SecurityInformation,
1310 StringSecurityDescriptor,
1311 StringSecurityDescriptorLen);
1313 return retval;
1316 static BOOL WINAPI
1317 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1318 DWORD StringSDRevision,
1319 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1320 PULONG SecurityDescriptorSize)
1322 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1323 BOOL retval;
1325 if (is_windows_9x () == TRUE)
1327 errno = ENOTSUP;
1328 return FALSE;
1331 if (g_b_init_convert_sddl_to_sd == 0)
1333 g_b_init_convert_sddl_to_sd = 1;
1334 #ifdef _UNICODE
1335 s_pfn_Convert_SDDL_To_SD =
1336 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1337 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1338 #else
1339 s_pfn_Convert_SDDL_To_SD =
1340 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1341 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1342 #endif
1344 if (s_pfn_Convert_SDDL_To_SD == NULL)
1346 errno = ENOTSUP;
1347 return FALSE;
1350 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1351 StringSDRevision,
1352 SecurityDescriptor,
1353 SecurityDescriptorSize);
1355 return retval;
1358 static DWORD WINAPI
1359 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1361 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1362 HMODULE hm_iphlpapi = NULL;
1364 if (is_windows_9x () == TRUE)
1365 return ERROR_NOT_SUPPORTED;
1367 if (g_b_init_get_adapters_info == 0)
1369 g_b_init_get_adapters_info = 1;
1370 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1371 if (hm_iphlpapi)
1372 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1373 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1375 if (s_pfn_Get_Adapters_Info == NULL)
1376 return ERROR_NOT_SUPPORTED;
1377 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1382 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1383 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1385 This is called from alloc.c:valid_pointer_p. */
1387 w32_valid_pointer_p (void *p, int size)
1389 SIZE_T done;
1390 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1392 if (h)
1394 unsigned char *buf = alloca (size);
1395 int retval = ReadProcessMemory (h, p, buf, size, &done);
1397 CloseHandle (h);
1398 return retval;
1400 else
1401 return -1;
1406 /* Here's an overview of how the Windows build supports file names
1407 that cannot be encoded by the current system codepage.
1409 From the POV of Lisp and layers of C code above the functions here,
1410 Emacs on Windows pretends that its file names are encoded in UTF-8;
1411 see encode_file and decode_file on coding.c. Any file name that is
1412 passed as a unibyte string to C functions defined here is assumed
1413 to be in UTF-8 encoding. Any file name returned by functions
1414 defined here must be in UTF-8 encoding, with only a few exceptions
1415 reserved for a couple of special cases. (Be sure to use
1416 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1417 as they can be much longer than MAX_PATH!)
1419 The UTF-8 encoded file names cannot be passed to system APIs, as
1420 Windows does not support that. Therefore, they are converted
1421 either to UTF-16 or to the ANSI codepage, depending on the value of
1422 w32-unicode-filenames, before calling any system APIs or CRT library
1423 functions. The default value of that variable is determined by the
1424 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1425 user can change that default (although I don't see why would she
1426 want to).
1428 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1429 filename_from_utf16, and filename_from_ansi, are the workhorses of
1430 these conversions. They rely on Windows native APIs
1431 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1432 functions from coding.c here, because they allocate memory, which
1433 is a bad idea on the level of libc, which is what the functions
1434 here emulate. (If you worry about performance due to constant
1435 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1436 it was measured to take only a few microseconds on a not-so-fast
1437 machine, and second, that's exactly what the ANSI APIs we used
1438 before did anyway, because they are just thin wrappers around the
1439 Unicode APIs.)
1441 The variables file-name-coding-system and default-file-name-coding-system
1442 still exist, but are actually used only when a file name needs to
1443 be converted to the ANSI codepage. This happens all the time when
1444 w32-unicode-filenames is nil, but can also happen from time to time
1445 when it is t. Otherwise, these variables have no effect on file-name
1446 encoding when w32-unicode-filenames is t; this is similar to
1447 selection-coding-system.
1449 This arrangement works very well, but it has a few gotchas and
1450 limitations:
1452 . Lisp code that encodes or decodes file names manually should
1453 normally use 'utf-8' as the coding-system on Windows,
1454 disregarding file-name-coding-system. This is a somewhat
1455 unpleasant consequence, but it cannot be avoided. Fortunately,
1456 very few Lisp packages need to do that.
1458 More generally, passing to library functions (e.g., fopen or
1459 opendir) file names already encoded in the ANSI codepage is
1460 explicitly *verboten*, as all those functions, as shadowed and
1461 emulated here, assume they will receive UTF-8 encoded file names.
1463 For the same reasons, no CRT function or Win32 API can be called
1464 directly in Emacs sources, without either converting the file
1465 names from UTF-8 to UTF-16 or ANSI codepage, or going through
1466 some shadowing function defined here.
1468 . Environment variables stored in Vprocess_environment are encoded
1469 in the ANSI codepage, so if getenv/egetenv is used for a variable
1470 whose value is a file name or a list of directories, it needs to
1471 be converted to UTF-8, before it is used as argument to functions
1472 or decoded into a Lisp string.
1474 . File names passed to external libraries, like the image libraries
1475 and GnuTLS, need special handling. These libraries generally
1476 don't support UTF-16 or UTF-8 file names, so they must get file
1477 names encoded in the ANSI codepage. To facilitate using these
1478 libraries with file names that are not encodable in the ANSI
1479 codepage, use the function ansi_encode_filename, which will try
1480 to use the short 8+3 alias of a file name if that file name is
1481 not encodable in the ANSI codepage. See image.c and gnutls.c for
1482 examples of how this should be done.
1484 . Running subprocesses in non-ASCII directories and with non-ASCII
1485 file arguments is limited to the current codepage (even though
1486 Emacs is perfectly capable of finding an executable program file
1487 in a directory whose name cannot be encoded in the current
1488 codepage). This is because the command-line arguments are
1489 encoded _before_ they get to the w32-specific level, and the
1490 encoding is not known in advance (it doesn't have to be the
1491 current ANSI codepage), so w32proc.c functions cannot re-encode
1492 them in UTF-16. This should be fixed, but will also require
1493 changes in cmdproxy. The current limitation is not terribly bad
1494 anyway, since very few, if any, Windows console programs that are
1495 likely to be invoked by Emacs support UTF-16 encoded command
1496 lines.
1498 . For similar reasons, server.el and emacsclient are also limited
1499 to the current ANSI codepage for now.
1501 . Emacs itself can only handle command-line arguments encoded in
1502 the current codepage.
1504 . Turning on w32-unicode-filename on Windows 9X (if it at all
1505 works) requires UNICOWS.DLL, which is thus a requirement even in
1506 non-GUI sessions, something the we previously avoided. */
1510 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1511 codepage defined by file-name-coding-system. */
1513 /* Current codepage for encoding file names. */
1514 static int file_name_codepage;
1516 /* Produce a Windows ANSI codepage suitable for encoding file names.
1517 Return the information about that codepage in CP_INFO. */
1519 codepage_for_filenames (CPINFO *cp_info)
1521 /* A simple cache to avoid calling GetCPInfo every time we need to
1522 encode/decode a file name. The file-name encoding is not
1523 supposed to be changed too frequently, if ever. */
1524 static Lisp_Object last_file_name_encoding;
1525 static CPINFO cp;
1526 Lisp_Object current_encoding;
1528 current_encoding = Vfile_name_coding_system;
1529 if (NILP (current_encoding))
1530 current_encoding = Vdefault_file_name_coding_system;
1532 if (!EQ (last_file_name_encoding, current_encoding))
1534 /* Default to the current ANSI codepage. */
1535 file_name_codepage = w32_ansi_code_page;
1537 if (NILP (current_encoding))
1539 char *cpname = SSDATA (SYMBOL_NAME (current_encoding));
1540 char *cp = NULL, *end;
1541 int cpnum;
1543 if (strncmp (cpname, "cp", 2) == 0)
1544 cp = cpname + 2;
1545 else if (strncmp (cpname, "windows-", 8) == 0)
1546 cp = cpname + 8;
1548 if (cp)
1550 end = cp;
1551 cpnum = strtol (cp, &end, 10);
1552 if (cpnum && *end == '\0' && end - cp >= 2)
1553 file_name_codepage = cpnum;
1557 if (!file_name_codepage)
1558 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1560 if (!GetCPInfo (file_name_codepage, &cp))
1562 file_name_codepage = CP_ACP;
1563 if (!GetCPInfo (file_name_codepage, &cp))
1564 emacs_abort ();
1567 if (cp_info)
1568 *cp_info = cp;
1570 return file_name_codepage;
1574 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1576 int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
1577 -1, fn_out, MAX_PATH);
1579 if (!result)
1581 DWORD err = GetLastError ();
1583 switch (err)
1585 case ERROR_INVALID_FLAGS:
1586 case ERROR_INVALID_PARAMETER:
1587 errno = EINVAL;
1588 break;
1589 case ERROR_INSUFFICIENT_BUFFER:
1590 case ERROR_NO_UNICODE_TRANSLATION:
1591 default:
1592 errno = ENOENT;
1593 break;
1595 return -1;
1597 return 0;
1601 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1603 int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1604 fn_out, MAX_UTF8_PATH, NULL, NULL);
1606 if (!result)
1608 DWORD err = GetLastError ();
1610 switch (err)
1612 case ERROR_INVALID_FLAGS:
1613 case ERROR_INVALID_PARAMETER:
1614 errno = EINVAL;
1615 break;
1616 case ERROR_INSUFFICIENT_BUFFER:
1617 case ERROR_NO_UNICODE_TRANSLATION:
1618 default:
1619 errno = ENOENT;
1620 break;
1622 return -1;
1624 return 0;
1628 filename_to_ansi (const char *fn_in, char *fn_out)
1630 wchar_t fn_utf16[MAX_PATH];
1632 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1634 int result;
1635 int codepage = codepage_for_filenames (NULL);
1637 result = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
1638 fn_out, MAX_PATH, NULL, NULL);
1639 if (!result)
1641 DWORD err = GetLastError ();
1643 switch (err)
1645 case ERROR_INVALID_FLAGS:
1646 case ERROR_INVALID_PARAMETER:
1647 errno = EINVAL;
1648 break;
1649 case ERROR_INSUFFICIENT_BUFFER:
1650 case ERROR_NO_UNICODE_TRANSLATION:
1651 default:
1652 errno = ENOENT;
1653 break;
1655 return -1;
1657 return 0;
1659 return -1;
1663 filename_from_ansi (const char *fn_in, char *fn_out)
1665 wchar_t fn_utf16[MAX_PATH];
1666 int codepage = codepage_for_filenames (NULL);
1667 int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
1668 -1, fn_utf16, MAX_PATH);
1670 if (!result)
1672 DWORD err = GetLastError ();
1674 switch (err)
1676 case ERROR_INVALID_FLAGS:
1677 case ERROR_INVALID_PARAMETER:
1678 errno = EINVAL;
1679 break;
1680 case ERROR_INSUFFICIENT_BUFFER:
1681 case ERROR_NO_UNICODE_TRANSLATION:
1682 default:
1683 errno = ENOENT;
1684 break;
1686 return -1;
1688 return filename_from_utf16 (fn_utf16, fn_out);
1693 /* The directory where we started, in UTF-8. */
1694 static char startup_dir[MAX_UTF8_PATH];
1696 /* Get the current working directory. */
1697 char *
1698 getcwd (char *dir, int dirsize)
1700 if (!dirsize)
1702 errno = EINVAL;
1703 return NULL;
1705 if (dirsize <= strlen (startup_dir))
1707 errno = ERANGE;
1708 return NULL;
1710 #if 0
1711 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1712 return dir;
1713 return NULL;
1714 #else
1715 /* Emacs doesn't actually change directory itself, it stays in the
1716 same directory where it was started. */
1717 strcpy (dir, startup_dir);
1718 return dir;
1719 #endif
1722 /* Emulate getloadavg. */
1724 struct load_sample {
1725 time_t sample_time;
1726 ULONGLONG idle;
1727 ULONGLONG kernel;
1728 ULONGLONG user;
1731 /* Number of processors on this machine. */
1732 static unsigned num_of_processors;
1734 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1735 static struct load_sample samples[16*60];
1736 static int first_idx = -1, last_idx = -1;
1737 static int max_idx = ARRAYELTS (samples);
1739 static int
1740 buf_next (int from)
1742 int next_idx = from + 1;
1744 if (next_idx >= max_idx)
1745 next_idx = 0;
1747 return next_idx;
1750 static int
1751 buf_prev (int from)
1753 int prev_idx = from - 1;
1755 if (prev_idx < 0)
1756 prev_idx = max_idx - 1;
1758 return prev_idx;
1761 static void
1762 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1764 SYSTEM_INFO sysinfo;
1765 FILETIME ft_idle, ft_user, ft_kernel;
1767 /* Initialize the number of processors on this machine. */
1768 if (num_of_processors <= 0)
1770 get_native_system_info (&sysinfo);
1771 num_of_processors = sysinfo.dwNumberOfProcessors;
1772 if (num_of_processors <= 0)
1774 GetSystemInfo (&sysinfo);
1775 num_of_processors = sysinfo.dwNumberOfProcessors;
1777 if (num_of_processors <= 0)
1778 num_of_processors = 1;
1781 /* TODO: Take into account threads that are ready to run, by
1782 sampling the "\System\Processor Queue Length" performance
1783 counter. The code below accounts only for threads that are
1784 actually running. */
1786 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1788 ULARGE_INTEGER uidle, ukernel, uuser;
1790 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1791 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1792 memcpy (&uuser, &ft_user, sizeof (ft_user));
1793 *idle = uidle.QuadPart;
1794 *kernel = ukernel.QuadPart;
1795 *user = uuser.QuadPart;
1797 else
1799 *idle = 0;
1800 *kernel = 0;
1801 *user = 0;
1805 /* Produce the load average for a given time interval, using the
1806 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1807 1-minute, 5-minute, or 15-minute average, respectively. */
1808 static double
1809 getavg (int which)
1811 double retval = -1.0;
1812 double tdiff;
1813 int idx;
1814 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1815 time_t now = samples[last_idx].sample_time;
1817 if (first_idx != last_idx)
1819 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1821 tdiff = difftime (now, samples[idx].sample_time);
1822 if (tdiff >= span - 2*DBL_EPSILON*now)
1824 long double sys =
1825 samples[last_idx].kernel + samples[last_idx].user
1826 - (samples[idx].kernel + samples[idx].user);
1827 long double idl = samples[last_idx].idle - samples[idx].idle;
1829 retval = (1.0 - idl / sys) * num_of_processors;
1830 break;
1832 if (idx == first_idx)
1833 break;
1837 return retval;
1841 getloadavg (double loadavg[], int nelem)
1843 int elem;
1844 ULONGLONG idle, kernel, user;
1845 time_t now = time (NULL);
1847 /* If system time jumped back for some reason, delete all samples
1848 whose time is later than the current wall-clock time. This
1849 prevents load average figures from becoming frozen for prolonged
1850 periods of time, when system time is reset backwards. */
1851 if (last_idx >= 0)
1853 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1855 if (last_idx == first_idx)
1857 first_idx = last_idx = -1;
1858 break;
1860 last_idx = buf_prev (last_idx);
1864 /* Store another sample. We ignore samples that are less than 1 sec
1865 apart. */
1866 if (last_idx < 0
1867 || (difftime (now, samples[last_idx].sample_time)
1868 >= 1.0 - 2*DBL_EPSILON*now))
1870 sample_system_load (&idle, &kernel, &user);
1871 last_idx = buf_next (last_idx);
1872 samples[last_idx].sample_time = now;
1873 samples[last_idx].idle = idle;
1874 samples[last_idx].kernel = kernel;
1875 samples[last_idx].user = user;
1876 /* If the buffer has more that 15 min worth of samples, discard
1877 the old ones. */
1878 if (first_idx == -1)
1879 first_idx = last_idx;
1880 while (first_idx != last_idx
1881 && (difftime (now, samples[first_idx].sample_time)
1882 >= 15.0*60 + 2*DBL_EPSILON*now))
1883 first_idx = buf_next (first_idx);
1886 for (elem = 0; elem < nelem; elem++)
1888 double avg = getavg (elem);
1890 if (avg < 0)
1891 break;
1892 loadavg[elem] = avg;
1895 return elem;
1898 /* Emulate getpwuid, getpwnam and others. */
1900 #define PASSWD_FIELD_SIZE 256
1902 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1903 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1904 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1905 static char dflt_passwd_dir[MAX_UTF8_PATH];
1906 static char dflt_passwd_shell[MAX_UTF8_PATH];
1908 static struct passwd dflt_passwd =
1910 dflt_passwd_name,
1911 dflt_passwd_passwd,
1915 dflt_passwd_gecos,
1916 dflt_passwd_dir,
1917 dflt_passwd_shell,
1920 static char dflt_group_name[GNLEN+1];
1922 static struct group dflt_group =
1924 /* When group information is not available, we return this as the
1925 group for all files. */
1926 dflt_group_name,
1930 unsigned
1931 getuid (void)
1933 return dflt_passwd.pw_uid;
1936 unsigned
1937 geteuid (void)
1939 /* I could imagine arguing for checking to see whether the user is
1940 in the Administrators group and returning a UID of 0 for that
1941 case, but I don't know how wise that would be in the long run. */
1942 return getuid ();
1945 unsigned
1946 getgid (void)
1948 return dflt_passwd.pw_gid;
1951 unsigned
1952 getegid (void)
1954 return getgid ();
1957 struct passwd *
1958 getpwuid (unsigned uid)
1960 if (uid == dflt_passwd.pw_uid)
1961 return &dflt_passwd;
1962 return NULL;
1965 struct group *
1966 getgrgid (gid_t gid)
1968 return &dflt_group;
1971 struct passwd *
1972 getpwnam (char *name)
1974 struct passwd *pw;
1976 pw = getpwuid (getuid ());
1977 if (!pw)
1978 return pw;
1980 if (xstrcasecmp (name, pw->pw_name))
1981 return NULL;
1983 return pw;
1986 static void
1987 init_user_info (void)
1989 /* Find the user's real name by opening the process token and
1990 looking up the name associated with the user-sid in that token.
1992 Use the relative portion of the identifier authority value from
1993 the user-sid as the user id value (same for group id using the
1994 primary group sid from the process token). */
1996 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1997 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1998 DWORD glength = sizeof (gname);
1999 HANDLE token = NULL;
2000 SID_NAME_USE user_type;
2001 unsigned char *buf = NULL;
2002 DWORD blen = 0;
2003 TOKEN_USER user_token;
2004 TOKEN_PRIMARY_GROUP group_token;
2005 BOOL result;
2007 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
2008 if (result)
2010 result = get_token_information (token, TokenUser, NULL, 0, &blen);
2011 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2013 buf = xmalloc (blen);
2014 result = get_token_information (token, TokenUser,
2015 (LPVOID)buf, blen, &needed);
2016 if (result)
2018 memcpy (&user_token, buf, sizeof (user_token));
2019 result = lookup_account_sid (NULL, user_token.User.Sid,
2020 uname, &ulength,
2021 domain, &dlength, &user_type);
2024 else
2025 result = FALSE;
2027 if (result)
2029 strcpy (dflt_passwd.pw_name, uname);
2030 /* Determine a reasonable uid value. */
2031 if (xstrcasecmp ("administrator", uname) == 0)
2033 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
2034 dflt_passwd.pw_gid = 513; /* well-known None gid */
2036 else
2038 /* Use the last sub-authority value of the RID, the relative
2039 portion of the SID, as user/group ID. */
2040 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
2042 /* Get group id and name. */
2043 result = get_token_information (token, TokenPrimaryGroup,
2044 (LPVOID)buf, blen, &needed);
2045 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2047 buf = xrealloc (buf, blen = needed);
2048 result = get_token_information (token, TokenPrimaryGroup,
2049 (LPVOID)buf, blen, &needed);
2051 if (result)
2053 memcpy (&group_token, buf, sizeof (group_token));
2054 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
2055 dlength = sizeof (domain);
2056 /* If we can get at the real Primary Group name, use that.
2057 Otherwise, the default group name was already set to
2058 "None" in globals_of_w32. */
2059 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
2060 gname, &glength, NULL, &dlength,
2061 &user_type))
2062 strcpy (dflt_group_name, gname);
2064 else
2065 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2068 /* If security calls are not supported (presumably because we
2069 are running under Windows 9X), fallback to this: */
2070 else if (GetUserName (uname, &ulength))
2072 strcpy (dflt_passwd.pw_name, uname);
2073 if (xstrcasecmp ("administrator", uname) == 0)
2074 dflt_passwd.pw_uid = 0;
2075 else
2076 dflt_passwd.pw_uid = 123;
2077 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2079 else
2081 strcpy (dflt_passwd.pw_name, "unknown");
2082 dflt_passwd.pw_uid = 123;
2083 dflt_passwd.pw_gid = 123;
2085 dflt_group.gr_gid = dflt_passwd.pw_gid;
2087 /* Set dir and shell from environment variables. */
2088 if (w32_unicode_filenames)
2090 wchar_t *home = _wgetenv (L"HOME");
2091 wchar_t *shell = _wgetenv (L"SHELL");
2093 /* Ensure HOME and SHELL are defined. */
2094 if (home == NULL)
2095 emacs_abort ();
2096 if (shell == NULL)
2097 emacs_abort ();
2098 filename_from_utf16 (home, dflt_passwd.pw_dir);
2099 filename_from_utf16 (shell, dflt_passwd.pw_shell);
2101 else
2103 char *home = getenv ("HOME");
2104 char *shell = getenv ("SHELL");
2106 if (home == NULL)
2107 emacs_abort ();
2108 if (shell == NULL)
2109 emacs_abort ();
2110 filename_from_ansi (home, dflt_passwd.pw_dir);
2111 filename_from_ansi (shell, dflt_passwd.pw_shell);
2114 xfree (buf);
2115 if (token)
2116 CloseHandle (token);
2119 static HCRYPTPROV w32_crypto_hprov;
2120 static int
2121 w32_init_crypt_random (void)
2123 if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL,
2124 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2126 DebPrint (("CryptAcquireContext failed with error %x\n",
2127 GetLastError ()));
2128 w32_crypto_hprov = 0;
2129 return -1;
2131 return 0;
2135 w32_init_random (void *buf, ptrdiff_t buflen)
2137 if (!w32_crypto_hprov)
2138 w32_init_crypt_random ();
2139 if (w32_crypto_hprov)
2141 if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf))
2142 return 0;
2144 return -1;
2148 random (void)
2150 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
2151 return ((rand () << 15) | rand ());
2154 void
2155 srandom (int seed)
2157 srand (seed);
2160 /* Return the maximum length in bytes of a multibyte character
2161 sequence encoded in the current ANSI codepage. This is required to
2162 correctly walk the encoded file names one character at a time. */
2163 static int
2164 max_filename_mbslen (void)
2166 CPINFO cp_info;
2168 codepage_for_filenames (&cp_info);
2169 return cp_info.MaxCharSize;
2172 /* Normalize filename by converting in-place all of its path
2173 separators to the separator specified by PATH_SEP. */
2175 static void
2176 normalize_filename (register char *fp, char path_sep)
2178 char *p2;
2180 /* Always lower-case drive letters a-z, even if the filesystem
2181 preserves case in filenames.
2182 This is so filenames can be compared by string comparison
2183 functions that are case-sensitive. Even case-preserving filesystems
2184 do not distinguish case in drive letters. */
2185 p2 = fp + 1;
2187 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2189 *fp += 'a' - 'A';
2190 fp += 2;
2193 while (*fp)
2195 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2196 *fp = path_sep;
2197 fp++;
2201 /* Destructively turn backslashes into slashes. */
2202 void
2203 dostounix_filename (register char *p)
2205 normalize_filename (p, '/');
2208 /* Destructively turn slashes into backslashes. */
2209 void
2210 unixtodos_filename (register char *p)
2212 normalize_filename (p, '\\');
2215 /* Remove all CR's that are followed by a LF.
2216 (From msdos.c...probably should figure out a way to share it,
2217 although this code isn't going to ever change.) */
2218 static int
2219 crlf_to_lf (register int n, register char *buf)
2221 unsigned char *np = (unsigned char *)buf;
2222 unsigned char *startp = np;
2223 char *endp = buf + n;
2225 if (n == 0)
2226 return n;
2227 while (buf < endp - 1)
2229 if (*buf == 0x0d)
2231 if (*(++buf) != 0x0a)
2232 *np++ = 0x0d;
2234 else
2235 *np++ = *buf++;
2237 if (buf < endp)
2238 *np++ = *buf++;
2239 return np - startp;
2242 /* Parse the root part of file name, if present. Return length and
2243 optionally store pointer to char after root. */
2244 static int
2245 parse_root (const char * name, const char ** pPath)
2247 const char * start = name;
2249 if (name == NULL)
2250 return 0;
2252 /* find the root name of the volume if given */
2253 if (isalpha (name[0]) && name[1] == ':')
2255 /* skip past drive specifier */
2256 name += 2;
2257 if (IS_DIRECTORY_SEP (name[0]))
2258 name++;
2260 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2262 int slashes = 2;
2264 name += 2;
2267 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2268 break;
2269 name++;
2271 while ( *name );
2272 if (IS_DIRECTORY_SEP (name[0]))
2273 name++;
2276 if (pPath)
2277 *pPath = name;
2279 return name - start;
2282 /* Get long base name for name; name is assumed to be absolute. */
2283 static int
2284 get_long_basename (char * name, char * buf, int size)
2286 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2287 char fname_utf8[MAX_UTF8_PATH];
2288 int len = 0;
2289 int cstatus = -1;
2291 /* Must be valid filename, no wild cards or other invalid characters. */
2292 if (strpbrk (name, "*?|<>\""))
2293 return 0;
2295 if (w32_unicode_filenames)
2297 wchar_t fname_utf16[MAX_PATH];
2298 WIN32_FIND_DATAW find_data_wide;
2300 filename_to_utf16 (name, fname_utf16);
2301 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2302 if (dir_handle != INVALID_HANDLE_VALUE)
2303 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2305 else
2307 char fname_ansi[MAX_PATH];
2308 WIN32_FIND_DATAA find_data_ansi;
2310 filename_to_ansi (name, fname_ansi);
2311 /* If the ANSI name includes ? characters, it is not encodable
2312 in the ANSI codepage. In that case, we deliver the question
2313 marks to the caller; calling FindFirstFileA in this case
2314 could return some unrelated file name in the same
2315 directory. */
2316 if (_mbspbrk (fname_ansi, "?"))
2318 /* Find the basename of fname_ansi. */
2319 char *p = strrchr (fname_ansi, '\\');
2321 if (!p)
2322 p = fname_ansi;
2323 else
2324 p++;
2325 cstatus = filename_from_ansi (p, fname_utf8);
2327 else
2329 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2330 if (dir_handle != INVALID_HANDLE_VALUE)
2331 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2335 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2336 memcpy (buf, fname_utf8, len + 1);
2337 else
2338 len = 0;
2340 if (dir_handle != INVALID_HANDLE_VALUE)
2341 FindClose (dir_handle);
2343 return len;
2346 /* Get long name for file, if possible (assumed to be absolute). */
2347 BOOL
2348 w32_get_long_filename (const char * name, char * buf, int size)
2350 char * o = buf;
2351 char * p;
2352 const char * q;
2353 char full[ MAX_UTF8_PATH ];
2354 int len;
2356 len = strlen (name);
2357 if (len >= MAX_UTF8_PATH)
2358 return FALSE;
2360 /* Use local copy for destructive modification. */
2361 memcpy (full, name, len+1);
2362 unixtodos_filename (full);
2364 /* Copy root part verbatim. */
2365 len = parse_root (full, (const char **)&p);
2366 memcpy (o, full, len);
2367 o += len;
2368 *o = '\0';
2369 size -= len;
2371 while (p != NULL && *p)
2373 q = p;
2374 p = strchr (q, '\\');
2375 if (p) *p = '\0';
2376 len = get_long_basename (full, o, size);
2377 if (len > 0)
2379 o += len;
2380 size -= len;
2381 if (p != NULL)
2383 *p++ = '\\';
2384 if (size < 2)
2385 return FALSE;
2386 *o++ = '\\';
2387 size--;
2388 *o = '\0';
2391 else
2392 return FALSE;
2395 return TRUE;
2398 unsigned int
2399 w32_get_short_filename (const char * name, char * buf, int size)
2401 if (w32_unicode_filenames)
2403 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2404 unsigned int retval;
2406 filename_to_utf16 (name, name_utf16);
2407 retval = GetShortPathNameW (name_utf16, short_name, size);
2408 if (retval && retval < size)
2409 filename_from_utf16 (short_name, buf);
2410 return retval;
2412 else
2414 char name_ansi[MAX_PATH];
2416 filename_to_ansi (name, name_ansi);
2417 return GetShortPathNameA (name_ansi, buf, size);
2421 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2422 MS-Windows ANSI codepage. If FILENAME includes characters not
2423 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2424 if it exists. This is needed because the w32 build wants to
2425 support file names outside of the system locale, but image
2426 libraries typically don't support wide (a.k.a. "Unicode") APIs
2427 required for that. */
2429 Lisp_Object
2430 ansi_encode_filename (Lisp_Object filename)
2432 Lisp_Object encoded_filename;
2433 char fname[MAX_PATH];
2435 filename_to_ansi (SSDATA (filename), fname);
2436 if (_mbspbrk (fname, "?"))
2438 char shortname[MAX_PATH];
2440 if (w32_get_short_filename (SSDATA (filename), shortname, MAX_PATH))
2442 dostounix_filename (shortname);
2443 encoded_filename = build_string (shortname);
2445 else
2446 encoded_filename = build_unibyte_string (fname);
2448 else
2449 encoded_filename = build_unibyte_string (fname);
2450 return encoded_filename;
2453 static int
2454 is_unc_volume (const char *filename)
2456 const char *ptr = filename;
2458 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2459 return 0;
2461 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2462 return 0;
2464 return 1;
2467 /* Emulate the Posix unsetenv. */
2469 unsetenv (const char *name)
2471 char *var;
2472 size_t name_len;
2474 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2476 errno = EINVAL;
2477 return -1;
2479 name_len = strlen (name);
2480 /* MS docs says an environment variable cannot be longer than 32K. */
2481 if (name_len > 32767)
2483 errno = ENOMEM;
2484 return 0;
2486 /* It is safe to use 'alloca' with 32K size, since the stack is at
2487 least 2MB, and we set it to 8MB in the link command line. */
2488 var = alloca (name_len + 2);
2489 strncpy (var, name, name_len);
2490 var[name_len++] = '=';
2491 var[name_len] = '\0';
2492 return _putenv (var);
2495 /* MS _putenv doesn't support removing a variable when the argument
2496 does not include the '=' character, so we fix that here. */
2498 sys_putenv (char *str)
2500 const char *const name_end = strchr (str, '=');
2502 if (name_end == NULL)
2504 /* Remove the variable from the environment. */
2505 return unsetenv (str);
2508 if (strncmp (str, "TZ=<", 4) == 0)
2510 /* MS-Windows does not support POSIX.1-2001 angle-bracket TZ
2511 abbreviation syntax. Convert to POSIX.1-1988 syntax if possible,
2512 and to the undocumented placeholder "ZZZ" otherwise. */
2513 bool supported_abbr = true;
2514 for (char *p = str + 4; *p; p++)
2516 if (('0' <= *p && *p <= '9') || *p == '-' || *p == '+')
2517 supported_abbr = false;
2518 else if (*p == '>')
2520 ptrdiff_t abbrlen;
2521 if (supported_abbr)
2523 abbrlen = p - (str + 4);
2524 memmove (str + 3, str + 4, abbrlen);
2526 else
2528 abbrlen = 3;
2529 memset (str + 3, 'Z', abbrlen);
2531 memmove (str + 3 + abbrlen, p + 1, strlen (p));
2532 break;
2537 return _putenv (str);
2540 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2542 LPBYTE
2543 w32_get_resource (const char *key, LPDWORD lpdwtype)
2545 LPBYTE lpvalue;
2546 HKEY hrootkey = NULL;
2547 DWORD cbData;
2549 /* Check both the current user and the local machine to see if
2550 we have any resources. */
2552 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2554 lpvalue = NULL;
2556 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2557 && (lpvalue = xmalloc (cbData)) != NULL
2558 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2560 RegCloseKey (hrootkey);
2561 return (lpvalue);
2564 xfree (lpvalue);
2566 RegCloseKey (hrootkey);
2569 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2571 lpvalue = NULL;
2573 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2574 && (lpvalue = xmalloc (cbData)) != NULL
2575 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2577 RegCloseKey (hrootkey);
2578 return (lpvalue);
2581 xfree (lpvalue);
2583 RegCloseKey (hrootkey);
2586 return (NULL);
2589 /* The argv[] array holds ANSI-encoded strings, and so this function
2590 works with ANS_encoded strings. */
2591 void
2592 init_environment (char ** argv)
2594 static const char * const tempdirs[] = {
2595 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2598 int i;
2600 const int imax = ARRAYELTS (tempdirs);
2602 /* Implementation note: This function explicitly works with ANSI
2603 file names, not with UTF-8 encoded file names. This is because
2604 this function pushes variables into the Emacs's environment, and
2605 the environment variables are always assumed to be in the
2606 locale-specific encoding. Do NOT call any functions that accept
2607 UTF-8 file names from this function! */
2609 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2610 temporary files and assume "/tmp" if $TMPDIR is unset, which
2611 will break on DOS/Windows. Refuse to work if we cannot find
2612 a directory, not even "c:/", usable for that purpose. */
2613 for (i = 0; i < imax ; i++)
2615 const char *tmp = tempdirs[i];
2617 if (*tmp == '$')
2618 tmp = getenv (tmp + 1);
2619 /* Note that `access' can lie to us if the directory resides on a
2620 read-only filesystem, like CD-ROM or a write-protected floppy.
2621 The only way to be really sure is to actually create a file and
2622 see if it succeeds. But I think that's too much to ask. */
2624 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2625 if (tmp && sys_access (tmp, D_OK) == 0)
2627 char * var = alloca (strlen (tmp) + 8);
2628 sprintf (var, "TMPDIR=%s", tmp);
2629 _putenv (strdup (var));
2630 break;
2633 if (i >= imax)
2634 cmd_error_internal
2635 (Fcons (Qerror,
2636 Fcons (build_string ("no usable temporary directories found!!"),
2637 Qnil)),
2638 "While setting TMPDIR: ");
2640 /* Check for environment variables and use registry settings if they
2641 don't exist. Fallback on default values where applicable. */
2643 int i;
2644 LPBYTE lpval;
2645 DWORD dwType;
2646 char locale_name[32];
2647 char default_home[MAX_PATH];
2648 int appdata = 0;
2650 static const struct env_entry
2652 const char * name;
2653 const char * def_value;
2654 } dflt_envvars[] =
2656 /* If the default value is NULL, we will use the value from the
2657 outside environment or the Registry, but will not push the
2658 variable into the Emacs environment if it is defined neither
2659 in the Registry nor in the outside environment. */
2660 {"HOME", "C:/"},
2661 {"PRELOAD_WINSOCK", NULL},
2662 {"emacs_dir", "C:/emacs"},
2663 {"EMACSLOADPATH", NULL},
2664 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2665 {"EMACSDATA", NULL},
2666 {"EMACSPATH", NULL},
2667 {"INFOPATH", NULL},
2668 {"EMACSDOC", NULL},
2669 {"TERM", "cmd"},
2670 {"LANG", NULL},
2673 #define N_ENV_VARS ARRAYELTS (dflt_envvars)
2675 /* We need to copy dflt_envvars[] and work on the copy because we
2676 don't want the dumped Emacs to inherit the values of
2677 environment variables we saw during dumping (which could be on
2678 a different system). The defaults above must be left intact. */
2679 struct env_entry env_vars[N_ENV_VARS];
2681 for (i = 0; i < N_ENV_VARS; i++)
2682 env_vars[i] = dflt_envvars[i];
2684 /* For backwards compatibility, check if a .emacs file exists in C:/
2685 If not, then we can try to default to the appdata directory under the
2686 user's profile, which is more likely to be writable. */
2687 if (sys_access ("C:/.emacs", F_OK) != 0)
2689 HRESULT profile_result;
2690 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2691 of Windows 95 and NT4 that have not been updated to include
2692 MSIE 5. */
2693 ShGetFolderPath_fn get_folder_path;
2694 get_folder_path = (ShGetFolderPath_fn)
2695 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2697 if (get_folder_path != NULL)
2699 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2700 0, default_home);
2702 /* If we can't get the appdata dir, revert to old behavior. */
2703 if (profile_result == S_OK)
2705 env_vars[0].def_value = default_home;
2706 appdata = 1;
2711 /* Get default locale info and use it for LANG. */
2712 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2713 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2714 locale_name, sizeof (locale_name)))
2716 for (i = 0; i < N_ENV_VARS; i++)
2718 if (strcmp (env_vars[i].name, "LANG") == 0)
2720 env_vars[i].def_value = locale_name;
2721 break;
2726 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2728 /* Treat emacs_dir specially: set it unconditionally based on our
2729 location. */
2731 char *p;
2732 char modname[MAX_PATH];
2734 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2735 emacs_abort ();
2736 if ((p = _mbsrchr (modname, '\\')) == NULL)
2737 emacs_abort ();
2738 *p = 0;
2740 if ((p = _mbsrchr (modname, '\\'))
2741 /* From bin means installed Emacs, from src means uninstalled. */
2742 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2744 char buf[SET_ENV_BUF_SIZE];
2745 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2747 *p = 0;
2748 for (p = modname; *p; p = CharNext (p))
2749 if (*p == '\\') *p = '/';
2751 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2752 _putenv (strdup (buf));
2753 /* If we are running from the Posix-like build tree, define
2754 SHELL to point to our own cmdproxy. The loop below will
2755 then disregard PATH_EXEC and the default value. */
2756 if (within_build_tree)
2758 _snprintf (buf, sizeof (buf) - 1,
2759 "SHELL=%s/nt/cmdproxy.exe", modname);
2760 _putenv (strdup (buf));
2765 for (i = 0; i < N_ENV_VARS; i++)
2767 if (!getenv (env_vars[i].name))
2769 int dont_free = 0;
2770 char bufc[SET_ENV_BUF_SIZE];
2772 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2773 /* Also ignore empty environment variables. */
2774 || *lpval == 0)
2776 xfree (lpval);
2777 dont_free = 1;
2778 if (strcmp (env_vars[i].name, "SHELL") == 0)
2780 /* Look for cmdproxy.exe in every directory in
2781 PATH_EXEC. FIXME: This does not find cmdproxy
2782 in nt/ when we run uninstalled. */
2783 char fname[MAX_PATH];
2784 const char *pstart = PATH_EXEC, *pend;
2786 do {
2787 pend = _mbschr (pstart, ';');
2788 if (!pend)
2789 pend = pstart + strlen (pstart);
2790 /* Be defensive against series of ;;; characters. */
2791 if (pend > pstart)
2793 strncpy (fname, pstart, pend - pstart);
2794 fname[pend - pstart] = '/';
2795 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2796 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2797 sizeof (bufc));
2798 if (sys_access (bufc, F_OK) == 0)
2800 lpval = bufc;
2801 dwType = REG_SZ;
2802 break;
2805 if (*pend)
2806 pstart = pend + 1;
2807 else
2808 pstart = pend;
2809 if (!*pstart)
2811 /* If not found in any directory, use the
2812 default as the last resort. */
2813 lpval = (char *)env_vars[i].def_value;
2814 dwType = REG_EXPAND_SZ;
2816 } while (*pstart);
2818 else
2820 lpval = (char *)env_vars[i].def_value;
2821 dwType = REG_EXPAND_SZ;
2823 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2824 Vdelayed_warnings_list
2825 = Fcons (listn (CONSTYPE_HEAP, 2,
2826 intern ("initialization"),
2827 build_string ("Setting HOME to C:\\ by default is deprecated")),
2828 Vdelayed_warnings_list);
2831 if (lpval)
2833 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2835 if (dwType == REG_EXPAND_SZ)
2836 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2837 else if (dwType == REG_SZ)
2838 strcpy (buf1, (char *)lpval);
2839 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2841 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2842 buf1);
2843 _putenv (strdup (buf2));
2846 if (!dont_free)
2847 xfree (lpval);
2853 /* Rebuild system configuration to reflect invoking system. */
2854 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2856 /* Another special case: on NT, the PATH variable is actually named
2857 "Path" although cmd.exe (perhaps NT itself) arranges for
2858 environment variable lookup and setting to be case insensitive.
2859 However, Emacs assumes a fully case sensitive environment, so we
2860 need to change "Path" to "PATH" to match the expectations of
2861 various elisp packages. We do this by the sneaky method of
2862 modifying the string in the C runtime environ entry.
2864 The same applies to COMSPEC. */
2866 char ** envp;
2868 for (envp = environ; *envp; envp++)
2869 if (_strnicmp (*envp, "PATH=", 5) == 0)
2870 memcpy (*envp, "PATH=", 5);
2871 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
2872 memcpy (*envp, "COMSPEC=", 8);
2875 /* Remember the initial working directory for getcwd. */
2876 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2877 Does it matter anywhere in Emacs? */
2878 if (w32_unicode_filenames)
2880 wchar_t wstartup_dir[MAX_PATH];
2882 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2883 emacs_abort ();
2884 filename_from_utf16 (wstartup_dir, startup_dir);
2886 else
2888 char astartup_dir[MAX_PATH];
2890 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2891 emacs_abort ();
2892 filename_from_ansi (astartup_dir, startup_dir);
2896 static char modname[MAX_PATH];
2898 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2899 emacs_abort ();
2900 argv[0] = modname;
2903 /* Determine if there is a middle mouse button, to allow parse_button
2904 to decide whether right mouse events should be mouse-2 or
2905 mouse-3. */
2906 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2908 init_user_info ();
2911 /* Called from expand-file-name when default-directory is not a string. */
2913 char *
2914 emacs_root_dir (void)
2916 static char root_dir[MAX_UTF8_PATH];
2917 const char *p;
2919 p = getenv ("emacs_dir");
2920 if (p == NULL)
2921 emacs_abort ();
2922 filename_from_ansi (p, root_dir);
2923 root_dir[parse_root (root_dir, NULL)] = '\0';
2924 dostounix_filename (root_dir);
2925 return root_dir;
2928 #include <sys/timeb.h>
2930 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2932 gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
2934 struct _timeb tb;
2935 _ftime (&tb);
2937 tv->tv_sec = tb.time;
2938 tv->tv_usec = tb.millitm * 1000L;
2939 /* Implementation note: _ftime sometimes doesn't update the dstflag
2940 according to the new timezone when the system timezone is
2941 changed. We could fix that by using GetSystemTime and
2942 GetTimeZoneInformation, but that doesn't seem necessary, since
2943 Emacs always calls gettimeofday with the 2nd argument NULL (see
2944 current_emacs_time). */
2945 if (tz)
2947 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2948 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2950 return 0;
2953 /* Emulate fdutimens. */
2955 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2956 TIMESPEC[0] and TIMESPEC[1], respectively.
2957 FD must be either negative -- in which case it is ignored --
2958 or a file descriptor that is open on FILE.
2959 If FD is nonnegative, then FILE can be NULL, which means
2960 use just futimes instead of utimes.
2961 If TIMESPEC is null, FAIL.
2962 Return 0 on success, -1 (setting errno) on failure. */
2965 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2967 if (!timespec)
2969 errno = ENOSYS;
2970 return -1;
2972 if (fd < 0 && !file)
2974 errno = EBADF;
2975 return -1;
2977 /* _futime's prototype defines 2nd arg as having the type 'struct
2978 _utimbuf', while utime needs to accept 'struct utimbuf' for
2979 compatibility with Posix. So we need to use 2 different (but
2980 equivalent) types to avoid compiler warnings, sigh. */
2981 if (fd >= 0)
2983 struct _utimbuf _ut;
2985 _ut.actime = timespec[0].tv_sec;
2986 _ut.modtime = timespec[1].tv_sec;
2987 return _futime (fd, &_ut);
2989 else
2991 struct utimbuf ut;
2993 ut.actime = timespec[0].tv_sec;
2994 ut.modtime = timespec[1].tv_sec;
2995 /* Call 'utime', which is implemented below, not the MS library
2996 function, which fails on directories. */
2997 return utime (file, &ut);
3002 /* ------------------------------------------------------------------------- */
3003 /* IO support and wrapper functions for the Windows API. */
3004 /* ------------------------------------------------------------------------- */
3006 /* Place a wrapper around the MSVC version of ctime. It returns NULL
3007 on network directories, so we handle that case here.
3008 (Ulrich Leodolter, 1/11/95). */
3009 char *
3010 sys_ctime (const time_t *t)
3012 char *str = (char *) ctime (t);
3013 return (str ? str : (char *)"Sun Jan 01 00:00:00 1970");
3016 /* Emulate sleep...we could have done this with a define, but that
3017 would necessitate including windows.h in the files that used it.
3018 This is much easier. */
3019 void
3020 sys_sleep (int seconds)
3022 Sleep (seconds * 1000);
3025 /* Internal MSVC functions for low-level descriptor munging */
3026 extern int __cdecl _set_osfhnd (int fd, long h);
3027 extern int __cdecl _free_osfhnd (int fd);
3029 /* parallel array of private info on file handles */
3030 filedesc fd_info [ MAXDESC ];
3032 typedef struct volume_info_data {
3033 struct volume_info_data * next;
3035 /* time when info was obtained */
3036 DWORD timestamp;
3038 /* actual volume info */
3039 char * root_dir;
3040 DWORD serialnum;
3041 DWORD maxcomp;
3042 DWORD flags;
3043 char * name;
3044 char * type;
3045 } volume_info_data;
3047 /* Global referenced by various functions. */
3048 static volume_info_data volume_info;
3050 /* Vector to indicate which drives are local and fixed (for which cached
3051 data never expires). */
3052 static BOOL fixed_drives[26];
3054 /* Consider cached volume information to be stale if older than 10s,
3055 at least for non-local drives. Info for fixed drives is never stale. */
3056 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
3057 #define VOLINFO_STILL_VALID( root_dir, info ) \
3058 ( ( isalpha (root_dir[0]) && \
3059 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
3060 || GetTickCount () - info->timestamp < 10000 )
3062 /* Cache support functions. */
3064 /* Simple linked list with linear search is sufficient. */
3065 static volume_info_data *volume_cache = NULL;
3067 static volume_info_data *
3068 lookup_volume_info (char * root_dir)
3070 volume_info_data * info;
3072 for (info = volume_cache; info; info = info->next)
3073 if (xstrcasecmp (info->root_dir, root_dir) == 0)
3074 break;
3075 return info;
3078 static void
3079 add_volume_info (char * root_dir, volume_info_data * info)
3081 info->root_dir = xstrdup (root_dir);
3082 unixtodos_filename (info->root_dir);
3083 info->next = volume_cache;
3084 volume_cache = info;
3088 /* Wrapper for GetVolumeInformation, which uses caching to avoid
3089 performance penalty (~2ms on 486 for local drives, 7.5ms for local
3090 cdrom drive, ~5-10ms or more for remote drives on LAN). */
3091 static volume_info_data *
3092 GetCachedVolumeInformation (char * root_dir)
3094 volume_info_data * info;
3095 char default_root[ MAX_UTF8_PATH ];
3096 char name[MAX_PATH+1];
3097 char type[MAX_PATH+1];
3099 /* NULL for root_dir means use root from current directory. */
3100 if (root_dir == NULL)
3102 if (w32_unicode_filenames)
3104 wchar_t curdirw[MAX_PATH];
3106 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
3107 return NULL;
3108 filename_from_utf16 (curdirw, default_root);
3110 else
3112 char curdira[MAX_PATH];
3114 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
3115 return NULL;
3116 filename_from_ansi (curdira, default_root);
3118 parse_root (default_root, (const char **)&root_dir);
3119 *root_dir = 0;
3120 root_dir = default_root;
3123 /* Local fixed drives can be cached permanently. Removable drives
3124 cannot be cached permanently, since the volume name and serial
3125 number (if nothing else) can change. Remote drives should be
3126 treated as if they are removable, since there is no sure way to
3127 tell whether they are or not. Also, the UNC association of drive
3128 letters mapped to remote volumes can be changed at any time (even
3129 by other processes) without notice.
3131 As a compromise, so we can benefit from caching info for remote
3132 volumes, we use a simple expiry mechanism to invalidate cache
3133 entries that are more than ten seconds old. */
3135 #if 0
3136 /* No point doing this, because WNetGetConnection is even slower than
3137 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
3138 GetDriveType is about the only call of this type which does not
3139 involve network access, and so is extremely quick). */
3141 /* Map drive letter to UNC if remote. */
3142 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
3144 char remote_name[ 256 ];
3145 char drive[3] = { root_dir[0], ':' };
3147 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
3148 == NO_ERROR)
3149 /* do something */ ;
3151 #endif
3153 info = lookup_volume_info (root_dir);
3155 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
3157 DWORD serialnum;
3158 DWORD maxcomp;
3159 DWORD flags;
3161 /* Info is not cached, or is stale. */
3162 if (w32_unicode_filenames)
3164 wchar_t root_w[MAX_PATH];
3165 wchar_t name_w[MAX_PATH+1];
3166 wchar_t type_w[MAX_PATH+1];
3168 filename_to_utf16 (root_dir, root_w);
3169 if (!GetVolumeInformationW (root_w,
3170 name_w, sizeof (name_w),
3171 &serialnum,
3172 &maxcomp,
3173 &flags,
3174 type_w, sizeof (type_w)))
3175 return NULL;
3176 /* Hmm... not really 100% correct, as these 2 are not file
3177 names... */
3178 filename_from_utf16 (name_w, name);
3179 filename_from_utf16 (type_w, type);
3181 else
3183 char root_a[MAX_PATH];
3184 char name_a[MAX_PATH+1];
3185 char type_a[MAX_PATH+1];
3187 filename_to_ansi (root_dir, root_a);
3188 if (!GetVolumeInformationA (root_a,
3189 name_a, sizeof (name_a),
3190 &serialnum,
3191 &maxcomp,
3192 &flags,
3193 type_a, sizeof (type_a)))
3194 return NULL;
3195 filename_from_ansi (name_a, name);
3196 filename_from_ansi (type_a, type);
3199 /* Cache the volume information for future use, overwriting existing
3200 entry if present. */
3201 if (info == NULL)
3203 info = xmalloc (sizeof (volume_info_data));
3204 add_volume_info (root_dir, info);
3206 else
3208 xfree (info->name);
3209 xfree (info->type);
3212 info->name = xstrdup (name);
3213 unixtodos_filename (info->name);
3214 info->serialnum = serialnum;
3215 info->maxcomp = maxcomp;
3216 info->flags = flags;
3217 info->type = xstrdup (type);
3218 info->timestamp = GetTickCount ();
3221 return info;
3224 /* Get information on the volume where NAME is held; set path pointer to
3225 start of pathname in NAME (past UNC header\volume header if present),
3226 if pPath is non-NULL.
3228 Note: if NAME includes symlinks, the information is for the volume
3229 of the symlink, not of its target. That's because, even though
3230 GetVolumeInformation returns information about the symlink target
3231 of its argument, we only pass the root directory to
3232 GetVolumeInformation, not the full NAME. */
3233 static int
3234 get_volume_info (const char * name, const char ** pPath)
3236 char temp[MAX_UTF8_PATH];
3237 char *rootname = NULL; /* default to current volume */
3238 volume_info_data * info;
3239 int root_len = parse_root (name, pPath);
3241 if (name == NULL)
3242 return FALSE;
3244 /* Copy the root name of the volume, if given. */
3245 if (root_len)
3247 strncpy (temp, name, root_len);
3248 temp[root_len] = '\0';
3249 unixtodos_filename (temp);
3250 rootname = temp;
3253 info = GetCachedVolumeInformation (rootname);
3254 if (info != NULL)
3256 /* Set global referenced by other functions. */
3257 volume_info = *info;
3258 return TRUE;
3260 return FALSE;
3263 /* Determine if volume is FAT format (ie. only supports short 8.3
3264 names); also set path pointer to start of pathname in name, if
3265 pPath is non-NULL. */
3266 static int
3267 is_fat_volume (const char * name, const char ** pPath)
3269 if (get_volume_info (name, pPath))
3270 return (volume_info.maxcomp == 12);
3271 return FALSE;
3274 /* Convert all slashes in a filename to backslashes, and map filename
3275 to a valid 8.3 name if necessary. The result is a pointer to a
3276 static buffer, so CAVEAT EMPTOR! */
3277 const char *map_w32_filename (const char *, const char **);
3279 const char *
3280 map_w32_filename (const char * name, const char ** pPath)
3282 static char shortname[MAX_UTF8_PATH];
3283 char * str = shortname;
3284 char c;
3285 char * path;
3286 const char * save_name = name;
3288 if (strlen (name) >= sizeof (shortname))
3290 /* Return a filename which will cause callers to fail. */
3291 strcpy (shortname, "?");
3292 return shortname;
3295 if (!fatal_error_in_progress /* disable fancy processing during crash */
3296 && is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3298 register int left = 8; /* maximum number of chars in part */
3299 register int extn = 0; /* extension added? */
3300 register int dots = 2; /* maximum number of dots allowed */
3302 while (name < path)
3303 *str++ = *name++; /* skip past UNC header */
3305 while ((c = *name++))
3307 switch ( c )
3309 case ':':
3310 case '\\':
3311 case '/':
3312 *str++ = (c == ':' ? ':' : '\\');
3313 extn = 0; /* reset extension flags */
3314 dots = 2; /* max 2 dots */
3315 left = 8; /* max length 8 for main part */
3316 break;
3317 case '.':
3318 if ( dots )
3320 /* Convert path components of the form .xxx to _xxx,
3321 but leave . and .. as they are. This allows .emacs
3322 to be read as _emacs, for example. */
3324 if (! *name ||
3325 *name == '.' ||
3326 IS_DIRECTORY_SEP (*name))
3328 *str++ = '.';
3329 dots--;
3331 else
3333 *str++ = '_';
3334 left--;
3335 dots = 0;
3338 else if ( !extn )
3340 *str++ = '.';
3341 extn = 1; /* we've got an extension */
3342 left = 3; /* 3 chars in extension */
3344 else
3346 /* any embedded dots after the first are converted to _ */
3347 *str++ = '_';
3349 break;
3350 case '~':
3351 case '#': /* don't lose these, they're important */
3352 if ( ! left )
3353 str[-1] = c; /* replace last character of part */
3354 /* FALLTHRU */
3355 default:
3356 if ( left && 'A' <= c && c <= 'Z' )
3358 *str++ = tolower (c); /* map to lower case (looks nicer) */
3359 left--;
3360 dots = 0; /* started a path component */
3362 break;
3365 *str = '\0';
3367 else
3369 strcpy (shortname, name);
3370 unixtodos_filename (shortname);
3373 if (pPath)
3374 *pPath = shortname + (path - save_name);
3376 return shortname;
3379 static int
3380 is_exec (const char * name)
3382 char * p = strrchr (name, '.');
3383 return
3384 (p != NULL
3385 && (xstrcasecmp (p, ".exe") == 0 ||
3386 xstrcasecmp (p, ".com") == 0 ||
3387 xstrcasecmp (p, ".bat") == 0 ||
3388 xstrcasecmp (p, ".cmd") == 0));
3391 /* Emulate the Unix directory procedures opendir, closedir, and
3392 readdir. We rename them to sys_* names because some versions of
3393 MinGW startup code call opendir and readdir to glob wildcards, and
3394 the code that calls them doesn't grok UTF-8 encoded file names we
3395 produce in dirent->d_name[]. */
3397 struct dirent dir_static; /* simulated directory contents */
3398 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3399 static int dir_is_fat;
3400 static char dir_pathname[MAX_UTF8_PATH];
3401 static WIN32_FIND_DATAW dir_find_data_w;
3402 static WIN32_FIND_DATAA dir_find_data_a;
3403 #define DIR_FIND_DATA_W 1
3404 #define DIR_FIND_DATA_A 2
3405 static int last_dir_find_data = -1;
3407 /* Support shares on a network resource as subdirectories of a read-only
3408 root directory. */
3409 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3410 static HANDLE open_unc_volume (const char *);
3411 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3412 static void close_unc_volume (HANDLE);
3414 DIR *
3415 sys_opendir (const char *filename)
3417 DIR *dirp;
3419 /* Opening is done by FindFirstFile. However, a read is inherent to
3420 this operation, so we defer the open until read time. */
3422 if (dir_find_handle != INVALID_HANDLE_VALUE)
3423 return NULL;
3424 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3425 return NULL;
3427 /* Note: We don't support traversal of UNC volumes via symlinks.
3428 Doing so would mean punishing 99.99% of use cases by resolving
3429 all the possible symlinks in FILENAME, recursively. */
3430 if (is_unc_volume (filename))
3432 wnet_enum_handle = open_unc_volume (filename);
3433 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3434 return NULL;
3437 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3438 return NULL;
3440 dirp->dd_fd = 0;
3441 dirp->dd_loc = 0;
3442 dirp->dd_size = 0;
3444 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3445 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3446 /* Note: We don't support symlinks to file names on FAT volumes.
3447 Doing so would mean punishing 99.99% of use cases by resolving
3448 all the possible symlinks in FILENAME, recursively. */
3449 dir_is_fat = is_fat_volume (filename, NULL);
3451 return dirp;
3454 void
3455 sys_closedir (DIR *dirp)
3457 /* If we have a find-handle open, close it. */
3458 if (dir_find_handle != INVALID_HANDLE_VALUE)
3460 FindClose (dir_find_handle);
3461 dir_find_handle = INVALID_HANDLE_VALUE;
3463 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3465 close_unc_volume (wnet_enum_handle);
3466 wnet_enum_handle = INVALID_HANDLE_VALUE;
3468 xfree ((char *) dirp);
3471 struct dirent *
3472 sys_readdir (DIR *dirp)
3474 int downcase = !NILP (Vw32_downcase_file_names);
3476 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3478 if (!read_unc_volume (wnet_enum_handle,
3479 dir_find_data_w.cFileName,
3480 dir_find_data_a.cFileName,
3481 MAX_PATH))
3482 return NULL;
3484 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3485 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3487 char filename[MAX_UTF8_PATH];
3488 int ln;
3489 bool last_slash = true;
3491 /* Note: We don't need to worry about dir_pathname being longer
3492 than MAX_UTF8_PATH, as sys_opendir already took care of that
3493 when it called map_w32_filename: that function will put a "?"
3494 in its return value in that case, thus failing all the calls
3495 below. */
3496 strcpy (filename, dir_pathname);
3497 ln = strlen (filename);
3498 if (!IS_DIRECTORY_SEP (filename[ln - 1]))
3499 last_slash = false;
3501 /* Note: No need to resolve symlinks in FILENAME, because
3502 FindFirst opens the directory that is the target of a
3503 symlink. */
3504 if (w32_unicode_filenames)
3506 wchar_t fnw[MAX_PATH + 2];
3508 filename_to_utf16 (filename, fnw);
3509 if (!last_slash)
3510 wcscat (fnw, L"\\");
3511 wcscat (fnw, L"*");
3512 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3514 else
3516 char fna[MAX_PATH + 2];
3518 filename_to_ansi (filename, fna);
3519 if (!last_slash)
3520 strcat (fna, "\\");
3521 strcat (fna, "*");
3522 /* If FILENAME is not representable by the current ANSI
3523 codepage, we don't want FindFirstFileA to interpret the
3524 '?' characters as a wildcard. */
3525 if (_mbspbrk (fna, "?"))
3526 dir_find_handle = INVALID_HANDLE_VALUE;
3527 else
3528 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3531 if (dir_find_handle == INVALID_HANDLE_VALUE)
3533 /* Any changes in the value of errno here should be in sync
3534 with what directory_files_internal does when it calls
3535 readdir. */
3536 switch (GetLastError ())
3538 /* Windows uses this value when FindFirstFile finds no
3539 files that match the wildcard. This is not supposed
3540 to happen, since our wildcard is "*", but just in
3541 case, if there's some weird empty directory with not
3542 even "." and ".." entries... */
3543 case ERROR_FILE_NOT_FOUND:
3544 errno = 0;
3545 /* FALLTHRU */
3546 default:
3547 break;
3548 case ERROR_ACCESS_DENIED:
3549 case ERROR_NETWORK_ACCESS_DENIED:
3550 errno = EACCES;
3551 break;
3552 case ERROR_PATH_NOT_FOUND:
3553 case ERROR_INVALID_DRIVE:
3554 case ERROR_NOT_READY:
3555 case ERROR_BAD_NETPATH:
3556 case ERROR_BAD_NET_NAME:
3557 errno = ENOENT;
3558 break;
3560 return NULL;
3563 else if (w32_unicode_filenames)
3565 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3567 errno = 0;
3568 return NULL;
3571 else
3573 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3575 errno = 0;
3576 return NULL;
3580 /* Emacs never uses this value, so don't bother making it match
3581 value returned by stat(). */
3582 dir_static.d_ino = 1;
3584 if (w32_unicode_filenames)
3586 if (downcase || dir_is_fat)
3588 wchar_t tem[MAX_PATH];
3590 wcscpy (tem, dir_find_data_w.cFileName);
3591 CharLowerW (tem);
3592 filename_from_utf16 (tem, dir_static.d_name);
3594 else
3595 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3596 last_dir_find_data = DIR_FIND_DATA_W;
3598 else
3600 char tem[MAX_PATH];
3602 /* If the file name in cFileName[] includes `?' characters, it
3603 means the original file name used characters that cannot be
3604 represented by the current ANSI codepage. To avoid total
3605 lossage, retrieve the short 8+3 alias of the long file
3606 name. */
3607 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3609 strcpy (tem, dir_find_data_a.cAlternateFileName);
3610 /* 8+3 aliases are returned in all caps, which could break
3611 various alists that look at filenames' extensions. */
3612 downcase = 1;
3614 else if (downcase || dir_is_fat)
3615 strcpy (tem, dir_find_data_a.cFileName);
3616 else
3617 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3618 if (downcase || dir_is_fat)
3620 _mbslwr (tem);
3621 filename_from_ansi (tem, dir_static.d_name);
3623 last_dir_find_data = DIR_FIND_DATA_A;
3626 dir_static.d_namlen = strlen (dir_static.d_name);
3627 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3628 dir_static.d_namlen - dir_static.d_namlen % 4;
3630 return &dir_static;
3633 static HANDLE
3634 open_unc_volume (const char *path)
3636 const char *fn = map_w32_filename (path, NULL);
3637 DWORD result;
3638 HANDLE henum;
3640 if (w32_unicode_filenames)
3642 NETRESOURCEW nrw;
3643 wchar_t fnw[MAX_PATH];
3645 nrw.dwScope = RESOURCE_GLOBALNET;
3646 nrw.dwType = RESOURCETYPE_DISK;
3647 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3648 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3649 nrw.lpLocalName = NULL;
3650 filename_to_utf16 (fn, fnw);
3651 nrw.lpRemoteName = fnw;
3652 nrw.lpComment = NULL;
3653 nrw.lpProvider = NULL;
3655 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3656 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3658 else
3660 NETRESOURCEA nra;
3661 char fna[MAX_PATH];
3663 nra.dwScope = RESOURCE_GLOBALNET;
3664 nra.dwType = RESOURCETYPE_DISK;
3665 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3666 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3667 nra.lpLocalName = NULL;
3668 filename_to_ansi (fn, fna);
3669 nra.lpRemoteName = fna;
3670 nra.lpComment = NULL;
3671 nra.lpProvider = NULL;
3673 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3674 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3676 if (result == NO_ERROR)
3677 return henum;
3678 else
3680 /* Make sure directory_files_internal reports a sensible error. */
3681 errno = ENOENT;
3682 return INVALID_HANDLE_VALUE;
3686 static void *
3687 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3689 DWORD count;
3690 int result;
3691 char *buffer;
3692 DWORD bufsize = 512;
3693 void *retval;
3695 count = 1;
3696 if (w32_unicode_filenames)
3698 wchar_t *ptrw;
3700 bufsize *= 2;
3701 buffer = alloca (bufsize);
3702 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3703 if (result != NO_ERROR)
3704 return NULL;
3705 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3706 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3707 ptrw += 2;
3708 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3709 ptrw++;
3710 wcsncpy (fname_w, ptrw, size);
3711 retval = fname_w;
3713 else
3715 int dbcs_p = max_filename_mbslen () > 1;
3716 char *ptra;
3718 buffer = alloca (bufsize);
3719 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3720 if (result != NO_ERROR)
3721 return NULL;
3722 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3723 ptra += 2;
3724 if (!dbcs_p)
3725 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3726 else
3728 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3729 ptra = CharNextExA (file_name_codepage, ptra, 0);
3731 ptra++;
3732 strncpy (fname_a, ptra, size);
3733 retval = fname_a;
3736 return retval;
3739 static void
3740 close_unc_volume (HANDLE henum)
3742 if (henum != INVALID_HANDLE_VALUE)
3743 WNetCloseEnum (henum);
3746 static DWORD
3747 unc_volume_file_attributes (const char *path)
3749 HANDLE henum;
3750 DWORD attrs;
3752 henum = open_unc_volume (path);
3753 if (henum == INVALID_HANDLE_VALUE)
3754 return -1;
3756 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3758 close_unc_volume (henum);
3760 return attrs;
3763 /* Ensure a network connection is authenticated. */
3764 static void
3765 logon_network_drive (const char *path)
3767 char share[MAX_UTF8_PATH];
3768 int n_slashes;
3769 char drive[4];
3770 UINT drvtype;
3771 char *p;
3772 DWORD val;
3774 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3775 drvtype = DRIVE_REMOTE;
3776 else if (path[0] == '\0' || path[1] != ':')
3777 drvtype = GetDriveType (NULL);
3778 else
3780 drive[0] = path[0];
3781 drive[1] = ':';
3782 drive[2] = '\\';
3783 drive[3] = '\0';
3784 drvtype = GetDriveType (drive);
3787 /* Only logon to networked drives. */
3788 if (drvtype != DRIVE_REMOTE)
3789 return;
3791 n_slashes = 2;
3792 strncpy (share, path, MAX_UTF8_PATH);
3793 /* Truncate to just server and share name. */
3794 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3796 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3798 *p = '\0';
3799 break;
3803 if (w32_unicode_filenames)
3805 NETRESOURCEW resourcew;
3806 wchar_t share_w[MAX_PATH];
3808 resourcew.dwScope = RESOURCE_GLOBALNET;
3809 resourcew.dwType = RESOURCETYPE_DISK;
3810 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3811 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3812 resourcew.lpLocalName = NULL;
3813 filename_to_utf16 (share, share_w);
3814 resourcew.lpRemoteName = share_w;
3815 resourcew.lpProvider = NULL;
3817 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3819 else
3821 NETRESOURCEA resourcea;
3822 char share_a[MAX_PATH];
3824 resourcea.dwScope = RESOURCE_GLOBALNET;
3825 resourcea.dwType = RESOURCETYPE_DISK;
3826 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3827 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3828 resourcea.lpLocalName = NULL;
3829 filename_to_ansi (share, share_a);
3830 resourcea.lpRemoteName = share_a;
3831 resourcea.lpProvider = NULL;
3833 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3836 switch (val)
3838 case NO_ERROR:
3839 case ERROR_ALREADY_ASSIGNED:
3840 break;
3841 case ERROR_ACCESS_DENIED:
3842 case ERROR_LOGON_FAILURE:
3843 errno = EACCES;
3844 break;
3845 case ERROR_BUSY:
3846 errno = EAGAIN;
3847 break;
3848 case ERROR_BAD_NET_NAME:
3849 case ERROR_NO_NET_OR_BAD_PATH:
3850 case ERROR_NO_NETWORK:
3851 case ERROR_CANCELLED:
3852 default:
3853 errno = ENOENT;
3854 break;
3858 /* Emulate faccessat(2). */
3860 faccessat (int dirfd, const char * path, int mode, int flags)
3862 DWORD attributes;
3864 if (dirfd != AT_FDCWD
3865 && !(IS_DIRECTORY_SEP (path[0])
3866 || IS_DEVICE_SEP (path[1])))
3868 errno = EBADF;
3869 return -1;
3872 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3873 newer versions blow up when passed D_OK. */
3874 path = map_w32_filename (path, NULL);
3875 /* If the last element of PATH is a symlink, we need to resolve it
3876 to get the attributes of its target file. Note: any symlinks in
3877 PATH elements other than the last one are transparently resolved
3878 by GetFileAttributes below. */
3879 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3880 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3881 path = chase_symlinks (path);
3883 if (w32_unicode_filenames)
3885 wchar_t path_w[MAX_PATH];
3887 filename_to_utf16 (path, path_w);
3888 attributes = GetFileAttributesW (path_w);
3890 else
3892 char path_a[MAX_PATH];
3894 filename_to_ansi (path, path_a);
3895 attributes = GetFileAttributesA (path_a);
3898 if (attributes == -1)
3900 DWORD w32err = GetLastError ();
3902 switch (w32err)
3904 case ERROR_INVALID_NAME:
3905 case ERROR_BAD_PATHNAME:
3906 if (is_unc_volume (path))
3908 attributes = unc_volume_file_attributes (path);
3909 if (attributes == -1)
3911 errno = EACCES;
3912 return -1;
3914 goto check_attrs;
3916 /* FALLTHROUGH */
3917 case ERROR_FILE_NOT_FOUND:
3918 case ERROR_BAD_NETPATH:
3919 errno = ENOENT;
3920 break;
3921 default:
3922 errno = EACCES;
3923 break;
3925 return -1;
3928 check_attrs:
3929 if ((mode & X_OK) != 0
3930 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3932 errno = EACCES;
3933 return -1;
3935 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3937 errno = EACCES;
3938 return -1;
3940 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3942 errno = EACCES;
3943 return -1;
3945 return 0;
3948 /* A special test for DIRNAME being a directory accessible by the
3949 current user. This is needed because the security permissions in
3950 directory's ACLs are not visible in the Posix-style mode bits
3951 returned by 'stat' and in attributes returned by GetFileAttributes.
3952 So a directory would seem like it's readable by the current user,
3953 but will in fact error out with EACCES when they actually try. */
3955 w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
3957 char pattern[MAX_UTF8_PATH];
3958 bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
3959 HANDLE dh;
3961 /* Network volumes need a different reading method. */
3962 if (is_unc_volume (dirname))
3964 void *read_result = NULL;
3965 wchar_t fnw[MAX_PATH];
3966 char fna[MAX_PATH];
3968 dh = open_unc_volume (dirname);
3969 if (dh != INVALID_HANDLE_VALUE)
3971 read_result = read_unc_volume (dh, fnw, fna, MAX_PATH);
3972 close_unc_volume (dh);
3974 /* Treat empty volumes as accessible. */
3975 return read_result != NULL || GetLastError () == ERROR_NO_MORE_ITEMS;
3978 /* Note: map_w32_filename makes sure DIRNAME is not longer than
3979 MAX_UTF8_PATH. */
3980 strcpy (pattern, map_w32_filename (dirname, NULL));
3982 /* Note: No need to resolve symlinks in FILENAME, because FindFirst
3983 opens the directory that is the target of a symlink. */
3984 if (w32_unicode_filenames)
3986 wchar_t pat_w[MAX_PATH + 2];
3987 WIN32_FIND_DATAW dfd_w;
3989 filename_to_utf16 (pattern, pat_w);
3990 if (!last_slash)
3991 wcscat (pat_w, L"\\");
3992 wcscat (pat_w, L"*");
3993 dh = FindFirstFileW (pat_w, &dfd_w);
3995 else
3997 char pat_a[MAX_PATH + 2];
3998 WIN32_FIND_DATAA dfd_a;
4000 filename_to_ansi (pattern, pat_a);
4001 if (!last_slash)
4002 strcpy (pat_a, "\\");
4003 strcat (pat_a, "*");
4004 /* In case DIRNAME cannot be expressed in characters from the
4005 current ANSI codepage. */
4006 if (_mbspbrk (pat_a, "?"))
4007 dh = INVALID_HANDLE_VALUE;
4008 else
4009 dh = FindFirstFileA (pat_a, &dfd_a);
4012 if (dh == INVALID_HANDLE_VALUE)
4013 return 0;
4014 FindClose (dh);
4015 return 1;
4018 /* A version of 'access' to be used locally with file names in
4019 locale-specific encoding. Does not resolve symlinks and does not
4020 support file names on FAT12 and FAT16 volumes, but that's OK, since
4021 we only invoke this function for files inside the Emacs source or
4022 installation tree, on directories (so any symlinks should have the
4023 directory bit set), and on short file names such as "C:/.emacs". */
4024 static int
4025 sys_access (const char *fname, int mode)
4027 char fname_copy[MAX_PATH], *p;
4028 DWORD attributes;
4030 strcpy (fname_copy, fname);
4031 /* Do the equivalent of unixtodos_filename. */
4032 for (p = fname_copy; *p; p = CharNext (p))
4033 if (*p == '/')
4034 *p = '\\';
4036 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
4038 DWORD w32err = GetLastError ();
4040 switch (w32err)
4042 case ERROR_INVALID_NAME:
4043 case ERROR_BAD_PATHNAME:
4044 case ERROR_FILE_NOT_FOUND:
4045 case ERROR_BAD_NETPATH:
4046 errno = ENOENT;
4047 break;
4048 default:
4049 errno = EACCES;
4050 break;
4052 return -1;
4054 if ((mode & X_OK) != 0
4055 && !(is_exec (fname_copy)
4056 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
4058 errno = EACCES;
4059 return -1;
4061 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
4063 errno = EACCES;
4064 return -1;
4066 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
4068 errno = EACCES;
4069 return -1;
4071 return 0;
4074 /* Shadow some MSVC runtime functions to map requests for long filenames
4075 to reasonable short names if necessary. This was originally added to
4076 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
4077 long file names. */
4080 sys_chdir (const char * path)
4082 path = map_w32_filename (path, NULL);
4083 if (w32_unicode_filenames)
4085 wchar_t newdir_w[MAX_PATH];
4087 if (filename_to_utf16 (path, newdir_w) == 0)
4088 return _wchdir (newdir_w);
4089 return -1;
4091 else
4093 char newdir_a[MAX_PATH];
4095 if (filename_to_ansi (path, newdir_a) == 0)
4096 return _chdir (newdir_a);
4097 return -1;
4102 sys_chmod (const char * path, int mode)
4104 path = chase_symlinks (map_w32_filename (path, NULL));
4105 if (w32_unicode_filenames)
4107 wchar_t path_w[MAX_PATH];
4109 filename_to_utf16 (path, path_w);
4110 return _wchmod (path_w, mode);
4112 else
4114 char path_a[MAX_PATH];
4116 filename_to_ansi (path, path_a);
4117 return _chmod (path_a, mode);
4122 sys_creat (const char * path, int mode)
4124 path = map_w32_filename (path, NULL);
4125 if (w32_unicode_filenames)
4127 wchar_t path_w[MAX_PATH];
4129 filename_to_utf16 (path, path_w);
4130 return _wcreat (path_w, mode);
4132 else
4134 char path_a[MAX_PATH];
4136 filename_to_ansi (path, path_a);
4137 return _creat (path_a, mode);
4141 FILE *
4142 sys_fopen (const char * path, const char * mode)
4144 int fd;
4145 int oflag;
4146 const char * mode_save = mode;
4148 /* Force all file handles to be non-inheritable. This is necessary to
4149 ensure child processes don't unwittingly inherit handles that might
4150 prevent future file access. */
4152 if (mode[0] == 'r')
4153 oflag = O_RDONLY;
4154 else if (mode[0] == 'w' || mode[0] == 'a')
4155 oflag = O_WRONLY | O_CREAT | O_TRUNC;
4156 else
4157 return NULL;
4159 /* Only do simplistic option parsing. */
4160 while (*++mode)
4161 if (mode[0] == '+')
4163 oflag &= ~(O_RDONLY | O_WRONLY);
4164 oflag |= O_RDWR;
4166 else if (mode[0] == 'b')
4168 oflag &= ~O_TEXT;
4169 oflag |= O_BINARY;
4171 else if (mode[0] == 't')
4173 oflag &= ~O_BINARY;
4174 oflag |= O_TEXT;
4176 else break;
4178 path = map_w32_filename (path, NULL);
4179 if (w32_unicode_filenames)
4181 wchar_t path_w[MAX_PATH];
4183 filename_to_utf16 (path, path_w);
4184 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
4186 else
4188 char path_a[MAX_PATH];
4190 filename_to_ansi (path, path_a);
4191 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
4193 if (fd < 0)
4194 return NULL;
4196 return _fdopen (fd, mode_save);
4199 /* This only works on NTFS volumes, but is useful to have. */
4201 sys_link (const char * old, const char * new)
4203 HANDLE fileh;
4204 int result = -1;
4205 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
4206 wchar_t oldname_w[MAX_PATH];
4207 char oldname_a[MAX_PATH];
4209 if (old == NULL || new == NULL)
4211 errno = ENOENT;
4212 return -1;
4215 strcpy (oldname, map_w32_filename (old, NULL));
4216 strcpy (newname, map_w32_filename (new, NULL));
4218 if (w32_unicode_filenames)
4220 filename_to_utf16 (oldname, oldname_w);
4221 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
4222 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4224 else
4226 filename_to_ansi (oldname, oldname_a);
4227 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
4228 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4230 if (fileh != INVALID_HANDLE_VALUE)
4232 int wlen;
4234 /* Confusingly, the "alternate" stream name field does not apply
4235 when restoring a hard link, and instead contains the actual
4236 stream data for the link (ie. the name of the link to create).
4237 The WIN32_STREAM_ID structure before the cStreamName field is
4238 the stream header, which is then immediately followed by the
4239 stream data. */
4241 struct {
4242 WIN32_STREAM_ID wid;
4243 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
4244 } data;
4246 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
4247 indicates that flag is unsupported for CP_UTF8, and OTOH says
4248 it is the default anyway. */
4249 wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
4250 data.wid.cStreamName, MAX_PATH);
4251 if (wlen > 0)
4253 LPVOID context = NULL;
4254 DWORD wbytes = 0;
4256 data.wid.dwStreamId = BACKUP_LINK;
4257 data.wid.dwStreamAttributes = 0;
4258 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
4259 data.wid.Size.HighPart = 0;
4260 data.wid.dwStreamNameSize = 0;
4262 if (BackupWrite (fileh, (LPBYTE)&data,
4263 offsetof (WIN32_STREAM_ID, cStreamName)
4264 + data.wid.Size.LowPart,
4265 &wbytes, FALSE, FALSE, &context)
4266 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
4268 /* succeeded */
4269 result = 0;
4271 else
4273 DWORD err = GetLastError ();
4274 DWORD attributes;
4276 switch (err)
4278 case ERROR_ACCESS_DENIED:
4279 /* This is what happens when OLDNAME is a directory,
4280 since Windows doesn't support hard links to
4281 directories. Posix says to set errno to EPERM in
4282 that case. */
4283 if (w32_unicode_filenames)
4284 attributes = GetFileAttributesW (oldname_w);
4285 else
4286 attributes = GetFileAttributesA (oldname_a);
4287 if (attributes != -1
4288 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
4289 errno = EPERM;
4290 else if (attributes == -1
4291 && is_unc_volume (oldname)
4292 && unc_volume_file_attributes (oldname) != -1)
4293 errno = EPERM;
4294 else
4295 errno = EACCES;
4296 break;
4297 case ERROR_TOO_MANY_LINKS:
4298 errno = EMLINK;
4299 break;
4300 case ERROR_NOT_SAME_DEVICE:
4301 errno = EXDEV;
4302 break;
4303 default:
4304 errno = EINVAL;
4305 break;
4310 CloseHandle (fileh);
4312 else
4313 errno = ENOENT;
4315 return result;
4319 sys_mkdir (const char * path)
4321 path = map_w32_filename (path, NULL);
4323 if (w32_unicode_filenames)
4325 wchar_t path_w[MAX_PATH];
4327 filename_to_utf16 (path, path_w);
4328 return _wmkdir (path_w);
4330 else
4332 char path_a[MAX_PATH];
4334 filename_to_ansi (path, path_a);
4335 return _mkdir (path_a);
4340 sys_open (const char * path, int oflag, int mode)
4342 const char* mpath = map_w32_filename (path, NULL);
4343 int res = -1;
4345 if (w32_unicode_filenames)
4347 wchar_t mpath_w[MAX_PATH];
4349 filename_to_utf16 (mpath, mpath_w);
4350 /* If possible, try to open file without _O_CREAT, to be able to
4351 write to existing hidden and system files. Force all file
4352 handles to be non-inheritable. */
4353 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4354 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4355 if (res < 0)
4356 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4358 else
4360 char mpath_a[MAX_PATH];
4362 filename_to_ansi (mpath, mpath_a);
4363 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4364 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4365 if (res < 0)
4366 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4369 return res;
4372 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
4373 when using mktemp.
4375 Standard algorithm for generating a temporary file name seems to be
4376 use pid or tid with a letter on the front (in place of the 6 X's)
4377 and cycle through the letters to find a unique name. We extend
4378 that to allow any reasonable character as the first of the 6 X's,
4379 so that the number of simultaneously used temporary files will be
4380 greater. */
4383 mkostemp (char * template, int flags)
4385 char * p;
4386 int i, fd = -1;
4387 unsigned uid = GetCurrentThreadId ();
4388 int save_errno = errno;
4389 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
4391 errno = EINVAL;
4392 if (template == NULL)
4393 return -1;
4395 p = template + strlen (template);
4396 i = 5;
4397 /* replace up to the last 5 X's with uid in decimal */
4398 while (--p >= template && p[0] == 'X' && --i >= 0)
4400 p[0] = '0' + uid % 10;
4401 uid /= 10;
4404 if (i < 0 && p[0] == 'X')
4406 i = 0;
4409 p[0] = first_char[i];
4410 if ((fd = sys_open (template,
4411 flags | _O_CREAT | _O_EXCL | _O_RDWR,
4412 S_IRUSR | S_IWUSR)) >= 0
4413 || errno != EEXIST)
4415 if (fd >= 0)
4416 errno = save_errno;
4417 return fd;
4420 while (++i < sizeof (first_char));
4423 /* Template is badly formed or else we can't generate a unique name. */
4424 return -1;
4428 fchmod (int fd, mode_t mode)
4430 return 0;
4434 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4436 BOOL result;
4437 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4438 int newname_dev;
4439 int oldname_dev;
4440 bool have_temp_a = false;
4442 /* MoveFile on Windows 95 doesn't correctly change the short file name
4443 alias in a number of circumstances (it is not easy to predict when
4444 just by looking at oldname and newname, unfortunately). In these
4445 cases, renaming through a temporary name avoids the problem.
4447 A second problem on Windows 95 is that renaming through a temp name when
4448 newname is uppercase fails (the final long name ends up in
4449 lowercase, although the short alias might be uppercase) UNLESS the
4450 long temp name is not 8.3.
4452 So, on Windows 95 we always rename through a temp name, and we make sure
4453 the temp name has a long extension to ensure correct renaming. */
4455 strcpy (temp, map_w32_filename (oldname, NULL));
4457 /* volume_info is set indirectly by map_w32_filename. */
4458 oldname_dev = volume_info.serialnum;
4460 if (os_subtype == OS_9X)
4462 char * o;
4463 char * p;
4464 int i = 0;
4465 char oldname_a[MAX_PATH];
4467 oldname = map_w32_filename (oldname, NULL);
4468 filename_to_ansi (oldname, oldname_a);
4469 filename_to_ansi (temp, temp_a);
4470 if ((o = strrchr (oldname_a, '\\')))
4471 o++;
4472 else
4473 o = (char *) oldname_a;
4475 if ((p = strrchr (temp_a, '\\')))
4476 p++;
4477 else
4478 p = temp_a;
4482 /* Force temp name to require a manufactured 8.3 alias - this
4483 seems to make the second rename work properly. */
4484 sprintf (p, "_.%s.%d", o, i);
4485 i++;
4486 result = rename (oldname_a, temp_a);
4488 /* This loop must surely terminate! */
4489 while (result < 0 && errno == EEXIST);
4490 if (result < 0)
4491 return -1;
4492 have_temp_a = true;
4495 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4496 (at least if it is a file; don't do this for directories).
4498 Since we mustn't do this if we are just changing the case of the
4499 file name (we would end up deleting the file we are trying to
4500 rename!), we let rename detect if the destination file already
4501 exists - that way we avoid the possible pitfalls of trying to
4502 determine ourselves whether two names really refer to the same
4503 file, which is not always possible in the general case. (Consider
4504 all the permutations of shared or subst'd drives, etc.) */
4506 newname = map_w32_filename (newname, NULL);
4508 /* volume_info is set indirectly by map_w32_filename. */
4509 newname_dev = volume_info.serialnum;
4511 if (w32_unicode_filenames)
4513 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4515 filename_to_utf16 (temp, temp_w);
4516 filename_to_utf16 (newname, newname_w);
4517 result = _wrename (temp_w, newname_w);
4518 if (result < 0 && force)
4520 DWORD w32err = GetLastError ();
4522 if (errno == EACCES
4523 && newname_dev != oldname_dev)
4525 /* The implementation of `rename' on Windows does not return
4526 errno = EXDEV when you are moving a directory to a
4527 different storage device (ex. logical disk). It returns
4528 EACCES instead. So here we handle such situations and
4529 return EXDEV. */
4530 DWORD attributes;
4532 if ((attributes = GetFileAttributesW (temp_w)) != -1
4533 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4534 errno = EXDEV;
4536 else if (errno == EEXIST)
4538 if (_wchmod (newname_w, 0666) != 0)
4539 return result;
4540 if (_wunlink (newname_w) != 0)
4541 return result;
4542 result = _wrename (temp_w, newname_w);
4544 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4545 && is_symlink (temp))
4547 /* This is Windows prohibiting the user from creating a
4548 symlink in another place, since that requires
4549 privileges. */
4550 errno = EPERM;
4554 else
4556 char newname_a[MAX_PATH];
4558 if (!have_temp_a)
4559 filename_to_ansi (temp, temp_a);
4560 filename_to_ansi (newname, newname_a);
4561 result = rename (temp_a, newname_a);
4562 if (result < 0 && force)
4564 DWORD w32err = GetLastError ();
4566 if (errno == EACCES
4567 && newname_dev != oldname_dev)
4569 DWORD attributes;
4571 if ((attributes = GetFileAttributesA (temp_a)) != -1
4572 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4573 errno = EXDEV;
4575 else if (errno == EEXIST)
4577 if (_chmod (newname_a, 0666) != 0)
4578 return result;
4579 if (_unlink (newname_a) != 0)
4580 return result;
4581 result = rename (temp_a, newname_a);
4583 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4584 && is_symlink (temp))
4585 errno = EPERM;
4589 return result;
4593 sys_rename (char const *old, char const *new)
4595 return sys_rename_replace (old, new, TRUE);
4599 sys_rmdir (const char * path)
4601 path = map_w32_filename (path, NULL);
4603 if (w32_unicode_filenames)
4605 wchar_t path_w[MAX_PATH];
4607 filename_to_utf16 (path, path_w);
4608 return _wrmdir (path_w);
4610 else
4612 char path_a[MAX_PATH];
4614 filename_to_ansi (path, path_a);
4615 return _rmdir (path_a);
4620 sys_unlink (const char * path)
4622 int rmstatus, e;
4624 path = map_w32_filename (path, NULL);
4626 if (w32_unicode_filenames)
4628 wchar_t path_w[MAX_PATH];
4630 filename_to_utf16 (path, path_w);
4631 /* On Unix, unlink works without write permission. */
4632 _wchmod (path_w, 0666);
4633 rmstatus = _wunlink (path_w);
4634 e = errno;
4635 /* Symlinks to directories can only be deleted by _rmdir;
4636 _unlink returns EACCES. */
4637 if (rmstatus != 0
4638 && errno == EACCES
4639 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4640 rmstatus = _wrmdir (path_w);
4641 else
4642 errno = e;
4644 else
4646 char path_a[MAX_PATH];
4648 filename_to_ansi (path, path_a);
4649 _chmod (path_a, 0666);
4650 rmstatus = _unlink (path_a);
4651 e = errno;
4652 if (rmstatus != 0
4653 && errno == EACCES
4654 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4655 rmstatus = _rmdir (path_a);
4656 else
4657 errno = e;
4660 return rmstatus;
4663 static FILETIME utc_base_ft;
4664 static ULONGLONG utc_base; /* In 100ns units */
4665 static int init = 0;
4667 #define FILETIME_TO_U64(result, ft) \
4668 do { \
4669 ULARGE_INTEGER uiTemp; \
4670 uiTemp.LowPart = (ft).dwLowDateTime; \
4671 uiTemp.HighPart = (ft).dwHighDateTime; \
4672 result = uiTemp.QuadPart; \
4673 } while (0)
4675 static void
4676 initialize_utc_base (void)
4678 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4679 SYSTEMTIME st;
4681 st.wYear = 1970;
4682 st.wMonth = 1;
4683 st.wDay = 1;
4684 st.wHour = 0;
4685 st.wMinute = 0;
4686 st.wSecond = 0;
4687 st.wMilliseconds = 0;
4689 SystemTimeToFileTime (&st, &utc_base_ft);
4690 FILETIME_TO_U64 (utc_base, utc_base_ft);
4693 static time_t
4694 convert_time (FILETIME ft)
4696 ULONGLONG tmp;
4698 if (!init)
4700 initialize_utc_base ();
4701 init = 1;
4704 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4705 return 0;
4707 FILETIME_TO_U64 (tmp, ft);
4708 return (time_t) ((tmp - utc_base) / 10000000L);
4711 static void
4712 convert_from_time_t (time_t time, FILETIME * pft)
4714 ULARGE_INTEGER tmp;
4716 if (!init)
4718 initialize_utc_base ();
4719 init = 1;
4722 /* time in 100ns units since 1-Jan-1601 */
4723 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4724 pft->dwHighDateTime = tmp.HighPart;
4725 pft->dwLowDateTime = tmp.LowPart;
4728 static PSECURITY_DESCRIPTOR
4729 get_file_security_desc_by_handle (HANDLE h)
4731 PSECURITY_DESCRIPTOR psd = NULL;
4732 DWORD err;
4733 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4734 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4736 err = get_security_info (h, SE_FILE_OBJECT, si,
4737 NULL, NULL, NULL, NULL, &psd);
4738 if (err != ERROR_SUCCESS)
4739 return NULL;
4741 return psd;
4744 static PSECURITY_DESCRIPTOR
4745 get_file_security_desc_by_name (const char *fname)
4747 PSECURITY_DESCRIPTOR psd = NULL;
4748 DWORD sd_len, err;
4749 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4750 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4752 if (!get_file_security (fname, si, psd, 0, &sd_len))
4754 err = GetLastError ();
4755 if (err != ERROR_INSUFFICIENT_BUFFER)
4756 return NULL;
4759 psd = xmalloc (sd_len);
4760 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4762 xfree (psd);
4763 return NULL;
4766 return psd;
4769 static DWORD
4770 get_rid (PSID sid)
4772 unsigned n_subauthorities;
4774 /* Use the last sub-authority value of the RID, the relative
4775 portion of the SID, as user/group ID. */
4776 n_subauthorities = *get_sid_sub_authority_count (sid);
4777 if (n_subauthorities < 1)
4778 return 0; /* the "World" RID */
4779 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4782 /* Caching SID and account values for faster lokup. */
4784 struct w32_id {
4785 unsigned rid;
4786 struct w32_id *next;
4787 char name[GNLEN+1];
4788 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4791 static struct w32_id *w32_idlist;
4793 static int
4794 w32_cached_id (PSID sid, unsigned *id, char *name)
4796 struct w32_id *tail, *found;
4798 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4800 if (equal_sid ((PSID)tail->sid, sid))
4802 found = tail;
4803 break;
4806 if (found)
4808 *id = found->rid;
4809 strcpy (name, found->name);
4810 return 1;
4812 else
4813 return 0;
4816 static void
4817 w32_add_to_cache (PSID sid, unsigned id, char *name)
4819 DWORD sid_len;
4820 struct w32_id *new_entry;
4822 /* We don't want to leave behind stale cache from when Emacs was
4823 dumped. */
4824 if (initialized)
4826 sid_len = get_length_sid (sid);
4827 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4828 if (new_entry)
4830 new_entry->rid = id;
4831 strcpy (new_entry->name, name);
4832 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4833 new_entry->next = w32_idlist;
4834 w32_idlist = new_entry;
4839 #define UID 1
4840 #define GID 2
4842 static int
4843 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4845 PSID sid = NULL;
4846 BOOL dflt;
4847 SID_NAME_USE ignore;
4848 char name[UNLEN+1];
4849 DWORD name_len = sizeof (name);
4850 char domain[1024];
4851 DWORD domain_len = sizeof (domain);
4852 int use_dflt = 0;
4853 int result;
4855 if (what == UID)
4856 result = get_security_descriptor_owner (psd, &sid, &dflt);
4857 else if (what == GID)
4858 result = get_security_descriptor_group (psd, &sid, &dflt);
4859 else
4860 result = 0;
4862 if (!result || !is_valid_sid (sid))
4863 use_dflt = 1;
4864 else if (!w32_cached_id (sid, id, nm))
4866 if (!lookup_account_sid (NULL, sid, name, &name_len,
4867 domain, &domain_len, &ignore)
4868 || name_len > UNLEN+1)
4869 use_dflt = 1;
4870 else
4872 *id = get_rid (sid);
4873 strcpy (nm, name);
4874 w32_add_to_cache (sid, *id, name);
4877 return use_dflt;
4880 static void
4881 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4883 int dflt_usr = 0, dflt_grp = 0;
4885 if (!psd)
4887 dflt_usr = 1;
4888 dflt_grp = 1;
4890 else
4892 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4893 dflt_usr = 1;
4894 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4895 dflt_grp = 1;
4897 /* Consider files to belong to current user/group, if we cannot get
4898 more accurate information. */
4899 if (dflt_usr)
4901 st->st_uid = dflt_passwd.pw_uid;
4902 strcpy (st->st_uname, dflt_passwd.pw_name);
4904 if (dflt_grp)
4906 st->st_gid = dflt_passwd.pw_gid;
4907 strcpy (st->st_gname, dflt_group.gr_name);
4911 /* Return non-zero if NAME is a potentially slow filesystem. */
4912 int is_slow_fs (const char *);
4915 is_slow_fs (const char *name)
4917 char drive_root[4];
4918 UINT devtype;
4920 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4921 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4922 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4923 devtype = GetDriveType (NULL); /* use root of current drive */
4924 else
4926 /* GetDriveType needs the root directory of the drive. */
4927 strncpy (drive_root, name, 2);
4928 drive_root[2] = '\\';
4929 drive_root[3] = '\0';
4930 devtype = GetDriveType (drive_root);
4932 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4935 /* If this is non-zero, the caller wants accurate information about
4936 file's owner and group, which could be expensive to get. dired.c
4937 uses this flag when needed for the job at hand. */
4938 int w32_stat_get_owner_group;
4940 /* MSVC stat function can't cope with UNC names and has other bugs, so
4941 replace it with our own. This also allows us to calculate consistent
4942 inode values and owner/group without hacks in the main Emacs code,
4943 and support file names encoded in UTF-8. */
4945 static int
4946 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4948 char *name, *save_name, *r;
4949 WIN32_FIND_DATAW wfd_w;
4950 WIN32_FIND_DATAA wfd_a;
4951 HANDLE fh;
4952 unsigned __int64 fake_inode = 0;
4953 int permission;
4954 int len;
4955 int rootdir = FALSE;
4956 PSECURITY_DESCRIPTOR psd = NULL;
4957 int is_a_symlink = 0;
4958 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4959 DWORD access_rights = 0;
4960 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4961 FILETIME ctime, atime, wtime;
4962 wchar_t name_w[MAX_PATH];
4963 char name_a[MAX_PATH];
4965 if (path == NULL || buf == NULL)
4967 errno = EFAULT;
4968 return -1;
4971 save_name = name = (char *) map_w32_filename (path, &path);
4972 /* Must be valid filename, no wild cards or other invalid
4973 characters. */
4974 if (strpbrk (name, "*?|<>\""))
4976 errno = ENOENT;
4977 return -1;
4980 len = strlen (name);
4981 /* Allocate 1 extra byte so that we could append a slash to a root
4982 directory, down below. */
4983 name = strcpy (alloca (len + 2), name);
4985 /* Avoid a somewhat costly call to is_symlink if the filesystem
4986 doesn't support symlinks. */
4987 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4988 is_a_symlink = is_symlink (name);
4990 /* Plan A: Open the file and get all the necessary information via
4991 the resulting handle. This solves several issues in one blow:
4993 . retrieves attributes for the target of a symlink, if needed
4994 . gets attributes of root directories and symlinks pointing to
4995 root directories, thus avoiding the need for special-casing
4996 these and detecting them by examining the file-name format
4997 . retrieves more accurate attributes (e.g., non-zero size for
4998 some directories, esp. directories that are junction points)
4999 . correctly resolves "c:/..", "/.." and similar file names
5000 . avoids run-time penalties for 99% of use cases
5002 Plan A is always tried first, unless the user asked not to (but
5003 if the file is a symlink and we need to follow links, we try Plan
5004 A even if the user asked not to).
5006 If Plan A fails, we go to Plan B (below), where various
5007 potentially expensive techniques must be used to handle "special"
5008 files such as UNC volumes etc. */
5009 if (!(NILP (Vw32_get_true_file_attributes)
5010 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
5011 /* Following symlinks requires getting the info by handle. */
5012 || (is_a_symlink && follow_symlinks))
5014 BY_HANDLE_FILE_INFORMATION info;
5016 if (is_a_symlink && !follow_symlinks)
5017 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
5018 /* READ_CONTROL access rights are required to get security info
5019 by handle. But if the OS doesn't support security in the
5020 first place, we don't need to try. */
5021 if (is_windows_9x () != TRUE)
5022 access_rights |= READ_CONTROL;
5024 if (w32_unicode_filenames)
5026 filename_to_utf16 (name, name_w);
5027 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
5028 file_flags, NULL);
5029 /* If CreateFile fails with READ_CONTROL, try again with
5030 zero as access rights. */
5031 if (fh == INVALID_HANDLE_VALUE && access_rights)
5032 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
5033 file_flags, NULL);
5035 else
5037 filename_to_ansi (name, name_a);
5038 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
5039 file_flags, NULL);
5040 if (fh == INVALID_HANDLE_VALUE && access_rights)
5041 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
5042 file_flags, NULL);
5044 if (fh == INVALID_HANDLE_VALUE)
5045 goto no_true_file_attributes;
5047 /* This is more accurate in terms of getting the correct number
5048 of links, but is quite slow (it is noticeable when Emacs is
5049 making a list of file name completions). */
5050 if (GetFileInformationByHandle (fh, &info))
5052 nlinks = info.nNumberOfLinks;
5053 /* Might as well use file index to fake inode values, but this
5054 is not guaranteed to be unique unless we keep a handle open
5055 all the time (even then there are situations where it is
5056 not unique). Reputedly, there are at most 48 bits of info
5057 (on NTFS, presumably less on FAT). */
5058 fake_inode = info.nFileIndexHigh;
5059 fake_inode <<= 32;
5060 fake_inode += info.nFileIndexLow;
5061 serialnum = info.dwVolumeSerialNumber;
5062 fs_high = info.nFileSizeHigh;
5063 fs_low = info.nFileSizeLow;
5064 ctime = info.ftCreationTime;
5065 atime = info.ftLastAccessTime;
5066 wtime = info.ftLastWriteTime;
5067 fattrs = info.dwFileAttributes;
5069 else
5071 /* We don't go to Plan B here, because it's not clear that
5072 it's a good idea. The only known use case where
5073 CreateFile succeeds, but GetFileInformationByHandle fails
5074 (with ERROR_INVALID_FUNCTION) is for character devices
5075 such as NUL, PRN, etc. For these, switching to Plan B is
5076 a net loss, because we lose the character device
5077 attribute returned by GetFileType below (FindFirstFile
5078 doesn't set that bit in the attributes), and the other
5079 fields don't make sense for character devices anyway.
5080 Emacs doesn't really care for non-file entities in the
5081 context of l?stat, so neither do we. */
5083 /* w32err is assigned so one could put a breakpoint here and
5084 examine its value, when GetFileInformationByHandle
5085 fails. */
5086 DWORD w32err = GetLastError ();
5088 switch (w32err)
5090 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
5091 errno = ENOENT;
5092 return -1;
5096 /* Test for a symlink before testing for a directory, since
5097 symlinks to directories have the directory bit set, but we
5098 don't want them to appear as directories. */
5099 if (is_a_symlink && !follow_symlinks)
5100 buf->st_mode = S_IFLNK;
5101 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5102 buf->st_mode = S_IFDIR;
5103 else
5105 DWORD ftype = GetFileType (fh);
5107 switch (ftype)
5109 case FILE_TYPE_DISK:
5110 buf->st_mode = S_IFREG;
5111 break;
5112 case FILE_TYPE_PIPE:
5113 buf->st_mode = S_IFIFO;
5114 break;
5115 case FILE_TYPE_CHAR:
5116 case FILE_TYPE_UNKNOWN:
5117 default:
5118 buf->st_mode = S_IFCHR;
5121 /* We produce the fallback owner and group data, based on the
5122 current user that runs Emacs, in the following cases:
5124 . caller didn't request owner and group info
5125 . this is Windows 9X
5126 . getting security by handle failed, and we need to produce
5127 information for the target of a symlink (this is better
5128 than producing a potentially misleading info about the
5129 symlink itself)
5131 If getting security by handle fails, and we don't need to
5132 resolve symlinks, we try getting security by name. */
5133 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5134 get_file_owner_and_group (NULL, buf);
5135 else
5137 psd = get_file_security_desc_by_handle (fh);
5138 if (psd)
5140 get_file_owner_and_group (psd, buf);
5141 LocalFree (psd);
5143 else if (!(is_a_symlink && follow_symlinks))
5145 psd = get_file_security_desc_by_name (name);
5146 get_file_owner_and_group (psd, buf);
5147 xfree (psd);
5149 else
5150 get_file_owner_and_group (NULL, buf);
5152 CloseHandle (fh);
5154 else
5156 no_true_file_attributes:
5157 /* Plan B: Either getting a handle on the file failed, or the
5158 caller explicitly asked us to not bother making this
5159 information more accurate.
5161 Implementation note: In Plan B, we never bother to resolve
5162 symlinks, even if we got here because we tried Plan A and
5163 failed. That's because, even if the caller asked for extra
5164 precision by setting Vw32_get_true_file_attributes to t,
5165 resolving symlinks requires acquiring a file handle to the
5166 symlink, which we already know will fail. And if the user
5167 did not ask for extra precision, resolving symlinks will fly
5168 in the face of that request, since the user then wants the
5169 lightweight version of the code. */
5170 rootdir = (path >= save_name + len - 1
5171 && (IS_DIRECTORY_SEP (*path) || *path == 0));
5173 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
5174 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
5175 if (IS_DIRECTORY_SEP (r[0])
5176 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
5177 r[1] = r[2] = '\0';
5179 /* Note: If NAME is a symlink to the root of a UNC volume
5180 (i.e. "\\SERVER"), we will not detect that here, and we will
5181 return data about the symlink as result of FindFirst below.
5182 This is unfortunate, but that marginal use case does not
5183 justify a call to chase_symlinks which would impose a penalty
5184 on all the other use cases. (We get here for symlinks to
5185 roots of UNC volumes because CreateFile above fails for them,
5186 unlike with symlinks to root directories X:\ of drives.) */
5187 if (is_unc_volume (name))
5189 fattrs = unc_volume_file_attributes (name);
5190 if (fattrs == -1)
5191 return -1;
5193 ctime = atime = wtime = utc_base_ft;
5195 else if (rootdir)
5197 /* Make sure root directories end in a slash. */
5198 if (!IS_DIRECTORY_SEP (name[len-1]))
5199 strcpy (name + len, "\\");
5200 if (GetDriveType (name) < 2)
5202 errno = ENOENT;
5203 return -1;
5206 fattrs = FILE_ATTRIBUTE_DIRECTORY;
5207 ctime = atime = wtime = utc_base_ft;
5209 else
5211 int have_wfd = -1;
5213 /* Make sure non-root directories do NOT end in a slash,
5214 otherwise FindFirstFile might fail. */
5215 if (IS_DIRECTORY_SEP (name[len-1]))
5216 name[len - 1] = 0;
5218 /* (This is hacky, but helps when doing file completions on
5219 network drives.) Optimize by using information available from
5220 active readdir if possible. */
5221 len = strlen (dir_pathname);
5222 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
5223 len--;
5224 if (dir_find_handle != INVALID_HANDLE_VALUE
5225 && last_dir_find_data != -1
5226 && !(is_a_symlink && follow_symlinks)
5227 /* The 2 file-name comparisons below support only ASCII
5228 characters, and will lose (compare not equal) when
5229 the file names include non-ASCII characters that are
5230 the same but for the case. However, doing this
5231 properly involves: (a) converting both file names to
5232 UTF-16, (b) lower-casing both names using CharLowerW,
5233 and (c) comparing the results; this would be quite a
5234 bit slower, whereas Plan B is for users who want
5235 lightweight albeit inaccurate version of 'stat'. */
5236 && c_strncasecmp (save_name, dir_pathname, len) == 0
5237 && IS_DIRECTORY_SEP (name[len])
5238 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
5240 have_wfd = last_dir_find_data;
5241 /* This was the last entry returned by readdir. */
5242 if (last_dir_find_data == DIR_FIND_DATA_W)
5243 wfd_w = dir_find_data_w;
5244 else
5245 wfd_a = dir_find_data_a;
5247 else
5249 logon_network_drive (name);
5251 if (w32_unicode_filenames)
5253 filename_to_utf16 (name, name_w);
5254 fh = FindFirstFileW (name_w, &wfd_w);
5255 have_wfd = DIR_FIND_DATA_W;
5257 else
5259 filename_to_ansi (name, name_a);
5260 /* If NAME includes characters not representable by
5261 the current ANSI codepage, filename_to_ansi
5262 usually replaces them with a '?'. We don't want
5263 to let FindFirstFileA interpret those as wildcards,
5264 and "succeed", returning us data from some random
5265 file in the same directory. */
5266 if (_mbspbrk (name_a, "?"))
5267 fh = INVALID_HANDLE_VALUE;
5268 else
5269 fh = FindFirstFileA (name_a, &wfd_a);
5270 have_wfd = DIR_FIND_DATA_A;
5272 if (fh == INVALID_HANDLE_VALUE)
5274 errno = ENOENT;
5275 return -1;
5277 FindClose (fh);
5279 /* Note: if NAME is a symlink, the information we get from
5280 FindFirstFile is for the symlink, not its target. */
5281 if (have_wfd == DIR_FIND_DATA_W)
5283 fattrs = wfd_w.dwFileAttributes;
5284 ctime = wfd_w.ftCreationTime;
5285 atime = wfd_w.ftLastAccessTime;
5286 wtime = wfd_w.ftLastWriteTime;
5287 fs_high = wfd_w.nFileSizeHigh;
5288 fs_low = wfd_w.nFileSizeLow;
5290 else
5292 fattrs = wfd_a.dwFileAttributes;
5293 ctime = wfd_a.ftCreationTime;
5294 atime = wfd_a.ftLastAccessTime;
5295 wtime = wfd_a.ftLastWriteTime;
5296 fs_high = wfd_a.nFileSizeHigh;
5297 fs_low = wfd_a.nFileSizeLow;
5299 fake_inode = 0;
5300 nlinks = 1;
5301 serialnum = volume_info.serialnum;
5303 if (is_a_symlink && !follow_symlinks)
5304 buf->st_mode = S_IFLNK;
5305 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5306 buf->st_mode = S_IFDIR;
5307 else
5308 buf->st_mode = S_IFREG;
5310 get_file_owner_and_group (NULL, buf);
5313 buf->st_ino = fake_inode;
5315 buf->st_dev = serialnum;
5316 buf->st_rdev = serialnum;
5318 buf->st_size = fs_high;
5319 buf->st_size <<= 32;
5320 buf->st_size += fs_low;
5321 buf->st_nlink = nlinks;
5323 /* Convert timestamps to Unix format. */
5324 buf->st_mtime = convert_time (wtime);
5325 buf->st_atime = convert_time (atime);
5326 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5327 buf->st_ctime = convert_time (ctime);
5328 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5330 /* determine rwx permissions */
5331 if (is_a_symlink && !follow_symlinks)
5332 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5333 else
5335 if (fattrs & FILE_ATTRIBUTE_READONLY)
5336 permission = S_IREAD;
5337 else
5338 permission = S_IREAD | S_IWRITE;
5340 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5341 permission |= S_IEXEC;
5342 else if (is_exec (name))
5343 permission |= S_IEXEC;
5346 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5348 return 0;
5352 stat (const char * path, struct stat * buf)
5354 return stat_worker (path, buf, 1);
5358 lstat (const char * path, struct stat * buf)
5360 return stat_worker (path, buf, 0);
5364 fstatat (int fd, char const *name, struct stat *st, int flags)
5366 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5367 This is good enough for the current usage in Emacs, but is fragile.
5369 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5370 Gnulib does this and can serve as a model. */
5371 char fullname[MAX_UTF8_PATH];
5373 if (fd != AT_FDCWD)
5375 char lastc = dir_pathname[strlen (dir_pathname) - 1];
5377 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
5378 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
5379 < 0)
5381 errno = ENAMETOOLONG;
5382 return -1;
5384 name = fullname;
5387 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5390 /* Provide fstat and utime as well as stat for consistent handling of
5391 file timestamps. */
5393 fstat (int desc, struct stat * buf)
5395 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5396 BY_HANDLE_FILE_INFORMATION info;
5397 unsigned __int64 fake_inode;
5398 int permission;
5400 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5402 case FILE_TYPE_DISK:
5403 buf->st_mode = S_IFREG;
5404 if (!GetFileInformationByHandle (fh, &info))
5406 errno = EACCES;
5407 return -1;
5409 break;
5410 case FILE_TYPE_PIPE:
5411 buf->st_mode = S_IFIFO;
5412 goto non_disk;
5413 case FILE_TYPE_CHAR:
5414 case FILE_TYPE_UNKNOWN:
5415 default:
5416 buf->st_mode = S_IFCHR;
5417 non_disk:
5418 memset (&info, 0, sizeof (info));
5419 info.dwFileAttributes = 0;
5420 info.ftCreationTime = utc_base_ft;
5421 info.ftLastAccessTime = utc_base_ft;
5422 info.ftLastWriteTime = utc_base_ft;
5425 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5426 buf->st_mode = S_IFDIR;
5428 buf->st_nlink = info.nNumberOfLinks;
5429 /* Might as well use file index to fake inode values, but this
5430 is not guaranteed to be unique unless we keep a handle open
5431 all the time (even then there are situations where it is
5432 not unique). Reputedly, there are at most 48 bits of info
5433 (on NTFS, presumably less on FAT). */
5434 fake_inode = info.nFileIndexHigh;
5435 fake_inode <<= 32;
5436 fake_inode += info.nFileIndexLow;
5438 /* MSVC defines _ino_t to be short; other libc's might not. */
5439 if (sizeof (buf->st_ino) == 2)
5440 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5441 else
5442 buf->st_ino = fake_inode;
5444 /* If the caller so requested, get the true file owner and group.
5445 Otherwise, consider the file to belong to the current user. */
5446 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5447 get_file_owner_and_group (NULL, buf);
5448 else
5450 PSECURITY_DESCRIPTOR psd = NULL;
5452 psd = get_file_security_desc_by_handle (fh);
5453 if (psd)
5455 get_file_owner_and_group (psd, buf);
5456 LocalFree (psd);
5458 else
5459 get_file_owner_and_group (NULL, buf);
5462 buf->st_dev = info.dwVolumeSerialNumber;
5463 buf->st_rdev = info.dwVolumeSerialNumber;
5465 buf->st_size = info.nFileSizeHigh;
5466 buf->st_size <<= 32;
5467 buf->st_size += info.nFileSizeLow;
5469 /* Convert timestamps to Unix format. */
5470 buf->st_mtime = convert_time (info.ftLastWriteTime);
5471 buf->st_atime = convert_time (info.ftLastAccessTime);
5472 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5473 buf->st_ctime = convert_time (info.ftCreationTime);
5474 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5476 /* determine rwx permissions */
5477 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5478 permission = S_IREAD;
5479 else
5480 permission = S_IREAD | S_IWRITE;
5482 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5483 permission |= S_IEXEC;
5484 else
5486 #if 0 /* no way of knowing the filename */
5487 char * p = strrchr (name, '.');
5488 if (p != NULL &&
5489 (xstrcasecmp (p, ".exe") == 0 ||
5490 xstrcasecmp (p, ".com") == 0 ||
5491 xstrcasecmp (p, ".bat") == 0 ||
5492 xstrcasecmp (p, ".cmd") == 0))
5493 permission |= S_IEXEC;
5494 #endif
5497 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5499 return 0;
5502 /* A version of 'utime' which handles directories as well as
5503 files. */
5506 utime (const char *name, struct utimbuf *times)
5508 struct utimbuf deftime;
5509 HANDLE fh;
5510 FILETIME mtime;
5511 FILETIME atime;
5513 if (times == NULL)
5515 deftime.modtime = deftime.actime = time (NULL);
5516 times = &deftime;
5519 if (w32_unicode_filenames)
5521 wchar_t name_utf16[MAX_PATH];
5523 if (filename_to_utf16 (name, name_utf16) != 0)
5524 return -1; /* errno set by filename_to_utf16 */
5526 /* Need write access to set times. */
5527 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5528 /* If NAME specifies a directory, FILE_SHARE_DELETE
5529 allows other processes to delete files inside it,
5530 while we have the directory open. */
5531 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5532 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5534 else
5536 char name_ansi[MAX_PATH];
5538 if (filename_to_ansi (name, name_ansi) != 0)
5539 return -1; /* errno set by filename_to_ansi */
5541 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5542 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5543 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5545 if (fh != INVALID_HANDLE_VALUE)
5547 convert_from_time_t (times->actime, &atime);
5548 convert_from_time_t (times->modtime, &mtime);
5549 if (!SetFileTime (fh, NULL, &atime, &mtime))
5551 CloseHandle (fh);
5552 errno = EACCES;
5553 return -1;
5555 CloseHandle (fh);
5557 else
5559 DWORD err = GetLastError ();
5561 switch (err)
5563 case ERROR_FILE_NOT_FOUND:
5564 case ERROR_PATH_NOT_FOUND:
5565 case ERROR_INVALID_DRIVE:
5566 case ERROR_BAD_NETPATH:
5567 case ERROR_DEV_NOT_EXIST:
5568 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5569 file name includes ?s, i.e. translation to ANSI failed. */
5570 case ERROR_INVALID_NAME:
5571 errno = ENOENT;
5572 break;
5573 case ERROR_TOO_MANY_OPEN_FILES:
5574 errno = ENFILE;
5575 break;
5576 case ERROR_ACCESS_DENIED:
5577 case ERROR_SHARING_VIOLATION:
5578 errno = EACCES;
5579 break;
5580 default:
5581 errno = EINVAL;
5582 break;
5584 return -1;
5586 return 0;
5590 sys_umask (int mode)
5592 static int current_mask;
5593 int retval, arg = 0;
5595 /* The only bit we really support is the write bit. Files are
5596 always readable on MS-Windows, and the execute bit does not exist
5597 at all. */
5598 /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
5599 to prevent access by other users on NTFS. */
5600 if ((mode & S_IWRITE) != 0)
5601 arg |= S_IWRITE;
5603 retval = _umask (arg);
5604 /* Merge into the return value the bits they've set the last time,
5605 which msvcrt.dll ignores and never returns. Emacs insists on its
5606 notion of mask being identical to what we return. */
5607 retval |= (current_mask & ~S_IWRITE);
5608 current_mask = mode;
5610 return retval;
5614 /* Symlink-related functions. */
5615 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5616 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5617 #endif
5620 symlink (char const *filename, char const *linkname)
5622 char linkfn[MAX_UTF8_PATH], *tgtfn;
5623 DWORD flags = 0;
5624 int dir_access, filename_ends_in_slash;
5626 /* Diagnostics follows Posix as much as possible. */
5627 if (filename == NULL || linkname == NULL)
5629 errno = EFAULT;
5630 return -1;
5632 if (!*filename)
5634 errno = ENOENT;
5635 return -1;
5637 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5639 errno = ENAMETOOLONG;
5640 return -1;
5643 strcpy (linkfn, map_w32_filename (linkname, NULL));
5644 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5646 errno = EPERM;
5647 return -1;
5650 /* Note: since empty FILENAME was already rejected, we can safely
5651 refer to FILENAME[1]. */
5652 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5654 /* Non-absolute FILENAME is understood as being relative to
5655 LINKNAME's directory. We need to prepend that directory to
5656 FILENAME to get correct results from faccessat below, since
5657 otherwise it will interpret FILENAME relative to the
5658 directory where the Emacs process runs. Note that
5659 make-symbolic-link always makes sure LINKNAME is a fully
5660 expanded file name. */
5661 char tem[MAX_UTF8_PATH];
5662 char *p = linkfn + strlen (linkfn);
5664 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5665 p--;
5666 if (p > linkfn)
5667 strncpy (tem, linkfn, p - linkfn);
5668 strcpy (tem + (p - linkfn), filename);
5669 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5671 else
5672 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5674 /* Since Windows distinguishes between symlinks to directories and
5675 to files, we provide a kludgy feature: if FILENAME doesn't
5676 exist, but ends in a slash, we create a symlink to directory. If
5677 FILENAME exists and is a directory, we always create a symlink to
5678 directory. */
5679 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5680 if (dir_access == 0 || filename_ends_in_slash)
5681 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5683 tgtfn = (char *)map_w32_filename (filename, NULL);
5684 if (filename_ends_in_slash)
5685 tgtfn[strlen (tgtfn) - 1] = '\0';
5687 errno = 0;
5688 if (!create_symbolic_link (linkfn, tgtfn, flags))
5690 /* ENOSYS is set by create_symbolic_link, when it detects that
5691 the OS doesn't support the CreateSymbolicLink API. */
5692 if (errno != ENOSYS)
5694 DWORD w32err = GetLastError ();
5696 switch (w32err)
5698 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5699 TGTFN point to the same file name, go figure. */
5700 case ERROR_SUCCESS:
5701 case ERROR_FILE_EXISTS:
5702 errno = EEXIST;
5703 break;
5704 case ERROR_ACCESS_DENIED:
5705 errno = EACCES;
5706 break;
5707 case ERROR_FILE_NOT_FOUND:
5708 case ERROR_PATH_NOT_FOUND:
5709 case ERROR_BAD_NETPATH:
5710 case ERROR_INVALID_REPARSE_DATA:
5711 errno = ENOENT;
5712 break;
5713 case ERROR_DIRECTORY:
5714 errno = EISDIR;
5715 break;
5716 case ERROR_PRIVILEGE_NOT_HELD:
5717 case ERROR_NOT_ALL_ASSIGNED:
5718 errno = EPERM;
5719 break;
5720 case ERROR_DISK_FULL:
5721 errno = ENOSPC;
5722 break;
5723 default:
5724 errno = EINVAL;
5725 break;
5728 return -1;
5730 return 0;
5733 /* A quick inexpensive test of whether FILENAME identifies a file that
5734 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5735 must already be in the normalized form returned by
5736 map_w32_filename. If the symlink is to a directory, the
5737 FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
5739 Note: for repeated operations on many files, it is best to test
5740 whether the underlying volume actually supports symlinks, by
5741 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5742 avoid the call to this function if it doesn't. That's because the
5743 call to GetFileAttributes takes a non-negligible time, especially
5744 on non-local or removable filesystems. See stat_worker for an
5745 example of how to do that. */
5746 static int
5747 is_symlink (const char *filename)
5749 DWORD attrs;
5750 wchar_t filename_w[MAX_PATH];
5751 char filename_a[MAX_PATH];
5752 WIN32_FIND_DATAW wfdw;
5753 WIN32_FIND_DATAA wfda;
5754 HANDLE fh;
5755 int attrs_mean_symlink;
5757 if (w32_unicode_filenames)
5759 filename_to_utf16 (filename, filename_w);
5760 attrs = GetFileAttributesW (filename_w);
5762 else
5764 filename_to_ansi (filename, filename_a);
5765 attrs = GetFileAttributesA (filename_a);
5767 if (attrs == -1)
5769 DWORD w32err = GetLastError ();
5771 switch (w32err)
5773 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5774 break;
5775 case ERROR_ACCESS_DENIED:
5776 errno = EACCES;
5777 break;
5778 case ERROR_FILE_NOT_FOUND:
5779 case ERROR_PATH_NOT_FOUND:
5780 default:
5781 errno = ENOENT;
5782 break;
5784 return 0;
5786 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5787 return 0;
5788 logon_network_drive (filename);
5789 if (w32_unicode_filenames)
5791 fh = FindFirstFileW (filename_w, &wfdw);
5792 attrs_mean_symlink =
5793 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5794 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5795 if (attrs_mean_symlink)
5796 attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5798 else if (_mbspbrk (filename_a, "?"))
5800 /* filename_to_ansi failed to convert the file name. */
5801 errno = ENOENT;
5802 return 0;
5804 else
5806 fh = FindFirstFileA (filename_a, &wfda);
5807 attrs_mean_symlink =
5808 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5809 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5810 if (attrs_mean_symlink)
5811 attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5813 if (fh == INVALID_HANDLE_VALUE)
5814 return 0;
5815 FindClose (fh);
5816 return attrs_mean_symlink;
5819 /* If NAME identifies a symbolic link, copy into BUF the file name of
5820 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5821 null-terminate the target name, even if it fits. Return the number
5822 of bytes copied, or -1 if NAME is not a symlink or any error was
5823 encountered while resolving it. The file name copied into BUF is
5824 encoded in the current ANSI codepage. */
5825 ssize_t
5826 readlink (const char *name, char *buf, size_t buf_size)
5828 const char *path;
5829 TOKEN_PRIVILEGES privs;
5830 int restore_privs = 0;
5831 HANDLE sh;
5832 ssize_t retval;
5833 char resolved[MAX_UTF8_PATH];
5835 if (name == NULL)
5837 errno = EFAULT;
5838 return -1;
5840 if (!*name)
5842 errno = ENOENT;
5843 return -1;
5846 path = map_w32_filename (name, NULL);
5848 if (strlen (path) > MAX_UTF8_PATH)
5850 errno = ENAMETOOLONG;
5851 return -1;
5854 errno = 0;
5855 if (is_windows_9x () == TRUE
5856 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5857 || !is_symlink (path))
5859 if (!errno)
5860 errno = EINVAL; /* not a symlink */
5861 return -1;
5864 /* Done with simple tests, now we're in for some _real_ work. */
5865 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5866 restore_privs = 1;
5867 /* Implementation note: From here and onward, don't return early,
5868 since that will fail to restore the original set of privileges of
5869 the calling thread. */
5871 retval = -1; /* not too optimistic, are we? */
5873 /* Note: In the next call to CreateFile, we use zero as the 2nd
5874 argument because, when the symlink is a hidden/system file,
5875 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5876 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5877 and directory symlinks. */
5878 if (w32_unicode_filenames)
5880 wchar_t path_w[MAX_PATH];
5882 filename_to_utf16 (path, path_w);
5883 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5884 FILE_FLAG_OPEN_REPARSE_POINT
5885 | FILE_FLAG_BACKUP_SEMANTICS,
5886 NULL);
5888 else
5890 char path_a[MAX_PATH];
5892 filename_to_ansi (path, path_a);
5893 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5894 FILE_FLAG_OPEN_REPARSE_POINT
5895 | FILE_FLAG_BACKUP_SEMANTICS,
5896 NULL);
5898 if (sh != INVALID_HANDLE_VALUE)
5900 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5901 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5902 DWORD retbytes;
5904 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5905 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5906 &retbytes, NULL))
5907 errno = EIO;
5908 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5909 errno = EINVAL;
5910 else
5912 /* Copy the link target name, in wide characters, from
5913 reparse_data, then convert it to multibyte encoding in
5914 the current locale's codepage. */
5915 WCHAR *lwname;
5916 size_t lname_size;
5917 USHORT lwname_len =
5918 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5919 WCHAR *lwname_src =
5920 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5921 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5922 size_t size_to_copy = buf_size;
5924 /* According to MSDN, PrintNameLength does not include the
5925 terminating null character. */
5926 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5927 memcpy (lwname, lwname_src, lwname_len);
5928 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5929 filename_from_utf16 (lwname, resolved);
5930 dostounix_filename (resolved);
5931 lname_size = strlen (resolved) + 1;
5932 if (lname_size <= buf_size)
5933 size_to_copy = lname_size;
5934 strncpy (buf, resolved, size_to_copy);
5935 /* Success! */
5936 retval = size_to_copy;
5938 CloseHandle (sh);
5940 else
5942 /* CreateFile failed. */
5943 DWORD w32err2 = GetLastError ();
5945 switch (w32err2)
5947 case ERROR_FILE_NOT_FOUND:
5948 case ERROR_PATH_NOT_FOUND:
5949 errno = ENOENT;
5950 break;
5951 case ERROR_ACCESS_DENIED:
5952 case ERROR_TOO_MANY_OPEN_FILES:
5953 errno = EACCES;
5954 break;
5955 default:
5956 errno = EPERM;
5957 break;
5960 if (restore_privs)
5962 restore_privilege (&privs);
5963 revert_to_self ();
5966 return retval;
5969 ssize_t
5970 readlinkat (int fd, char const *name, char *buffer,
5971 size_t buffer_size)
5973 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5974 as in fstatat. FIXME: Add proper support for readlinkat. */
5975 char fullname[MAX_UTF8_PATH];
5977 if (fd != AT_FDCWD)
5979 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5980 < 0)
5982 errno = ENAMETOOLONG;
5983 return -1;
5985 name = fullname;
5988 return readlink (name, buffer, buffer_size);
5991 /* If FILE is a symlink, return its target (stored in a static
5992 buffer); otherwise return FILE.
5994 This function repeatedly resolves symlinks in the last component of
5995 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5996 until it arrives at a file whose last component is not a symlink,
5997 or some error occurs. It returns the target of the last
5998 successfully resolved symlink in the chain. If it succeeds to
5999 resolve even a single symlink, the value returned is an absolute
6000 file name with backslashes (result of GetFullPathName). By
6001 contrast, if the original FILE is returned, it is unaltered.
6003 Note: This function can set errno even if it succeeds.
6005 Implementation note: we only resolve the last portion ("basename")
6006 of the argument FILE and of each following file in the chain,
6007 disregarding any possible symlinks in its leading directories.
6008 This is because Windows system calls and library functions
6009 transparently resolve symlinks in leading directories and return
6010 correct information, as long as the basename is not a symlink. */
6011 static char *
6012 chase_symlinks (const char *file)
6014 static char target[MAX_UTF8_PATH];
6015 char link[MAX_UTF8_PATH];
6016 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
6017 char target_a[MAX_PATH], link_a[MAX_PATH];
6018 ssize_t res, link_len;
6019 int loop_count = 0;
6021 if (is_windows_9x () == TRUE || !is_symlink (file))
6022 return (char *)file;
6024 if (w32_unicode_filenames)
6026 wchar_t file_w[MAX_PATH];
6028 filename_to_utf16 (file, file_w);
6029 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
6030 return (char *)file;
6031 filename_from_utf16 (link_w, link);
6033 else
6035 char file_a[MAX_PATH];
6037 filename_to_ansi (file, file_a);
6038 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
6039 return (char *)file;
6040 filename_from_ansi (link_a, link);
6042 link_len = strlen (link);
6044 target[0] = '\0';
6045 do {
6047 /* Remove trailing slashes, as we want to resolve the last
6048 non-trivial part of the link name. */
6049 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
6050 link[link_len--] = '\0';
6052 res = readlink (link, target, MAX_UTF8_PATH);
6053 if (res > 0)
6055 target[res] = '\0';
6056 if (!(IS_DEVICE_SEP (target[1])
6057 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
6059 /* Target is relative. Append it to the directory part of
6060 the symlink, then copy the result back to target. */
6061 char *p = link + link_len;
6063 while (p > link && !IS_ANY_SEP (p[-1]))
6064 p--;
6065 strcpy (p, target);
6066 strcpy (target, link);
6068 /* Resolve any "." and ".." to get a fully-qualified file name
6069 in link[] again. */
6070 if (w32_unicode_filenames)
6072 filename_to_utf16 (target, target_w);
6073 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
6074 if (link_len > 0)
6075 filename_from_utf16 (link_w, link);
6077 else
6079 filename_to_ansi (target, target_a);
6080 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
6081 if (link_len > 0)
6082 filename_from_ansi (link_a, link);
6084 link_len = strlen (link);
6086 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
6088 if (loop_count > 100)
6089 errno = ELOOP;
6091 if (target[0] == '\0') /* not a single call to readlink succeeded */
6092 return (char *)file;
6093 return target;
6097 /* Posix ACL emulation. */
6100 acl_valid (acl_t acl)
6102 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
6105 char *
6106 acl_to_text (acl_t acl, ssize_t *size)
6108 LPTSTR str_acl;
6109 SECURITY_INFORMATION flags =
6110 OWNER_SECURITY_INFORMATION |
6111 GROUP_SECURITY_INFORMATION |
6112 DACL_SECURITY_INFORMATION;
6113 char *retval = NULL;
6114 ULONG local_size;
6115 int e = errno;
6117 errno = 0;
6119 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
6121 errno = e;
6122 /* We don't want to mix heaps, so we duplicate the string in our
6123 heap and free the one allocated by the API. */
6124 retval = xstrdup (str_acl);
6125 if (size)
6126 *size = local_size;
6127 LocalFree (str_acl);
6129 else if (errno != ENOTSUP)
6130 errno = EINVAL;
6132 return retval;
6135 acl_t
6136 acl_from_text (const char *acl_str)
6138 PSECURITY_DESCRIPTOR psd, retval = NULL;
6139 ULONG sd_size;
6140 int e = errno;
6142 errno = 0;
6144 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
6146 errno = e;
6147 retval = xmalloc (sd_size);
6148 memcpy (retval, psd, sd_size);
6149 LocalFree (psd);
6151 else if (errno != ENOTSUP)
6152 errno = EINVAL;
6154 return retval;
6158 acl_free (void *ptr)
6160 xfree (ptr);
6161 return 0;
6164 acl_t
6165 acl_get_file (const char *fname, acl_type_t type)
6167 PSECURITY_DESCRIPTOR psd = NULL;
6168 const char *filename;
6170 if (type == ACL_TYPE_ACCESS)
6172 DWORD sd_len, err;
6173 SECURITY_INFORMATION si =
6174 OWNER_SECURITY_INFORMATION |
6175 GROUP_SECURITY_INFORMATION |
6176 DACL_SECURITY_INFORMATION ;
6177 int e = errno;
6179 filename = map_w32_filename (fname, NULL);
6180 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6181 fname = chase_symlinks (filename);
6182 else
6183 fname = filename;
6185 errno = 0;
6186 if (!get_file_security (fname, si, psd, 0, &sd_len)
6187 && errno != ENOTSUP)
6189 err = GetLastError ();
6190 if (err == ERROR_INSUFFICIENT_BUFFER)
6192 psd = xmalloc (sd_len);
6193 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
6195 xfree (psd);
6196 errno = EIO;
6197 psd = NULL;
6200 else if (err == ERROR_FILE_NOT_FOUND
6201 || err == ERROR_PATH_NOT_FOUND
6202 /* ERROR_INVALID_NAME is what we get if
6203 w32-unicode-filenames is nil and the file cannot
6204 be encoded in the current ANSI codepage. */
6205 || err == ERROR_INVALID_NAME)
6206 errno = ENOENT;
6207 else
6208 errno = EIO;
6210 else if (!errno)
6211 errno = e;
6213 else if (type != ACL_TYPE_DEFAULT)
6214 errno = EINVAL;
6216 return psd;
6220 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
6222 TOKEN_PRIVILEGES old1, old2;
6223 DWORD err;
6224 int st = 0, retval = -1;
6225 SECURITY_INFORMATION flags = 0;
6226 PSID psidOwner, psidGroup;
6227 PACL pacl;
6228 BOOL dflt;
6229 BOOL dacl_present;
6230 int e;
6231 const char *filename;
6233 if (acl_valid (acl) != 0
6234 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
6236 errno = EINVAL;
6237 return -1;
6240 if (type == ACL_TYPE_DEFAULT)
6242 errno = ENOSYS;
6243 return -1;
6246 filename = map_w32_filename (fname, NULL);
6247 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6248 fname = chase_symlinks (filename);
6249 else
6250 fname = filename;
6252 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
6253 &dflt)
6254 && psidOwner)
6255 flags |= OWNER_SECURITY_INFORMATION;
6256 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
6257 &dflt)
6258 && psidGroup)
6259 flags |= GROUP_SECURITY_INFORMATION;
6260 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
6261 &pacl, &dflt)
6262 && dacl_present)
6263 flags |= DACL_SECURITY_INFORMATION;
6264 if (!flags)
6265 return 0;
6267 /* According to KB-245153, setting the owner will succeed if either:
6268 (1) the caller is the user who will be the new owner, and has the
6269 SE_TAKE_OWNERSHIP privilege, or
6270 (2) the caller has the SE_RESTORE privilege, in which case she can
6271 set any valid user or group as the owner
6273 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
6274 privileges, and disregard any failures in obtaining them. If
6275 these privileges cannot be obtained, and do not already exist in
6276 the calling thread's security token, this function could fail
6277 with EPERM. */
6278 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
6279 st++;
6280 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
6281 st++;
6283 e = errno;
6284 errno = 0;
6285 /* SetFileSecurity is deprecated by MS, and sometimes fails when
6286 DACL inheritance is involved, but it seems to preserve ownership
6287 better than SetNamedSecurityInfo, which is important e.g., in
6288 copy-file. */
6289 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
6291 err = GetLastError ();
6293 if (errno != ENOTSUP)
6294 err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
6295 psidOwner, psidGroup, pacl, NULL);
6297 else
6298 err = ERROR_SUCCESS;
6299 if (err != ERROR_SUCCESS)
6301 if (errno == ENOTSUP)
6303 else if (err == ERROR_INVALID_OWNER
6304 || err == ERROR_NOT_ALL_ASSIGNED
6305 || err == ERROR_ACCESS_DENIED)
6307 /* Maybe the requested ACL and the one the file already has
6308 are identical, in which case we can silently ignore the
6309 failure. (And no, Windows doesn't.) */
6310 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
6312 errno = EPERM;
6313 if (current_acl)
6315 char *acl_from = acl_to_text (current_acl, NULL);
6316 char *acl_to = acl_to_text (acl, NULL);
6318 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
6320 retval = 0;
6321 errno = e;
6323 if (acl_from)
6324 acl_free (acl_from);
6325 if (acl_to)
6326 acl_free (acl_to);
6327 acl_free (current_acl);
6330 else if (err == ERROR_FILE_NOT_FOUND
6331 || err == ERROR_PATH_NOT_FOUND
6332 /* ERROR_INVALID_NAME is what we get if
6333 w32-unicode-filenames is nil and the file cannot be
6334 encoded in the current ANSI codepage. */
6335 || err == ERROR_INVALID_NAME)
6336 errno = ENOENT;
6337 else
6338 errno = EACCES;
6340 else
6342 retval = 0;
6343 errno = e;
6346 if (st)
6348 if (st >= 2)
6349 restore_privilege (&old2);
6350 restore_privilege (&old1);
6351 revert_to_self ();
6354 return retval;
6358 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
6359 have a fixed max size for file names, so we don't need the kind of
6360 alloc/malloc/realloc dance the gnulib version does. We also don't
6361 support FD-relative symlinks. */
6362 char *
6363 careadlinkat (int fd, char const *filename,
6364 char *buffer, size_t buffer_size,
6365 struct allocator const *alloc,
6366 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6368 char linkname[MAX_UTF8_PATH];
6369 ssize_t link_size;
6371 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6373 if (link_size > 0)
6375 char *retval = buffer;
6377 linkname[link_size++] = '\0';
6378 if (link_size > buffer_size)
6379 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6380 if (retval)
6381 memcpy (retval, linkname, link_size);
6383 return retval;
6385 return NULL;
6389 w32_copy_file (const char *from, const char *to,
6390 int keep_time, int preserve_ownership, int copy_acls)
6392 acl_t acl = NULL;
6393 BOOL copy_result;
6394 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6395 char from_a[MAX_PATH], to_a[MAX_PATH];
6397 /* We ignore preserve_ownership for now. */
6398 preserve_ownership = preserve_ownership;
6400 if (copy_acls)
6402 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6403 if (acl == NULL && acl_errno_valid (errno))
6404 return -2;
6406 if (w32_unicode_filenames)
6408 filename_to_utf16 (from, from_w);
6409 filename_to_utf16 (to, to_w);
6410 copy_result = CopyFileW (from_w, to_w, FALSE);
6412 else
6414 filename_to_ansi (from, from_a);
6415 filename_to_ansi (to, to_a);
6416 copy_result = CopyFileA (from_a, to_a, FALSE);
6418 if (!copy_result)
6420 /* CopyFile doesn't set errno when it fails. By far the most
6421 "popular" reason is that the target is read-only. */
6422 DWORD err = GetLastError ();
6424 switch (err)
6426 case ERROR_FILE_NOT_FOUND:
6427 errno = ENOENT;
6428 break;
6429 case ERROR_ACCESS_DENIED:
6430 errno = EACCES;
6431 break;
6432 case ERROR_ENCRYPTION_FAILED:
6433 errno = EIO;
6434 break;
6435 default:
6436 errno = EPERM;
6437 break;
6440 if (acl)
6441 acl_free (acl);
6442 return -1;
6444 /* CopyFile retains the timestamp by default. However, see
6445 "Community Additions" for CopyFile: it sounds like that is not
6446 entirely true. Testing on Windows XP confirms that modified time
6447 is copied, but creation and last-access times are not.
6448 FIXME? */
6449 else if (!keep_time)
6451 struct timespec now;
6452 DWORD attributes;
6454 if (w32_unicode_filenames)
6456 /* Ensure file is writable while its times are set. */
6457 attributes = GetFileAttributesW (to_w);
6458 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6459 now = current_timespec ();
6460 if (set_file_times (-1, to, now, now))
6462 /* Restore original attributes. */
6463 SetFileAttributesW (to_w, attributes);
6464 if (acl)
6465 acl_free (acl);
6466 return -3;
6468 /* Restore original attributes. */
6469 SetFileAttributesW (to_w, attributes);
6471 else
6473 attributes = GetFileAttributesA (to_a);
6474 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6475 now = current_timespec ();
6476 if (set_file_times (-1, to, now, now))
6478 SetFileAttributesA (to_a, attributes);
6479 if (acl)
6480 acl_free (acl);
6481 return -3;
6483 SetFileAttributesA (to_a, attributes);
6486 if (acl != NULL)
6488 bool fail =
6489 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6490 acl_free (acl);
6491 if (fail && acl_errno_valid (errno))
6492 return -4;
6495 return 0;
6499 /* Support for browsing other processes and their attributes. See
6500 process.c for the Lisp bindings. */
6502 /* Helper wrapper functions. */
6504 static HANDLE WINAPI
6505 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6507 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6509 if (g_b_init_create_toolhelp32_snapshot == 0)
6511 g_b_init_create_toolhelp32_snapshot = 1;
6512 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6513 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6514 "CreateToolhelp32Snapshot");
6516 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6518 return INVALID_HANDLE_VALUE;
6520 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6523 static BOOL WINAPI
6524 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6526 static Process32First_Proc s_pfn_Process32_First = NULL;
6528 if (g_b_init_process32_first == 0)
6530 g_b_init_process32_first = 1;
6531 s_pfn_Process32_First = (Process32First_Proc)
6532 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6533 "Process32First");
6535 if (s_pfn_Process32_First == NULL)
6537 return FALSE;
6539 return (s_pfn_Process32_First (hSnapshot, lppe));
6542 static BOOL WINAPI
6543 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6545 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6547 if (g_b_init_process32_next == 0)
6549 g_b_init_process32_next = 1;
6550 s_pfn_Process32_Next = (Process32Next_Proc)
6551 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6552 "Process32Next");
6554 if (s_pfn_Process32_Next == NULL)
6556 return FALSE;
6558 return (s_pfn_Process32_Next (hSnapshot, lppe));
6561 static BOOL WINAPI
6562 open_thread_token (HANDLE ThreadHandle,
6563 DWORD DesiredAccess,
6564 BOOL OpenAsSelf,
6565 PHANDLE TokenHandle)
6567 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6568 HMODULE hm_advapi32 = NULL;
6569 if (is_windows_9x () == TRUE)
6571 SetLastError (ERROR_NOT_SUPPORTED);
6572 return FALSE;
6574 if (g_b_init_open_thread_token == 0)
6576 g_b_init_open_thread_token = 1;
6577 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6578 s_pfn_Open_Thread_Token =
6579 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6581 if (s_pfn_Open_Thread_Token == NULL)
6583 SetLastError (ERROR_NOT_SUPPORTED);
6584 return FALSE;
6586 return (
6587 s_pfn_Open_Thread_Token (
6588 ThreadHandle,
6589 DesiredAccess,
6590 OpenAsSelf,
6591 TokenHandle)
6595 static BOOL WINAPI
6596 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6598 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6599 HMODULE hm_advapi32 = NULL;
6600 if (is_windows_9x () == TRUE)
6602 return FALSE;
6604 if (g_b_init_impersonate_self == 0)
6606 g_b_init_impersonate_self = 1;
6607 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6608 s_pfn_Impersonate_Self =
6609 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6611 if (s_pfn_Impersonate_Self == NULL)
6613 return FALSE;
6615 return s_pfn_Impersonate_Self (ImpersonationLevel);
6618 static BOOL WINAPI
6619 revert_to_self (void)
6621 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6622 HMODULE hm_advapi32 = NULL;
6623 if (is_windows_9x () == TRUE)
6625 return FALSE;
6627 if (g_b_init_revert_to_self == 0)
6629 g_b_init_revert_to_self = 1;
6630 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6631 s_pfn_Revert_To_Self =
6632 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6634 if (s_pfn_Revert_To_Self == NULL)
6636 return FALSE;
6638 return s_pfn_Revert_To_Self ();
6641 static BOOL WINAPI
6642 get_process_memory_info (HANDLE h_proc,
6643 PPROCESS_MEMORY_COUNTERS mem_counters,
6644 DWORD bufsize)
6646 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6647 HMODULE hm_psapi = NULL;
6648 if (is_windows_9x () == TRUE)
6650 return FALSE;
6652 if (g_b_init_get_process_memory_info == 0)
6654 g_b_init_get_process_memory_info = 1;
6655 hm_psapi = LoadLibrary ("Psapi.dll");
6656 if (hm_psapi)
6657 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6658 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6660 if (s_pfn_Get_Process_Memory_Info == NULL)
6662 return FALSE;
6664 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6667 static BOOL WINAPI
6668 get_process_working_set_size (HANDLE h_proc,
6669 PSIZE_T minrss,
6670 PSIZE_T maxrss)
6672 static GetProcessWorkingSetSize_Proc
6673 s_pfn_Get_Process_Working_Set_Size = NULL;
6675 if (is_windows_9x () == TRUE)
6677 return FALSE;
6679 if (g_b_init_get_process_working_set_size == 0)
6681 g_b_init_get_process_working_set_size = 1;
6682 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6683 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6684 "GetProcessWorkingSetSize");
6686 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6688 return FALSE;
6690 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6693 static BOOL WINAPI
6694 global_memory_status (MEMORYSTATUS *buf)
6696 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6698 if (is_windows_9x () == TRUE)
6700 return FALSE;
6702 if (g_b_init_global_memory_status == 0)
6704 g_b_init_global_memory_status = 1;
6705 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6706 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6707 "GlobalMemoryStatus");
6709 if (s_pfn_Global_Memory_Status == NULL)
6711 return FALSE;
6713 return s_pfn_Global_Memory_Status (buf);
6716 static BOOL WINAPI
6717 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6719 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6721 if (is_windows_9x () == TRUE)
6723 return FALSE;
6725 if (g_b_init_global_memory_status_ex == 0)
6727 g_b_init_global_memory_status_ex = 1;
6728 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6729 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6730 "GlobalMemoryStatusEx");
6732 if (s_pfn_Global_Memory_Status_Ex == NULL)
6734 return FALSE;
6736 return s_pfn_Global_Memory_Status_Ex (buf);
6739 Lisp_Object
6740 list_system_processes (void)
6742 Lisp_Object proclist = Qnil;
6743 HANDLE h_snapshot;
6745 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6747 if (h_snapshot != INVALID_HANDLE_VALUE)
6749 PROCESSENTRY32 proc_entry;
6750 DWORD proc_id;
6751 BOOL res;
6753 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6754 for (res = process32_first (h_snapshot, &proc_entry); res;
6755 res = process32_next (h_snapshot, &proc_entry))
6757 proc_id = proc_entry.th32ProcessID;
6758 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6761 CloseHandle (h_snapshot);
6762 proclist = Fnreverse (proclist);
6765 return proclist;
6768 static int
6769 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6771 TOKEN_PRIVILEGES priv;
6772 DWORD priv_size = sizeof (priv);
6773 DWORD opriv_size = sizeof (*old_priv);
6774 HANDLE h_token = NULL;
6775 HANDLE h_thread = GetCurrentThread ();
6776 int ret_val = 0;
6777 BOOL res;
6779 res = open_thread_token (h_thread,
6780 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6781 FALSE, &h_token);
6782 if (!res && GetLastError () == ERROR_NO_TOKEN)
6784 if (impersonate_self (SecurityImpersonation))
6785 res = open_thread_token (h_thread,
6786 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6787 FALSE, &h_token);
6789 if (res)
6791 priv.PrivilegeCount = 1;
6792 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6793 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6794 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6795 old_priv, &opriv_size)
6796 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6797 ret_val = 1;
6799 if (h_token)
6800 CloseHandle (h_token);
6802 return ret_val;
6805 static int
6806 restore_privilege (TOKEN_PRIVILEGES *priv)
6808 DWORD priv_size = sizeof (*priv);
6809 HANDLE h_token = NULL;
6810 int ret_val = 0;
6812 if (open_thread_token (GetCurrentThread (),
6813 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6814 FALSE, &h_token))
6816 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6817 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6818 ret_val = 1;
6820 if (h_token)
6821 CloseHandle (h_token);
6823 return ret_val;
6826 static Lisp_Object
6827 ltime (ULONGLONG time_100ns)
6829 ULONGLONG time_sec = time_100ns / 10000000;
6830 int subsec = time_100ns % 10000000;
6831 return list4i (time_sec >> 16, time_sec & 0xffff,
6832 subsec / 10, subsec % 10 * 100000);
6835 #define U64_TO_LISP_TIME(time) ltime (time)
6837 static int
6838 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6839 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6840 double *pcpu)
6842 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6843 ULONGLONG tem1, tem2, tem3, tem;
6845 if (!h_proc
6846 || !get_process_times_fn
6847 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6848 &ft_kernel, &ft_user))
6849 return 0;
6851 GetSystemTimeAsFileTime (&ft_current);
6853 FILETIME_TO_U64 (tem1, ft_kernel);
6854 *stime = U64_TO_LISP_TIME (tem1);
6856 FILETIME_TO_U64 (tem2, ft_user);
6857 *utime = U64_TO_LISP_TIME (tem2);
6859 tem3 = tem1 + tem2;
6860 *ttime = U64_TO_LISP_TIME (tem3);
6862 FILETIME_TO_U64 (tem, ft_creation);
6863 /* Process no 4 (System) returns zero creation time. */
6864 if (tem)
6865 tem -= utc_base;
6866 *ctime = U64_TO_LISP_TIME (tem);
6868 if (tem)
6870 FILETIME_TO_U64 (tem3, ft_current);
6871 tem = (tem3 - utc_base) - tem;
6873 *etime = U64_TO_LISP_TIME (tem);
6875 if (tem)
6877 *pcpu = 100.0 * (tem1 + tem2) / tem;
6878 if (*pcpu > 100)
6879 *pcpu = 100.0;
6881 else
6882 *pcpu = 0;
6884 return 1;
6887 Lisp_Object
6888 system_process_attributes (Lisp_Object pid)
6890 Lisp_Object attrs = Qnil;
6891 Lisp_Object cmd_str, decoded_cmd, tem;
6892 HANDLE h_snapshot, h_proc;
6893 DWORD proc_id;
6894 int found_proc = 0;
6895 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
6896 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
6897 DWORD glength = sizeof (gname);
6898 HANDLE token = NULL;
6899 SID_NAME_USE user_type;
6900 unsigned char *buf = NULL;
6901 DWORD blen = 0;
6902 TOKEN_USER user_token;
6903 TOKEN_PRIMARY_GROUP group_token;
6904 unsigned euid;
6905 unsigned egid;
6906 PROCESS_MEMORY_COUNTERS mem;
6907 PROCESS_MEMORY_COUNTERS_EX mem_ex;
6908 SIZE_T minrss, maxrss;
6909 MEMORYSTATUS memst;
6910 MEMORY_STATUS_EX memstex;
6911 double totphys = 0.0;
6912 Lisp_Object ctime, stime, utime, etime, ttime;
6913 double pcpu;
6914 BOOL result = FALSE;
6916 CHECK_NUMBER_OR_FLOAT (pid);
6917 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
6919 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6921 if (h_snapshot != INVALID_HANDLE_VALUE)
6923 PROCESSENTRY32 pe;
6924 BOOL res;
6926 pe.dwSize = sizeof (PROCESSENTRY32);
6927 for (res = process32_first (h_snapshot, &pe); res;
6928 res = process32_next (h_snapshot, &pe))
6930 if (proc_id == pe.th32ProcessID)
6932 if (proc_id == 0)
6933 decoded_cmd = build_string ("Idle");
6934 else
6936 /* Decode the command name from locale-specific
6937 encoding. */
6938 cmd_str = build_unibyte_string (pe.szExeFile);
6940 decoded_cmd =
6941 code_convert_string_norecord (cmd_str,
6942 Vlocale_coding_system, 0);
6944 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
6945 attrs = Fcons (Fcons (Qppid,
6946 make_fixnum_or_float (pe.th32ParentProcessID)),
6947 attrs);
6948 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
6949 attrs);
6950 attrs = Fcons (Fcons (Qthcount,
6951 make_fixnum_or_float (pe.cntThreads)),
6952 attrs);
6953 found_proc = 1;
6954 break;
6958 CloseHandle (h_snapshot);
6961 if (!found_proc)
6962 return Qnil;
6964 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6965 FALSE, proc_id);
6966 /* If we were denied a handle to the process, try again after
6967 enabling the SeDebugPrivilege in our process. */
6968 if (!h_proc)
6970 TOKEN_PRIVILEGES priv_current;
6972 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
6974 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6975 FALSE, proc_id);
6976 restore_privilege (&priv_current);
6977 revert_to_self ();
6980 if (h_proc)
6982 result = open_process_token (h_proc, TOKEN_QUERY, &token);
6983 if (result)
6985 result = get_token_information (token, TokenUser, NULL, 0, &blen);
6986 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6988 buf = xmalloc (blen);
6989 result = get_token_information (token, TokenUser,
6990 (LPVOID)buf, blen, &needed);
6991 if (result)
6993 memcpy (&user_token, buf, sizeof (user_token));
6994 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
6996 euid = get_rid (user_token.User.Sid);
6997 result = lookup_account_sid (NULL, user_token.User.Sid,
6998 uname, &ulength,
6999 domain, &dlength,
7000 &user_type);
7001 if (result)
7002 w32_add_to_cache (user_token.User.Sid, euid, uname);
7003 else
7005 strcpy (uname, "unknown");
7006 result = TRUE;
7009 ulength = strlen (uname);
7013 if (result)
7015 /* Determine a reasonable euid and gid values. */
7016 if (xstrcasecmp ("administrator", uname) == 0)
7018 euid = 500; /* well-known Administrator uid */
7019 egid = 513; /* well-known None gid */
7021 else
7023 /* Get group id and name. */
7024 result = get_token_information (token, TokenPrimaryGroup,
7025 (LPVOID)buf, blen, &needed);
7026 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7028 buf = xrealloc (buf, blen = needed);
7029 result = get_token_information (token, TokenPrimaryGroup,
7030 (LPVOID)buf, blen, &needed);
7032 if (result)
7034 memcpy (&group_token, buf, sizeof (group_token));
7035 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
7037 egid = get_rid (group_token.PrimaryGroup);
7038 dlength = sizeof (domain);
7039 result =
7040 lookup_account_sid (NULL, group_token.PrimaryGroup,
7041 gname, &glength, NULL, &dlength,
7042 &user_type);
7043 if (result)
7044 w32_add_to_cache (group_token.PrimaryGroup,
7045 egid, gname);
7046 else
7048 strcpy (gname, "None");
7049 result = TRUE;
7052 glength = strlen (gname);
7056 xfree (buf);
7058 if (!result)
7060 if (!is_windows_9x ())
7062 /* We couldn't open the process token, presumably because of
7063 insufficient access rights. Assume this process is run
7064 by the system. */
7065 strcpy (uname, "SYSTEM");
7066 strcpy (gname, "None");
7067 euid = 18; /* SYSTEM */
7068 egid = 513; /* None */
7069 glength = strlen (gname);
7070 ulength = strlen (uname);
7072 /* If we are running under Windows 9X, where security calls are
7073 not supported, we assume all processes are run by the current
7074 user. */
7075 else if (GetUserName (uname, &ulength))
7077 if (xstrcasecmp ("administrator", uname) == 0)
7078 euid = 0;
7079 else
7080 euid = 123;
7081 egid = euid;
7082 strcpy (gname, "None");
7083 glength = strlen (gname);
7084 ulength = strlen (uname);
7086 else
7088 euid = 123;
7089 egid = 123;
7090 strcpy (uname, "administrator");
7091 ulength = strlen (uname);
7092 strcpy (gname, "None");
7093 glength = strlen (gname);
7095 if (token)
7096 CloseHandle (token);
7099 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
7100 tem = make_unibyte_string (uname, ulength);
7101 attrs = Fcons (Fcons (Quser,
7102 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7103 attrs);
7104 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
7105 tem = make_unibyte_string (gname, glength);
7106 attrs = Fcons (Fcons (Qgroup,
7107 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7108 attrs);
7110 if (global_memory_status_ex (&memstex))
7111 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
7112 totphys = memstex.ullTotalPhys / 1024.0;
7113 #else
7114 /* Visual Studio 6 cannot convert an unsigned __int64 type to
7115 double, so we need to do this for it... */
7117 DWORD tot_hi = memstex.ullTotalPhys >> 32;
7118 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
7119 DWORD tot_lo = memstex.ullTotalPhys % 1024;
7121 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
7123 #endif /* __GNUC__ || _MSC_VER >= 1300 */
7124 else if (global_memory_status (&memst))
7125 totphys = memst.dwTotalPhys / 1024.0;
7127 if (h_proc
7128 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
7129 sizeof (mem_ex)))
7131 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7133 attrs = Fcons (Fcons (Qmajflt,
7134 make_fixnum_or_float (mem_ex.PageFaultCount)),
7135 attrs);
7136 attrs = Fcons (Fcons (Qvsize,
7137 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
7138 attrs);
7139 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7140 if (totphys)
7141 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7143 else if (h_proc
7144 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
7146 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7148 attrs = Fcons (Fcons (Qmajflt,
7149 make_fixnum_or_float (mem.PageFaultCount)),
7150 attrs);
7151 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7152 if (totphys)
7153 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7155 else if (h_proc
7156 && get_process_working_set_size (h_proc, &minrss, &maxrss))
7158 DWORD rss = maxrss / 1024;
7160 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
7161 if (totphys)
7162 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7165 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
7167 attrs = Fcons (Fcons (Qutime, utime), attrs);
7168 attrs = Fcons (Fcons (Qstime, stime), attrs);
7169 attrs = Fcons (Fcons (Qtime, ttime), attrs);
7170 attrs = Fcons (Fcons (Qstart, ctime), attrs);
7171 attrs = Fcons (Fcons (Qetime, etime), attrs);
7172 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
7175 /* FIXME: Retrieve command line by walking the PEB of the process. */
7177 if (h_proc)
7178 CloseHandle (h_proc);
7179 return attrs;
7183 w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
7184 unsigned long long *totalswap, unsigned long long *freeswap)
7186 MEMORYSTATUS memst;
7187 MEMORY_STATUS_EX memstex;
7189 /* Use GlobalMemoryStatusEx if available, as it can report more than
7190 2GB of memory. */
7191 if (global_memory_status_ex (&memstex))
7193 *totalram = memstex.ullTotalPhys;
7194 *freeram = memstex.ullAvailPhys;
7195 *totalswap = memstex.ullTotalPageFile;
7196 *freeswap = memstex.ullAvailPageFile;
7197 return 0;
7199 else if (global_memory_status (&memst))
7201 *totalram = memst.dwTotalPhys;
7202 *freeram = memst.dwAvailPhys;
7203 *totalswap = memst.dwTotalPageFile;
7204 *freeswap = memst.dwAvailPageFile;
7205 return 0;
7207 else
7208 return -1;
7212 /* Wrappers for winsock functions to map between our file descriptors
7213 and winsock's handles; also set h_errno for convenience.
7215 To allow Emacs to run on systems which don't have winsock support
7216 installed, we dynamically link to winsock on startup if present, and
7217 otherwise provide the minimum necessary functionality
7218 (eg. gethostname). */
7220 /* function pointers for relevant socket functions */
7221 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
7222 void (PASCAL *pfn_WSASetLastError) (int iError);
7223 int (PASCAL *pfn_WSAGetLastError) (void);
7224 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
7225 int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject,
7226 WSANETWORKEVENTS *NetworkEvents);
7228 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
7229 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
7230 int (PASCAL *pfn_socket) (int af, int type, int protocol);
7231 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
7232 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
7233 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
7234 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
7235 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
7236 int (PASCAL *pfn_closesocket) (SOCKET s);
7237 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
7238 int (PASCAL *pfn_WSACleanup) (void);
7240 u_short (PASCAL *pfn_htons) (u_short hostshort);
7241 u_short (PASCAL *pfn_ntohs) (u_short netshort);
7242 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
7243 int (PASCAL *pfn_gethostname) (char * name, int namelen);
7244 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
7245 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
7246 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
7247 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
7248 const char * optval, int optlen);
7249 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
7250 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
7251 int * namelen);
7252 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
7253 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
7254 struct sockaddr * from, int * fromlen);
7255 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
7256 const struct sockaddr * to, int tolen);
7258 int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
7259 const struct addrinfo *, struct addrinfo **);
7260 void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
7262 /* SetHandleInformation is only needed to make sockets non-inheritable. */
7263 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7264 #ifndef HANDLE_FLAG_INHERIT
7265 #define HANDLE_FLAG_INHERIT 1
7266 #endif
7268 HANDLE winsock_lib;
7269 static int winsock_inuse;
7271 BOOL term_winsock (void);
7273 BOOL
7274 term_winsock (void)
7276 if (winsock_lib != NULL && winsock_inuse == 0)
7278 release_listen_threads ();
7279 /* Not sure what would cause WSAENETDOWN, or even if it can happen
7280 after WSAStartup returns successfully, but it seems reasonable
7281 to allow unloading winsock anyway in that case. */
7282 if (pfn_WSACleanup () == 0 ||
7283 pfn_WSAGetLastError () == WSAENETDOWN)
7285 if (FreeLibrary (winsock_lib))
7286 winsock_lib = NULL;
7287 return TRUE;
7290 return FALSE;
7293 BOOL
7294 init_winsock (int load_now)
7296 WSADATA winsockData;
7298 if (winsock_lib != NULL)
7299 return TRUE;
7301 pfn_SetHandleInformation
7302 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
7303 "SetHandleInformation");
7305 winsock_lib = LoadLibrary ("Ws2_32.dll");
7307 if (winsock_lib != NULL)
7309 /* dynamically link to socket functions */
7311 #define LOAD_PROC(fn) \
7312 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
7313 goto fail;
7315 LOAD_PROC (WSAStartup);
7316 LOAD_PROC (WSASetLastError);
7317 LOAD_PROC (WSAGetLastError);
7318 LOAD_PROC (WSAEventSelect);
7319 LOAD_PROC (WSAEnumNetworkEvents);
7320 LOAD_PROC (WSACreateEvent);
7321 LOAD_PROC (WSACloseEvent);
7322 LOAD_PROC (socket);
7323 LOAD_PROC (bind);
7324 LOAD_PROC (connect);
7325 LOAD_PROC (ioctlsocket);
7326 LOAD_PROC (recv);
7327 LOAD_PROC (send);
7328 LOAD_PROC (closesocket);
7329 LOAD_PROC (shutdown);
7330 LOAD_PROC (htons);
7331 LOAD_PROC (ntohs);
7332 LOAD_PROC (inet_addr);
7333 LOAD_PROC (gethostname);
7334 LOAD_PROC (gethostbyname);
7335 LOAD_PROC (getservbyname);
7336 LOAD_PROC (getpeername);
7337 LOAD_PROC (WSACleanup);
7338 LOAD_PROC (setsockopt);
7339 LOAD_PROC (listen);
7340 LOAD_PROC (getsockname);
7341 LOAD_PROC (accept);
7342 LOAD_PROC (recvfrom);
7343 LOAD_PROC (sendto);
7344 #undef LOAD_PROC
7346 /* Try loading functions not available before XP. */
7347 pfn_getaddrinfo = (void *) GetProcAddress (winsock_lib, "getaddrinfo");
7348 pfn_freeaddrinfo = (void *) GetProcAddress (winsock_lib, "freeaddrinfo");
7349 /* Paranoia: these two functions should go together, so if one
7350 is absent, we cannot use the other. */
7351 if (pfn_getaddrinfo == NULL)
7352 pfn_freeaddrinfo = NULL;
7353 else if (pfn_freeaddrinfo == NULL)
7354 pfn_getaddrinfo = NULL;
7356 /* specify version 1.1 of winsock */
7357 if (pfn_WSAStartup (0x101, &winsockData) == 0)
7359 if (winsockData.wVersion != 0x101)
7360 goto fail;
7362 if (!load_now)
7364 /* Report that winsock exists and is usable, but leave
7365 socket functions disabled. I am assuming that calling
7366 WSAStartup does not require any network interaction,
7367 and in particular does not cause or require a dial-up
7368 connection to be established. */
7370 pfn_WSACleanup ();
7371 FreeLibrary (winsock_lib);
7372 winsock_lib = NULL;
7374 winsock_inuse = 0;
7375 return TRUE;
7378 fail:
7379 FreeLibrary (winsock_lib);
7380 winsock_lib = NULL;
7383 return FALSE;
7387 int h_errno = 0;
7389 /* Function to map winsock error codes to errno codes for those errno
7390 code defined in errno.h (errno values not defined by errno.h are
7391 already in nt/inc/sys/socket.h). */
7392 static void
7393 set_errno (void)
7395 int wsa_err;
7397 h_errno = 0;
7398 if (winsock_lib == NULL)
7399 wsa_err = EINVAL;
7400 else
7401 wsa_err = pfn_WSAGetLastError ();
7403 switch (wsa_err)
7405 case WSAEACCES: errno = EACCES; break;
7406 case WSAEBADF: errno = EBADF; break;
7407 case WSAEFAULT: errno = EFAULT; break;
7408 case WSAEINTR: errno = EINTR; break;
7409 case WSAEINVAL: errno = EINVAL; break;
7410 case WSAEMFILE: errno = EMFILE; break;
7411 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7412 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7413 case WSAEWOULDBLOCK: errno = EWOULDBLOCK; break;
7414 case WSAENOTCONN: errno = ENOTCONN; break;
7415 default: errno = wsa_err; break;
7419 static void
7420 check_errno (void)
7422 h_errno = 0;
7423 if (winsock_lib != NULL)
7424 pfn_WSASetLastError (0);
7427 /* Extend strerror to handle the winsock-specific error codes. */
7428 struct {
7429 int errnum;
7430 const char * msg;
7431 } _wsa_errlist[] = {
7432 {WSAEINTR , "Interrupted function call"},
7433 {WSAEBADF , "Bad file descriptor"},
7434 {WSAEACCES , "Permission denied"},
7435 {WSAEFAULT , "Bad address"},
7436 {WSAEINVAL , "Invalid argument"},
7437 {WSAEMFILE , "Too many open files"},
7439 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7440 {WSAEINPROGRESS , "Operation now in progress"},
7441 {WSAEALREADY , "Operation already in progress"},
7442 {WSAENOTSOCK , "Socket operation on non-socket"},
7443 {WSAEDESTADDRREQ , "Destination address required"},
7444 {WSAEMSGSIZE , "Message too long"},
7445 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7446 {WSAENOPROTOOPT , "Bad protocol option"},
7447 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7448 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7449 {WSAEOPNOTSUPP , "Operation not supported"},
7450 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7451 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7452 {WSAEADDRINUSE , "Address already in use"},
7453 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7454 {WSAENETDOWN , "Network is down"},
7455 {WSAENETUNREACH , "Network is unreachable"},
7456 {WSAENETRESET , "Network dropped connection on reset"},
7457 {WSAECONNABORTED , "Software caused connection abort"},
7458 {WSAECONNRESET , "Connection reset by peer"},
7459 {WSAENOBUFS , "No buffer space available"},
7460 {WSAEISCONN , "Socket is already connected"},
7461 {WSAENOTCONN , "Socket is not connected"},
7462 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7463 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7464 {WSAETIMEDOUT , "Connection timed out"},
7465 {WSAECONNREFUSED , "Connection refused"},
7466 {WSAELOOP , "Network loop"}, /* not sure */
7467 {WSAENAMETOOLONG , "Name is too long"},
7468 {WSAEHOSTDOWN , "Host is down"},
7469 {WSAEHOSTUNREACH , "No route to host"},
7470 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7471 {WSAEPROCLIM , "Too many processes"},
7472 {WSAEUSERS , "Too many users"}, /* not sure */
7473 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7474 {WSAESTALE , "Data is stale"}, /* not sure */
7475 {WSAEREMOTE , "Remote error"}, /* not sure */
7477 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7478 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7479 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7480 {WSAEDISCON , "Graceful shutdown in progress"},
7481 #ifdef WSAENOMORE
7482 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7483 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7484 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7485 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7486 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7487 {WSASYSCALLFAILURE , "System call failure"},
7488 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7489 {WSATYPE_NOT_FOUND , "Class type not found"},
7490 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7491 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7492 {WSAEREFUSED , "Operation refused"}, /* not sure */
7493 #endif
7495 {WSAHOST_NOT_FOUND , "Host not found"},
7496 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7497 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7498 {WSANO_DATA , "Valid name, no data record of requested type"},
7500 {-1, NULL}
7503 char *
7504 sys_strerror (int error_no)
7506 int i;
7507 static char unknown_msg[40];
7509 if (error_no >= 0 && error_no < sys_nerr)
7510 return sys_errlist[error_no];
7512 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7513 if (_wsa_errlist[i].errnum == error_no)
7514 return (char *)_wsa_errlist[i].msg;
7516 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7517 return unknown_msg;
7520 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7521 but I believe the method of keeping the socket handle separate (and
7522 insuring it is not inheritable) is the correct one. */
7524 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7526 static int socket_to_fd (SOCKET s);
7529 sys_socket (int af, int type, int protocol)
7531 SOCKET s;
7533 if (winsock_lib == NULL)
7535 errno = ENETDOWN;
7536 return -1;
7539 check_errno ();
7541 /* call the real socket function */
7542 s = pfn_socket (af, type, protocol);
7544 if (s != INVALID_SOCKET)
7545 return socket_to_fd (s);
7547 set_errno ();
7548 return -1;
7551 /* Convert a SOCKET to a file descriptor. */
7552 static int
7553 socket_to_fd (SOCKET s)
7555 int fd;
7556 child_process * cp;
7558 /* Although under NT 3.5 _open_osfhandle will accept a socket
7559 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7560 that does not work under NT 3.1. However, we can get the same
7561 effect by using a backdoor function to replace an existing
7562 descriptor handle with the one we want. */
7564 /* allocate a file descriptor (with appropriate flags) */
7565 fd = _open ("NUL:", _O_RDWR);
7566 if (fd >= 0)
7568 /* Make a non-inheritable copy of the socket handle. Note
7569 that it is possible that sockets aren't actually kernel
7570 handles, which appears to be the case on Windows 9x when
7571 the MS Proxy winsock client is installed. */
7573 /* Apparently there is a bug in NT 3.51 with some service
7574 packs, which prevents using DuplicateHandle to make a
7575 socket handle non-inheritable (causes WSACleanup to
7576 hang). The work-around is to use SetHandleInformation
7577 instead if it is available and implemented. */
7578 if (pfn_SetHandleInformation)
7580 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7582 else
7584 HANDLE parent = GetCurrentProcess ();
7585 HANDLE new_s = INVALID_HANDLE_VALUE;
7587 if (DuplicateHandle (parent,
7588 (HANDLE) s,
7589 parent,
7590 &new_s,
7592 FALSE,
7593 DUPLICATE_SAME_ACCESS))
7595 /* It is possible that DuplicateHandle succeeds even
7596 though the socket wasn't really a kernel handle,
7597 because a real handle has the same value. So
7598 test whether the new handle really is a socket. */
7599 unsigned long nonblocking = 0;
7600 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7602 pfn_closesocket (s);
7603 s = (SOCKET) new_s;
7605 else
7607 CloseHandle (new_s);
7612 eassert (fd < MAXDESC);
7613 fd_info[fd].hnd = (HANDLE) s;
7615 /* set our own internal flags */
7616 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7618 cp = new_child ();
7619 if (cp)
7621 cp->fd = fd;
7622 cp->status = STATUS_READ_ACKNOWLEDGED;
7624 /* attach child_process to fd_info */
7625 if (fd_info[ fd ].cp != NULL)
7627 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7628 emacs_abort ();
7631 fd_info[ fd ].cp = cp;
7633 /* success! */
7634 winsock_inuse++; /* count open sockets */
7635 return fd;
7638 /* clean up */
7639 _close (fd);
7641 else
7642 pfn_closesocket (s);
7643 errno = EMFILE;
7644 return -1;
7648 sys_bind (int s, const struct sockaddr * addr, int namelen)
7650 if (winsock_lib == NULL)
7652 errno = ENOTSOCK;
7653 return SOCKET_ERROR;
7656 check_errno ();
7657 if (fd_info[s].flags & FILE_SOCKET)
7659 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7660 if (rc == SOCKET_ERROR)
7661 set_errno ();
7662 return rc;
7664 errno = ENOTSOCK;
7665 return SOCKET_ERROR;
7669 sys_connect (int s, const struct sockaddr * name, int namelen)
7671 if (winsock_lib == NULL)
7673 errno = ENOTSOCK;
7674 return SOCKET_ERROR;
7677 check_errno ();
7678 if (fd_info[s].flags & FILE_SOCKET)
7680 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7681 if (rc == SOCKET_ERROR)
7683 set_errno ();
7684 /* If this is a non-blocking 'connect', set the bit in flags
7685 that will tell reader_thread to wait for connection
7686 before trying to read. */
7687 if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0)
7689 errno = EINPROGRESS; /* that's what process.c expects */
7690 fd_info[s].flags |= FILE_CONNECT;
7693 return rc;
7695 errno = ENOTSOCK;
7696 return SOCKET_ERROR;
7699 u_short
7700 sys_htons (u_short hostshort)
7702 return (winsock_lib != NULL) ?
7703 pfn_htons (hostshort) : hostshort;
7706 u_short
7707 sys_ntohs (u_short netshort)
7709 return (winsock_lib != NULL) ?
7710 pfn_ntohs (netshort) : netshort;
7713 unsigned long
7714 sys_inet_addr (const char * cp)
7716 return (winsock_lib != NULL) ?
7717 pfn_inet_addr (cp) : INADDR_NONE;
7721 sys_gethostname (char * name, int namelen)
7723 if (winsock_lib != NULL)
7725 int retval;
7727 check_errno ();
7728 retval = pfn_gethostname (name, namelen);
7729 if (retval == SOCKET_ERROR)
7730 set_errno ();
7731 return retval;
7734 if (namelen > MAX_COMPUTERNAME_LENGTH)
7735 return !GetComputerName (name, (DWORD *)&namelen);
7737 errno = EFAULT;
7738 return SOCKET_ERROR;
7741 struct hostent *
7742 sys_gethostbyname (const char * name)
7744 struct hostent * host;
7745 int h_err = h_errno;
7747 if (winsock_lib == NULL)
7749 h_errno = NO_RECOVERY;
7750 errno = ENETDOWN;
7751 return NULL;
7754 check_errno ();
7755 host = pfn_gethostbyname (name);
7756 if (!host)
7758 set_errno ();
7759 h_errno = errno;
7761 else
7762 h_errno = h_err;
7763 return host;
7766 struct servent *
7767 sys_getservbyname (const char * name, const char * proto)
7769 struct servent * serv;
7771 if (winsock_lib == NULL)
7773 errno = ENETDOWN;
7774 return NULL;
7777 check_errno ();
7778 serv = pfn_getservbyname (name, proto);
7779 if (!serv)
7780 set_errno ();
7781 return serv;
7785 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7787 if (winsock_lib == NULL)
7789 errno = ENETDOWN;
7790 return SOCKET_ERROR;
7793 check_errno ();
7794 if (fd_info[s].flags & FILE_SOCKET)
7796 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7797 if (rc == SOCKET_ERROR)
7798 set_errno ();
7799 return rc;
7801 errno = ENOTSOCK;
7802 return SOCKET_ERROR;
7806 sys_getaddrinfo (const char *node, const char *service,
7807 const struct addrinfo *hints, struct addrinfo **res)
7809 int rc;
7811 if (winsock_lib == NULL)
7813 errno = ENETDOWN;
7814 return SOCKET_ERROR;
7817 check_errno ();
7818 if (pfn_getaddrinfo)
7819 rc = pfn_getaddrinfo (node, service, hints, res);
7820 else
7822 int port = 0;
7823 struct hostent *host_info;
7824 struct gai_storage {
7825 struct addrinfo addrinfo;
7826 struct sockaddr_in sockaddr_in;
7827 } *gai_storage;
7829 /* We don't (yet) support any flags, as Emacs doesn't need that. */
7830 if (hints && hints->ai_flags != 0)
7831 return WSAEINVAL;
7832 /* NODE cannot be NULL, since process.c has fallbacks for that. */
7833 if (!node)
7834 return WSAHOST_NOT_FOUND;
7836 if (service)
7838 const char *protocol =
7839 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
7840 struct servent *srv = sys_getservbyname (service, protocol);
7842 if (srv)
7843 port = srv->s_port;
7844 else if (*service >= '0' && *service <= '9')
7846 char *endp;
7848 port = strtoul (service, &endp, 10);
7849 if (*endp || port > 65536)
7850 return WSAHOST_NOT_FOUND;
7851 port = sys_htons ((unsigned short) port);
7853 else
7854 return WSAHOST_NOT_FOUND;
7857 gai_storage = xzalloc (sizeof *gai_storage);
7858 gai_storage->sockaddr_in.sin_port = port;
7859 host_info = sys_gethostbyname (node);
7860 if (host_info)
7862 memcpy (&gai_storage->sockaddr_in.sin_addr,
7863 host_info->h_addr, host_info->h_length);
7864 gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
7866 else
7868 /* Attempt to interpret host as numeric inet address. */
7869 unsigned long numeric_addr = sys_inet_addr (node);
7871 if (numeric_addr == -1)
7873 free (gai_storage);
7874 return WSAHOST_NOT_FOUND;
7877 memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
7878 sizeof (gai_storage->sockaddr_in.sin_addr));
7879 gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
7882 gai_storage->addrinfo.ai_addr =
7883 (struct sockaddr *)&gai_storage->sockaddr_in;
7884 gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
7885 gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
7886 gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
7887 gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
7888 gai_storage->addrinfo.ai_next = NULL;
7890 *res = &gai_storage->addrinfo;
7891 rc = 0;
7894 return rc;
7897 void
7898 sys_freeaddrinfo (struct addrinfo *ai)
7900 if (winsock_lib == NULL)
7902 errno = ENETDOWN;
7903 return;
7906 check_errno ();
7907 if (pfn_freeaddrinfo)
7908 pfn_freeaddrinfo (ai);
7909 else
7911 eassert (ai->ai_next == NULL);
7912 xfree (ai);
7917 sys_shutdown (int s, int how)
7919 if (winsock_lib == NULL)
7921 errno = ENETDOWN;
7922 return SOCKET_ERROR;
7925 check_errno ();
7926 if (fd_info[s].flags & FILE_SOCKET)
7928 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
7929 if (rc == SOCKET_ERROR)
7930 set_errno ();
7931 return rc;
7933 errno = ENOTSOCK;
7934 return SOCKET_ERROR;
7938 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
7940 if (winsock_lib == NULL)
7942 errno = ENETDOWN;
7943 return SOCKET_ERROR;
7946 check_errno ();
7947 if (fd_info[s].flags & FILE_SOCKET)
7949 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
7950 (const char *)optval, optlen);
7951 if (rc == SOCKET_ERROR)
7952 set_errno ();
7953 return rc;
7955 errno = ENOTSOCK;
7956 return SOCKET_ERROR;
7960 sys_listen (int s, int backlog)
7962 if (winsock_lib == NULL)
7964 errno = ENETDOWN;
7965 return SOCKET_ERROR;
7968 check_errno ();
7969 if (fd_info[s].flags & FILE_SOCKET)
7971 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
7972 if (rc == SOCKET_ERROR)
7973 set_errno ();
7974 else
7975 fd_info[s].flags |= FILE_LISTEN;
7976 return rc;
7978 errno = ENOTSOCK;
7979 return SOCKET_ERROR;
7983 sys_getsockname (int s, struct sockaddr * name, int * namelen)
7985 if (winsock_lib == NULL)
7987 errno = ENETDOWN;
7988 return SOCKET_ERROR;
7991 check_errno ();
7992 if (fd_info[s].flags & FILE_SOCKET)
7994 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
7995 if (rc == SOCKET_ERROR)
7996 set_errno ();
7997 return rc;
7999 errno = ENOTSOCK;
8000 return SOCKET_ERROR;
8004 sys_accept (int s, struct sockaddr * addr, int * addrlen)
8006 if (winsock_lib == NULL)
8008 errno = ENETDOWN;
8009 return -1;
8012 check_errno ();
8013 if (fd_info[s].flags & FILE_LISTEN)
8015 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
8016 int fd = -1;
8017 if (t == INVALID_SOCKET)
8018 set_errno ();
8019 else
8020 fd = socket_to_fd (t);
8022 if (fd >= 0)
8024 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
8025 ResetEvent (fd_info[s].cp->char_avail);
8027 return fd;
8029 errno = ENOTSOCK;
8030 return -1;
8034 sys_recvfrom (int s, char * buf, int len, int flags,
8035 struct sockaddr * from, int * fromlen)
8037 if (winsock_lib == NULL)
8039 errno = ENETDOWN;
8040 return SOCKET_ERROR;
8043 check_errno ();
8044 if (fd_info[s].flags & FILE_SOCKET)
8046 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
8047 if (rc == SOCKET_ERROR)
8048 set_errno ();
8049 return rc;
8051 errno = ENOTSOCK;
8052 return SOCKET_ERROR;
8056 sys_sendto (int s, const char * buf, int len, int flags,
8057 const struct sockaddr * to, int tolen)
8059 if (winsock_lib == NULL)
8061 errno = ENETDOWN;
8062 return SOCKET_ERROR;
8065 check_errno ();
8066 if (fd_info[s].flags & FILE_SOCKET)
8068 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
8069 if (rc == SOCKET_ERROR)
8070 set_errno ();
8071 return rc;
8073 errno = ENOTSOCK;
8074 return SOCKET_ERROR;
8077 /* Windows does not have an fcntl function. Provide an implementation
8078 good enough for Emacs. */
8080 fcntl (int s, int cmd, int options)
8082 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
8083 invoked in a context where fd1 is closed and all descriptors less
8084 than fd1 are open, so sys_dup is an adequate implementation. */
8085 if (cmd == F_DUPFD_CLOEXEC)
8086 return sys_dup (s);
8088 check_errno ();
8089 if (fd_info[s].flags & FILE_SOCKET)
8091 if (winsock_lib == NULL)
8093 errno = ENETDOWN;
8094 return -1;
8097 if (cmd == F_SETFL && options == O_NONBLOCK)
8099 unsigned long nblock = 1;
8100 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
8101 if (rc == SOCKET_ERROR)
8102 set_errno ();
8103 /* Keep track of the fact that we set this to non-blocking. */
8104 fd_info[s].flags |= FILE_NDELAY;
8105 return rc;
8107 else
8109 errno = EINVAL;
8110 return SOCKET_ERROR;
8113 else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE))
8114 == (FILE_PIPE | FILE_WRITE))
8116 /* Force our writes to pipes be non-blocking. */
8117 if (cmd == F_SETFL && options == O_NONBLOCK)
8119 HANDLE h = (HANDLE)_get_osfhandle (s);
8120 DWORD pipe_mode = PIPE_NOWAIT;
8122 if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL))
8124 DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ()));
8125 return SOCKET_ERROR;
8127 fd_info[s].flags |= FILE_NDELAY;
8128 return 0;
8130 else
8132 errno = EINVAL;
8133 return SOCKET_ERROR;
8136 errno = ENOTSOCK;
8137 return SOCKET_ERROR;
8141 /* Shadow main io functions: we need to handle pipes and sockets more
8142 intelligently. */
8145 sys_close (int fd)
8147 int rc;
8149 if (fd < 0)
8151 errno = EBADF;
8152 return -1;
8155 if (fd < MAXDESC && fd_info[fd].cp)
8157 child_process * cp = fd_info[fd].cp;
8159 fd_info[fd].cp = NULL;
8161 if (CHILD_ACTIVE (cp))
8163 /* if last descriptor to active child_process then cleanup */
8164 int i;
8165 for (i = 0; i < MAXDESC; i++)
8167 if (i == fd)
8168 continue;
8169 if (fd_info[i].cp == cp)
8170 break;
8172 if (i == MAXDESC)
8174 if (fd_info[fd].flags & FILE_SOCKET)
8176 if (winsock_lib == NULL) emacs_abort ();
8178 pfn_shutdown (SOCK_HANDLE (fd), 2);
8179 rc = pfn_closesocket (SOCK_HANDLE (fd));
8181 winsock_inuse--; /* count open sockets */
8183 /* If the process handle is NULL, it's either a socket
8184 or serial connection, or a subprocess that was
8185 already reaped by reap_subprocess, but whose
8186 resources were not yet freed, because its output was
8187 not fully read yet by the time it was reaped. (This
8188 usually happens with async subprocesses whose output
8189 is being read by Emacs.) Otherwise, this process was
8190 not reaped yet, so we set its FD to a negative value
8191 to make sure sys_select will eventually get to
8192 calling the SIGCHLD handler for it, which will then
8193 invoke waitpid and reap_subprocess. */
8194 if (cp->procinfo.hProcess == NULL)
8195 delete_child (cp);
8196 else
8197 cp->fd = -1;
8202 if (fd >= 0 && fd < MAXDESC)
8203 fd_info[fd].flags = 0;
8205 /* Note that sockets do not need special treatment here (at least on
8206 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
8207 closesocket is equivalent to CloseHandle, which is to be expected
8208 because socket handles are fully fledged kernel handles. */
8209 rc = _close (fd);
8211 return rc;
8215 sys_dup (int fd)
8217 int new_fd;
8219 new_fd = _dup (fd);
8220 if (new_fd >= 0 && new_fd < MAXDESC)
8222 /* duplicate our internal info as well */
8223 fd_info[new_fd] = fd_info[fd];
8225 return new_fd;
8229 sys_dup2 (int src, int dst)
8231 int rc;
8233 if (dst < 0 || dst >= MAXDESC)
8235 errno = EBADF;
8236 return -1;
8239 /* MS _dup2 seems to have weird side effect when invoked with 2
8240 identical arguments: an attempt to fclose the corresponding stdio
8241 stream after that hangs (we do close standard streams in
8242 init_ntproc). Attempt to avoid that by not calling _dup2 that
8243 way: if SRC is valid, we know that dup2 should be a no-op, so do
8244 nothing and return DST. */
8245 if (src == dst)
8247 if ((HANDLE)_get_osfhandle (src) == INVALID_HANDLE_VALUE)
8249 errno = EBADF;
8250 return -1;
8252 return dst;
8255 /* Make sure we close the destination first if it's a pipe or socket. */
8256 if (fd_info[dst].flags != 0)
8257 sys_close (dst);
8259 rc = _dup2 (src, dst);
8260 if (rc == 0)
8262 /* Duplicate our internal info as well. */
8263 fd_info[dst] = fd_info[src];
8265 return rc == 0 ? dst : rc;
8269 pipe2 (int * phandles, int pipe2_flags)
8271 int rc;
8272 unsigned flags;
8273 unsigned pipe_size = 0;
8275 eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
8277 /* Allow Lisp to override the default buffer size of the pipe. */
8278 if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
8279 pipe_size = w32_pipe_buffer_size;
8281 /* make pipe handles non-inheritable; when we spawn a child, we
8282 replace the relevant handle with an inheritable one. Also put
8283 pipes into binary mode; we will do text mode translation ourselves
8284 if required. */
8285 rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
8287 if (rc == 0)
8289 /* Protect against overflow, since Windows can open more handles than
8290 our fd_info array has room for. */
8291 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
8293 _close (phandles[0]);
8294 _close (phandles[1]);
8295 errno = EMFILE;
8296 rc = -1;
8298 else
8300 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
8301 fd_info[phandles[0]].flags = flags;
8303 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
8304 fd_info[phandles[1]].flags = flags;
8308 return rc;
8311 /* Function to do blocking read of one byte, needed to implement
8312 select. It is only allowed on communication ports, sockets, or
8313 pipes. */
8315 _sys_read_ahead (int fd)
8317 child_process * cp;
8318 int rc;
8320 if (fd < 0 || fd >= MAXDESC)
8321 return STATUS_READ_ERROR;
8323 cp = fd_info[fd].cp;
8325 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8326 return STATUS_READ_ERROR;
8328 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
8329 || (fd_info[fd].flags & FILE_READ) == 0)
8331 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
8332 emacs_abort ();
8335 if ((fd_info[fd].flags & FILE_CONNECT) != 0)
8336 DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd));
8337 cp->status = STATUS_READ_IN_PROGRESS;
8339 if (fd_info[fd].flags & FILE_PIPE)
8341 rc = _read (fd, &cp->chr, sizeof (char));
8343 /* Give subprocess time to buffer some more output for us before
8344 reporting that input is available; we need this because Windows 95
8345 connects DOS programs to pipes by making the pipe appear to be
8346 the normal console stdout - as a result most DOS programs will
8347 write to stdout without buffering, ie. one character at a
8348 time. Even some W32 programs do this - "dir" in a command
8349 shell on NT is very slow if we don't do this. */
8350 if (rc > 0)
8352 int wait = w32_pipe_read_delay;
8354 if (wait > 0)
8355 Sleep (wait);
8356 else if (wait < 0)
8357 while (++wait <= 0)
8358 /* Yield remainder of our time slice, effectively giving a
8359 temporary priority boost to the child process. */
8360 Sleep (0);
8363 else if (fd_info[fd].flags & FILE_SERIAL)
8365 HANDLE hnd = fd_info[fd].hnd;
8366 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8367 COMMTIMEOUTS ct;
8369 /* Configure timeouts for blocking read. */
8370 if (!GetCommTimeouts (hnd, &ct))
8372 cp->status = STATUS_READ_ERROR;
8373 return STATUS_READ_ERROR;
8375 ct.ReadIntervalTimeout = 0;
8376 ct.ReadTotalTimeoutMultiplier = 0;
8377 ct.ReadTotalTimeoutConstant = 0;
8378 if (!SetCommTimeouts (hnd, &ct))
8380 cp->status = STATUS_READ_ERROR;
8381 return STATUS_READ_ERROR;
8384 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
8386 if (GetLastError () != ERROR_IO_PENDING)
8388 cp->status = STATUS_READ_ERROR;
8389 return STATUS_READ_ERROR;
8391 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8393 cp->status = STATUS_READ_ERROR;
8394 return STATUS_READ_ERROR;
8398 else if (fd_info[fd].flags & FILE_SOCKET)
8400 unsigned long nblock = 0;
8401 /* We always want this to block, so temporarily disable NDELAY. */
8402 if (fd_info[fd].flags & FILE_NDELAY)
8403 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8405 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
8407 if (fd_info[fd].flags & FILE_NDELAY)
8409 nblock = 1;
8410 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8414 if (rc == sizeof (char))
8415 cp->status = STATUS_READ_SUCCEEDED;
8416 else
8417 cp->status = STATUS_READ_FAILED;
8419 return cp->status;
8423 _sys_wait_accept (int fd)
8425 HANDLE hEv;
8426 child_process * cp;
8427 int rc;
8429 if (fd < 0 || fd >= MAXDESC)
8430 return STATUS_READ_ERROR;
8432 cp = fd_info[fd].cp;
8434 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8435 return STATUS_READ_ERROR;
8437 cp->status = STATUS_READ_FAILED;
8439 hEv = pfn_WSACreateEvent ();
8440 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
8441 if (rc != SOCKET_ERROR)
8443 do {
8444 rc = WaitForSingleObject (hEv, 500);
8445 Sleep (5);
8446 } while (rc == WAIT_TIMEOUT
8447 && cp->status != STATUS_READ_ERROR
8448 && cp->char_avail);
8449 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8450 if (rc == WAIT_OBJECT_0)
8451 cp->status = STATUS_READ_SUCCEEDED;
8453 pfn_WSACloseEvent (hEv);
8455 return cp->status;
8459 _sys_wait_connect (int fd)
8461 HANDLE hEv;
8462 child_process * cp;
8463 int rc;
8465 if (fd < 0 || fd >= MAXDESC)
8466 return STATUS_READ_ERROR;
8468 cp = fd_info[fd].cp;
8469 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8470 return STATUS_READ_ERROR;
8472 cp->status = STATUS_READ_FAILED;
8474 hEv = pfn_WSACreateEvent ();
8475 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT);
8476 if (rc != SOCKET_ERROR)
8478 do {
8479 rc = WaitForSingleObject (hEv, 500);
8480 Sleep (5);
8481 } while (rc == WAIT_TIMEOUT
8482 && cp->status != STATUS_READ_ERROR
8483 && cp->char_avail);
8484 if (rc == WAIT_OBJECT_0)
8486 /* We've got an event, but it could be a successful
8487 connection, or it could be a failure. Find out
8488 which one is it. */
8489 WSANETWORKEVENTS events;
8491 pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events);
8492 if ((events.lNetworkEvents & FD_CONNECT) != 0
8493 && events.iErrorCode[FD_CONNECT_BIT])
8495 cp->status = STATUS_CONNECT_FAILED;
8496 cp->errcode = events.iErrorCode[FD_CONNECT_BIT];
8498 else
8500 cp->status = STATUS_READ_SUCCEEDED;
8501 cp->errcode = 0;
8504 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8506 else
8507 pfn_WSACloseEvent (hEv);
8509 return cp->status;
8513 sys_read (int fd, char * buffer, unsigned int count)
8515 int nchars;
8516 int to_read;
8517 DWORD waiting;
8518 char * orig_buffer = buffer;
8520 if (fd < 0)
8522 errno = EBADF;
8523 return -1;
8526 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8528 child_process *cp = fd_info[fd].cp;
8530 if ((fd_info[fd].flags & FILE_READ) == 0)
8532 errno = EBADF;
8533 return -1;
8536 nchars = 0;
8538 /* re-read CR carried over from last read */
8539 if (fd_info[fd].flags & FILE_LAST_CR)
8541 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
8542 *buffer++ = 0x0d;
8543 count--;
8544 nchars++;
8545 fd_info[fd].flags &= ~FILE_LAST_CR;
8548 /* presence of a child_process structure means we are operating in
8549 non-blocking mode - otherwise we just call _read directly.
8550 Note that the child_process structure might be missing because
8551 reap_subprocess has been called; in this case the pipe is
8552 already broken, so calling _read on it is okay. */
8553 if (cp)
8555 int current_status = cp->status;
8557 switch (current_status)
8559 case STATUS_READ_FAILED:
8560 case STATUS_READ_ERROR:
8561 /* report normal EOF if nothing in buffer */
8562 if (nchars <= 0)
8563 fd_info[fd].flags |= FILE_AT_EOF;
8564 return nchars;
8566 case STATUS_READ_READY:
8567 case STATUS_READ_IN_PROGRESS:
8568 #if 0
8569 /* This happens all the time during GnuTLS handshake
8570 with the remote, evidently because GnuTLS waits for
8571 the read to complete by retrying the read operation
8572 upon EAGAIN. So I'm disabling the DebPrint to avoid
8573 wasting cycles on something that is not a real
8574 problem. Enable if you need to debug something that
8575 bumps into this. */
8576 DebPrint (("sys_read called when read is in progress %d\n",
8577 current_status));
8578 #endif
8579 errno = EWOULDBLOCK;
8580 return -1;
8582 case STATUS_READ_SUCCEEDED:
8583 /* consume read-ahead char */
8584 *buffer++ = cp->chr;
8585 count--;
8586 nchars++;
8587 cp->status = STATUS_READ_ACKNOWLEDGED;
8588 ResetEvent (cp->char_avail);
8590 case STATUS_READ_ACKNOWLEDGED:
8591 case STATUS_CONNECT_FAILED:
8592 break;
8594 default:
8595 DebPrint (("sys_read: bad status %d\n", current_status));
8596 errno = EBADF;
8597 return -1;
8600 if (fd_info[fd].flags & FILE_PIPE)
8602 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
8603 to_read = min (waiting, (DWORD) count);
8605 if (to_read > 0)
8606 nchars += _read (fd, buffer, to_read);
8608 else if (fd_info[fd].flags & FILE_SERIAL)
8610 HANDLE hnd = fd_info[fd].hnd;
8611 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8612 int rc = 0;
8613 COMMTIMEOUTS ct;
8615 if (count > 0)
8617 /* Configure timeouts for non-blocking read. */
8618 if (!GetCommTimeouts (hnd, &ct))
8620 errno = EIO;
8621 return -1;
8623 ct.ReadIntervalTimeout = MAXDWORD;
8624 ct.ReadTotalTimeoutMultiplier = 0;
8625 ct.ReadTotalTimeoutConstant = 0;
8626 if (!SetCommTimeouts (hnd, &ct))
8628 errno = EIO;
8629 return -1;
8632 if (!ResetEvent (ovl->hEvent))
8634 errno = EIO;
8635 return -1;
8637 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8639 if (GetLastError () != ERROR_IO_PENDING)
8641 errno = EIO;
8642 return -1;
8644 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8646 errno = EIO;
8647 return -1;
8650 nchars += rc;
8653 else /* FILE_SOCKET */
8655 if (winsock_lib == NULL) emacs_abort ();
8657 /* When a non-blocking 'connect' call fails,
8658 wait_reading_process_output detects this by calling
8659 'getpeername', and then attempts to obtain the connection
8660 error code by trying to read 1 byte from the socket. If
8661 we try to serve that read by calling 'recv' below, the
8662 error we get is a generic WSAENOTCONN, not the actual
8663 connection error. So instead, we use the actual error
8664 code stashed by '_sys_wait_connect' in cp->errcode.
8665 Alternatively, we could have used 'getsockopt', like on
8666 GNU/Linux, but: (a) I have no idea whether the winsock
8667 version could hang, as it does "on some systems" (see the
8668 comment in process.c); and (b) 'getsockopt' on Windows is
8669 documented to clear the socket error for the entire
8670 process, which I'm not sure is TRT; FIXME. */
8671 if (current_status == STATUS_CONNECT_FAILED
8672 && (fd_info[fd].flags & FILE_CONNECT) != 0
8673 && cp->errcode != 0)
8675 pfn_WSASetLastError (cp->errcode);
8676 set_errno ();
8677 return -1;
8679 /* Do the equivalent of a non-blocking read. */
8680 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8681 if (waiting == 0 && nchars == 0)
8683 errno = EWOULDBLOCK;
8684 return -1;
8687 if (waiting)
8689 /* always use binary mode for sockets */
8690 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8691 if (res == SOCKET_ERROR)
8693 set_errno ();
8694 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8695 errno, SOCK_HANDLE (fd)));
8696 return -1;
8698 nchars += res;
8702 else
8704 int nread = _read (fd, buffer, count);
8705 if (nread >= 0)
8706 nchars += nread;
8707 else if (nchars == 0)
8708 nchars = nread;
8711 if (nchars <= 0)
8712 fd_info[fd].flags |= FILE_AT_EOF;
8713 /* Perform text mode translation if required. */
8714 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8716 nchars = crlf_to_lf (nchars, orig_buffer);
8717 /* If buffer contains only CR, return that. To be absolutely
8718 sure we should attempt to read the next char, but in
8719 practice a CR to be followed by LF would not appear by
8720 itself in the buffer. */
8721 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8723 fd_info[fd].flags |= FILE_LAST_CR;
8724 nchars--;
8728 else
8729 nchars = _read (fd, buffer, count);
8731 return nchars;
8734 /* From w32xfns.c */
8735 extern HANDLE interrupt_handle;
8738 sys_write (int fd, const void * buffer, unsigned int count)
8740 int nchars;
8741 USE_SAFE_ALLOCA;
8743 if (fd < 0)
8745 errno = EBADF;
8746 return -1;
8749 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8751 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8753 errno = EBADF;
8754 return -1;
8757 /* Perform text mode translation if required. */
8758 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8760 char * tmpbuf;
8761 const unsigned char * src = buffer;
8762 unsigned char * dst;
8763 int nbytes = count;
8765 SAFE_NALLOCA (tmpbuf, 2, count);
8766 dst = (unsigned char *)tmpbuf;
8768 while (1)
8770 unsigned char *next;
8771 /* Copy next line or remaining bytes. */
8772 next = _memccpy (dst, src, '\n', nbytes);
8773 if (next)
8775 /* Copied one line ending with '\n'. */
8776 int copied = next - dst;
8777 nbytes -= copied;
8778 src += copied;
8779 /* Insert '\r' before '\n'. */
8780 next[-1] = '\r';
8781 next[0] = '\n';
8782 dst = next + 1;
8783 count++;
8785 else
8786 /* Copied remaining partial line -> now finished. */
8787 break;
8789 buffer = tmpbuf;
8793 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8795 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8796 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8797 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8798 DWORD active = 0;
8800 /* This is async (a.k.a. "overlapped") I/O, so the return value
8801 of FALSE from WriteFile means either an error or the output
8802 will be completed asynchronously (ERROR_IO_PENDING). */
8803 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8805 if (GetLastError () != ERROR_IO_PENDING)
8807 errno = EIO;
8808 nchars = -1;
8810 else
8812 /* Wait for the write to complete, and watch C-g while
8813 at that. */
8814 if (detect_input_pending ())
8815 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
8816 INFINITE, QS_ALLINPUT);
8817 else
8818 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8819 switch (active)
8821 case WAIT_OBJECT_0:
8822 /* User pressed C-g, cancel write, then leave.
8823 Don't bother cleaning up as we may only get stuck
8824 in buggy drivers. */
8825 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8826 CancelIo (hnd);
8827 errno = EIO; /* Why not EINTR? */
8828 nchars = -1;
8829 break;
8830 case WAIT_OBJECT_0 + 1:
8831 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8833 errno = EIO;
8834 nchars = -1;
8836 break;
8841 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8843 unsigned long nblock = 0;
8844 if (winsock_lib == NULL) emacs_abort ();
8846 child_process *cp = fd_info[fd].cp;
8848 /* If this is a non-blocking socket whose connection is in
8849 progress or terminated with an error already, return the
8850 proper error code to the caller. */
8851 if (cp != NULL && (fd_info[fd].flags & FILE_CONNECT) != 0)
8853 /* In case connection is in progress, ENOTCONN that would
8854 result from calling pfn_send is not what callers expect. */
8855 if (cp->status != STATUS_CONNECT_FAILED)
8857 errno = EWOULDBLOCK;
8858 return -1;
8860 /* In case connection failed, use the actual error code
8861 stashed by '_sys_wait_connect' in cp->errcode. */
8862 else if (cp->errcode != 0)
8864 pfn_WSASetLastError (cp->errcode);
8865 set_errno ();
8866 return -1;
8870 /* TODO: implement select() properly so non-blocking I/O works. */
8871 /* For now, make sure the write blocks. */
8872 if (fd_info[fd].flags & FILE_NDELAY)
8873 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8875 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
8877 if (nchars == SOCKET_ERROR)
8879 set_errno ();
8880 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
8881 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8884 /* Set the socket back to non-blocking if it was before,
8885 for other operations that support it. */
8886 if (fd_info[fd].flags & FILE_NDELAY)
8888 nblock = 1;
8889 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8892 else
8894 /* Some networked filesystems don't like too large writes, so
8895 break them into smaller chunks. See the Comments section of
8896 the MSDN documentation of WriteFile for details behind the
8897 choice of the value of CHUNK below. See also the thread
8898 http://thread.gmane.org/gmane.comp.version-control.git/145294
8899 in the git mailing list. */
8900 const unsigned char *p = buffer;
8901 const bool is_pipe = (fd < MAXDESC
8902 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
8903 == (FILE_PIPE | FILE_NDELAY)));
8904 /* Some programs, notably Node.js's node.exe, seem to never
8905 completely empty the pipe, so writing more than the size of
8906 the pipe's buffer always returns ENOSPC, and we loop forever
8907 between send_process and here. As a workaround, write no
8908 more than the pipe's buffer can hold. */
8909 DWORD pipe_buffer_size;
8910 if (is_pipe)
8912 if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
8913 NULL, &pipe_buffer_size, NULL, NULL))
8915 DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
8916 pipe_buffer_size = 4096;
8919 const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
8921 nchars = 0;
8922 errno = 0;
8923 while (count > 0)
8925 unsigned this_chunk = count < chunk ? count : chunk;
8926 int n = _write (fd, p, this_chunk);
8928 if (n > 0)
8929 nchars += n;
8930 if (n < 0)
8932 /* When there's no buffer space in a pipe that is in the
8933 non-blocking mode, _write returns ENOSPC. We return
8934 EAGAIN instead, which should trigger the logic in
8935 send_process that enters waiting loop and calls
8936 wait_reading_process_output to allow process input to
8937 be accepted during the wait. Those calls to
8938 wait_reading_process_output allow sys_select to
8939 notice when process input becomes available, thus
8940 avoiding deadlock whereby each side of the pipe is
8941 blocked on write, waiting for the other party to read
8942 its end of the pipe. */
8943 if (errno == ENOSPC && is_pipe)
8944 errno = EAGAIN;
8945 if (nchars == 0)
8946 nchars = -1;
8947 break;
8949 else if (n < this_chunk)
8950 break;
8951 count -= n;
8952 p += n;
8956 SAFE_FREE ();
8957 return nchars;
8961 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
8963 /* Return information about network interface IFNAME, or about all
8964 interfaces (if IFNAME is nil). */
8965 static Lisp_Object
8966 network_interface_get_info (Lisp_Object ifname)
8968 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
8969 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
8970 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
8971 Lisp_Object res = Qnil;
8973 if (retval == ERROR_BUFFER_OVERFLOW)
8975 ainfo = xrealloc (ainfo, ainfo_len);
8976 retval = get_adapters_info (ainfo, &ainfo_len);
8979 if (retval == ERROR_SUCCESS)
8981 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
8982 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
8983 int if_num;
8984 struct sockaddr_in sa;
8986 /* For the below, we need some winsock functions, so make sure
8987 the winsock DLL is loaded. If we cannot successfully load
8988 it, they will have no use of the information we provide,
8989 anyway, so punt. */
8990 if (!winsock_lib && !init_winsock (1))
8991 goto done;
8993 for (adapter = ainfo; adapter; adapter = adapter->Next)
8995 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
8996 u_long ip_addr;
8997 /* Present Unix-compatible interface names, instead of the
8998 Windows names, which are really GUIDs not readable by
8999 humans. */
9000 static const char *ifmt[] = {
9001 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
9002 "lo", "ifx%d"
9004 enum {
9005 NONE = -1,
9006 ETHERNET = 0,
9007 TOKENRING = 1,
9008 FDDI = 2,
9009 PPP = 3,
9010 SLIP = 4,
9011 WLAN = 5,
9012 LOOPBACK = 6,
9013 OTHER_IF = 7
9014 } ifmt_idx;
9016 switch (adapter->Type)
9018 case MIB_IF_TYPE_ETHERNET:
9019 /* Windows before Vista reports wireless adapters as
9020 Ethernet. Work around by looking at the Description
9021 string. */
9022 if (strstr (adapter->Description, "Wireless "))
9024 ifmt_idx = WLAN;
9025 if_num = wlan_count++;
9027 else
9029 ifmt_idx = ETHERNET;
9030 if_num = eth_count++;
9032 break;
9033 case MIB_IF_TYPE_TOKENRING:
9034 ifmt_idx = TOKENRING;
9035 if_num = tr_count++;
9036 break;
9037 case MIB_IF_TYPE_FDDI:
9038 ifmt_idx = FDDI;
9039 if_num = fddi_count++;
9040 break;
9041 case MIB_IF_TYPE_PPP:
9042 ifmt_idx = PPP;
9043 if_num = ppp_count++;
9044 break;
9045 case MIB_IF_TYPE_SLIP:
9046 ifmt_idx = SLIP;
9047 if_num = sl_count++;
9048 break;
9049 case IF_TYPE_IEEE80211:
9050 ifmt_idx = WLAN;
9051 if_num = wlan_count++;
9052 break;
9053 case MIB_IF_TYPE_LOOPBACK:
9054 if (lo_count < 0)
9056 ifmt_idx = LOOPBACK;
9057 if_num = lo_count++;
9059 else
9060 ifmt_idx = NONE;
9061 break;
9062 default:
9063 ifmt_idx = OTHER_IF;
9064 if_num = ifx_count++;
9065 break;
9067 if (ifmt_idx == NONE)
9068 continue;
9069 sprintf (namebuf, ifmt[ifmt_idx], if_num);
9071 sa.sin_family = AF_INET;
9072 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
9073 if (ip_addr == INADDR_NONE)
9075 /* Bogus address, skip this interface. */
9076 continue;
9078 sa.sin_addr.s_addr = ip_addr;
9079 sa.sin_port = 0;
9080 if (NILP (ifname))
9081 res = Fcons (Fcons (build_string (namebuf),
9082 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9083 sizeof (struct sockaddr))),
9084 res);
9085 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
9087 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
9088 register struct Lisp_Vector *p = XVECTOR (hwaddr);
9089 Lisp_Object flags = Qnil;
9090 int n;
9091 u_long net_mask;
9093 /* Flags. We guess most of them by type, since the
9094 Windows flags are different and hard to get by. */
9095 flags = Fcons (intern ("up"), flags);
9096 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
9098 flags = Fcons (intern ("broadcast"), flags);
9099 flags = Fcons (intern ("multicast"), flags);
9101 flags = Fcons (intern ("running"), flags);
9102 if (ifmt_idx == PPP)
9104 flags = Fcons (intern ("pointopoint"), flags);
9105 flags = Fcons (intern ("noarp"), flags);
9107 if (adapter->HaveWins)
9108 flags = Fcons (intern ("WINS"), flags);
9109 if (adapter->DhcpEnabled)
9110 flags = Fcons (intern ("dynamic"), flags);
9112 res = Fcons (flags, res);
9114 /* Hardware address and its family. */
9115 for (n = 0; n < adapter->AddressLength; n++)
9116 p->contents[n] = make_number ((int) adapter->Address[n]);
9117 /* Windows does not support AF_LINK or AF_PACKET family
9118 of addresses. Use an arbitrary family number that is
9119 identical to what GNU/Linux returns. */
9120 res = Fcons (Fcons (make_number (1), hwaddr), res);
9122 /* Network mask. */
9123 sa.sin_family = AF_INET;
9124 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
9125 if (net_mask != INADDR_NONE)
9127 sa.sin_addr.s_addr = net_mask;
9128 sa.sin_port = 0;
9129 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9130 sizeof (struct sockaddr)),
9131 res);
9133 else
9134 res = Fcons (Qnil, res);
9136 sa.sin_family = AF_INET;
9137 if (ip_addr != INADDR_NONE)
9139 /* Broadcast address is only reported by
9140 GetAdaptersAddresses, which is of limited
9141 availability. Generate it on our own. */
9142 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
9144 sa.sin_addr.s_addr = bcast_addr;
9145 sa.sin_port = 0;
9146 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9147 sizeof (struct sockaddr)),
9148 res);
9150 /* IP address. */
9151 sa.sin_addr.s_addr = ip_addr;
9152 sa.sin_port = 0;
9153 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9154 sizeof (struct sockaddr)),
9155 res);
9157 else
9158 res = Fcons (Qnil, Fcons (Qnil, res));
9161 /* GetAdaptersInfo is documented to not report loopback
9162 interfaces, so we generate one out of thin air. */
9163 if (!lo_count)
9165 sa.sin_family = AF_INET;
9166 sa.sin_port = 0;
9167 if (NILP (ifname))
9169 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9170 res = Fcons (Fcons (build_string ("lo"),
9171 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9172 sizeof (struct sockaddr))),
9173 res);
9175 else if (strcmp (SSDATA (ifname), "lo") == 0)
9177 res = Fcons (Fcons (intern ("running"),
9178 Fcons (intern ("loopback"),
9179 Fcons (intern ("up"), Qnil))), Qnil);
9180 /* 772 is what 3 different GNU/Linux systems report for
9181 the loopback interface. */
9182 res = Fcons (Fcons (make_number (772),
9183 Fmake_vector (make_number (6),
9184 make_number (0))),
9185 res);
9186 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
9187 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9188 sizeof (struct sockaddr)),
9189 res);
9190 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
9191 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9192 sizeof (struct sockaddr)),
9193 res);
9194 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9195 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9196 sizeof (struct sockaddr)),
9197 res);
9203 done:
9204 xfree (ainfo);
9205 return res;
9208 Lisp_Object
9209 network_interface_list (void)
9211 return network_interface_get_info (Qnil);
9214 Lisp_Object
9215 network_interface_info (Lisp_Object ifname)
9217 CHECK_STRING (ifname);
9218 return network_interface_get_info (ifname);
9222 /* The Windows CRT functions are "optimized for speed", so they don't
9223 check for timezone and DST changes if they were last called less
9224 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
9225 all Emacs features that repeatedly call time functions (e.g.,
9226 display-time) are in real danger of missing timezone and DST
9227 changes. Calling tzset before each localtime call fixes that. */
9228 struct tm *
9229 sys_localtime (const time_t *t)
9231 tzset ();
9232 return localtime (t);
9237 /* Try loading LIBRARY_ID from the file(s) specified in
9238 Vdynamic_library_alist. If the library is loaded successfully,
9239 return the handle of the DLL, and record the filename in the
9240 property :loaded-from of LIBRARY_ID. If the library could not be
9241 found, or when it was already loaded (because the handle is not
9242 recorded anywhere, and so is lost after use), return NULL.
9244 We could also save the handle in :loaded-from, but currently
9245 there's no use case for it. */
9246 HMODULE
9247 w32_delayed_load (Lisp_Object library_id)
9249 HMODULE dll_handle = NULL;
9251 CHECK_SYMBOL (library_id);
9253 if (CONSP (Vdynamic_library_alist)
9254 && NILP (Fassq (library_id, Vlibrary_cache)))
9256 Lisp_Object found = Qnil;
9257 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
9259 if (CONSP (dlls))
9260 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
9262 Lisp_Object dll = XCAR (dlls);
9263 char name[MAX_UTF8_PATH];
9264 DWORD res = -1;
9266 CHECK_STRING (dll);
9267 dll = ENCODE_FILE (dll);
9268 if (w32_unicode_filenames)
9270 wchar_t name_w[MAX_PATH];
9272 filename_to_utf16 (SSDATA (dll), name_w);
9273 dll_handle = LoadLibraryW (name_w);
9274 if (dll_handle)
9276 res = GetModuleFileNameW (dll_handle, name_w,
9277 sizeof (name_w));
9278 if (res > 0)
9279 filename_from_utf16 (name_w, name);
9282 else
9284 char name_a[MAX_PATH];
9286 filename_to_ansi (SSDATA (dll), name_a);
9287 dll_handle = LoadLibraryA (name_a);
9288 if (dll_handle)
9290 res = GetModuleFileNameA (dll_handle, name_a,
9291 sizeof (name_a));
9292 if (res > 0)
9293 filename_from_ansi (name_a, name);
9296 if (dll_handle)
9298 ptrdiff_t len = strlen (name);
9299 found = Fcons (dll,
9300 (res > 0)
9301 /* Possibly truncated */
9302 ? make_specified_string (name, -1, len, 1)
9303 : Qnil);
9304 /* This prevents thread start and end notifications
9305 from being sent to the DLL, for every thread we
9306 start. We don't need those notifications because
9307 threads we create never use any of these DLLs, only
9308 the main thread uses them. This is supposed to
9309 speed up thread creation. */
9310 DisableThreadLibraryCalls (dll_handle);
9311 break;
9315 Fput (library_id, QCloaded_from, found);
9318 return dll_handle;
9322 void
9323 check_windows_init_file (void)
9325 /* A common indication that Emacs is not installed properly is when
9326 it cannot find the Windows installation file. If this file does
9327 not exist in the expected place, tell the user. */
9329 if (!noninteractive && !inhibit_window_system
9330 /* Vload_path is not yet initialized when we are loading
9331 loadup.el. */
9332 && NILP (Vpurify_flag))
9334 Lisp_Object init_file;
9335 int fd;
9337 /* Implementation note: this function runs early during Emacs
9338 startup, before startup.el is run. So Vload_path is still in
9339 its initial unibyte form, but it holds UTF-8 encoded file
9340 names, since init_callproc was already called. So we do not
9341 need to ENCODE_FILE here, but we do need to convert the file
9342 names from UTF-8 to ANSI. */
9343 init_file = build_string ("term/w32-win");
9344 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
9345 if (fd < 0)
9347 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
9348 char *init_file_name = SSDATA (init_file);
9349 char *load_path = SSDATA (load_path_print);
9350 char *buffer = alloca (1024
9351 + strlen (init_file_name)
9352 + strlen (load_path));
9353 char *msg = buffer;
9354 int needed;
9356 sprintf (buffer,
9357 "The Emacs Windows initialization file \"%s.el\" "
9358 "could not be found in your Emacs installation. "
9359 "Emacs checked the following directories for this file:\n"
9360 "\n%s\n\n"
9361 "When Emacs cannot find this file, it usually means that it "
9362 "was not installed properly, or its distribution file was "
9363 "not unpacked properly.\nSee the README.W32 file in the "
9364 "top-level Emacs directory for more information.",
9365 init_file_name, load_path);
9366 needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
9367 buffer, -1, NULL, 0);
9368 if (needed > 0)
9370 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
9372 pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
9373 -1, msg_w, needed);
9374 needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
9375 NULL, 0, NULL, NULL);
9376 if (needed > 0)
9378 char *msg_a = alloca (needed + 1);
9380 pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
9381 NULL, NULL);
9382 msg = msg_a;
9385 MessageBox (NULL,
9386 msg,
9387 "Emacs Abort Dialog",
9388 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
9389 /* Use the low-level system abort. */
9390 abort ();
9392 else
9394 _close (fd);
9399 void
9400 term_ntproc (int ignored)
9402 (void)ignored;
9404 term_timers ();
9406 /* shutdown the socket interface if necessary */
9407 term_winsock ();
9409 term_w32select ();
9412 void
9413 init_ntproc (int dumping)
9415 sigset_t initial_mask = 0;
9417 /* Initialize the socket interface now if available and requested by
9418 the user by defining PRELOAD_WINSOCK; otherwise loading will be
9419 delayed until open-network-stream is called (w32-has-winsock can
9420 also be used to dynamically load or reload winsock).
9422 Conveniently, init_environment is called before us, so
9423 PRELOAD_WINSOCK can be set in the registry. */
9425 /* Always initialize this correctly. */
9426 winsock_lib = NULL;
9428 if (getenv ("PRELOAD_WINSOCK") != NULL)
9429 init_winsock (TRUE);
9431 /* Initial preparation for subprocess support: replace our standard
9432 handles with non-inheritable versions. */
9434 HANDLE parent;
9435 HANDLE stdin_save = INVALID_HANDLE_VALUE;
9436 HANDLE stdout_save = INVALID_HANDLE_VALUE;
9437 HANDLE stderr_save = INVALID_HANDLE_VALUE;
9439 parent = GetCurrentProcess ();
9441 /* ignore errors when duplicating and closing; typically the
9442 handles will be invalid when running as a gui program. */
9443 DuplicateHandle (parent,
9444 GetStdHandle (STD_INPUT_HANDLE),
9445 parent,
9446 &stdin_save,
9448 FALSE,
9449 DUPLICATE_SAME_ACCESS);
9451 DuplicateHandle (parent,
9452 GetStdHandle (STD_OUTPUT_HANDLE),
9453 parent,
9454 &stdout_save,
9456 FALSE,
9457 DUPLICATE_SAME_ACCESS);
9459 DuplicateHandle (parent,
9460 GetStdHandle (STD_ERROR_HANDLE),
9461 parent,
9462 &stderr_save,
9464 FALSE,
9465 DUPLICATE_SAME_ACCESS);
9467 fclose (stdin);
9468 fclose (stdout);
9469 fclose (stderr);
9471 if (stdin_save != INVALID_HANDLE_VALUE)
9472 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
9473 else
9474 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
9475 _fdopen (0, "r");
9477 if (stdout_save != INVALID_HANDLE_VALUE)
9478 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
9479 else
9480 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9481 _fdopen (1, "w");
9483 if (stderr_save != INVALID_HANDLE_VALUE)
9484 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
9485 else
9486 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9487 _fdopen (2, "w");
9490 /* unfortunately, atexit depends on implementation of malloc */
9491 /* atexit (term_ntproc); */
9492 if (!dumping)
9494 /* Make sure we start with all signals unblocked. */
9495 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
9496 signal (SIGABRT, term_ntproc);
9498 init_timers ();
9500 /* determine which drives are fixed, for GetCachedVolumeInformation */
9502 /* GetDriveType must have trailing backslash. */
9503 char drive[] = "A:\\";
9505 /* Loop over all possible drive letters */
9506 while (*drive <= 'Z')
9508 /* Record if this drive letter refers to a fixed drive. */
9509 fixed_drives[DRIVE_INDEX (*drive)] =
9510 (GetDriveType (drive) == DRIVE_FIXED);
9512 (*drive)++;
9515 /* Reset the volume info cache. */
9516 volume_cache = NULL;
9521 shutdown_handler ensures that buffers' autosave files are
9522 up to date when the user logs off, or the system shuts down.
9524 static BOOL WINAPI
9525 shutdown_handler (DWORD type)
9527 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
9528 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
9529 || type == CTRL_LOGOFF_EVENT /* User logs off. */
9530 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
9532 /* Shut down cleanly, making sure autosave files are up to date. */
9533 shut_down_emacs (0, Qnil);
9536 /* Allow other handlers to handle this signal. */
9537 return FALSE;
9540 /* On Windows 9X, load UNICOWS.DLL and return its handle, or die. On
9541 NT, return a handle to GDI32.DLL. */
9542 HANDLE
9543 maybe_load_unicows_dll (void)
9545 if (os_subtype == OS_9X)
9547 HANDLE ret = LoadLibrary ("Unicows.dll");
9548 if (ret)
9550 /* These two functions are present on Windows 9X as stubs
9551 that always fail. We need the real implementations from
9552 UNICOWS.DLL, so we must call these functions through
9553 pointers, and assign the correct addresses to these
9554 pointers at program startup (see emacs.c, which calls
9555 this function early on). */
9556 pMultiByteToWideChar =
9557 (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
9558 pWideCharToMultiByte =
9559 (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
9560 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9561 return ret;
9563 else
9565 int button;
9567 button = MessageBox (NULL,
9568 "Emacs cannot load the UNICOWS.DLL library.\n"
9569 "This library is essential for using Emacs\n"
9570 "on this system. You need to install it.\n\n"
9571 "Emacs will exit when you click OK.",
9572 "Emacs cannot load UNICOWS.DLL",
9573 MB_ICONERROR | MB_TASKMODAL
9574 | MB_SETFOREGROUND | MB_OK);
9575 switch (button)
9577 case IDOK:
9578 default:
9579 exit (1);
9583 else
9585 /* On NT family of Windows, these two functions are always
9586 linked in, so we just assign their addresses to the 2
9587 pointers; no need for the LoadLibrary dance. */
9588 pMultiByteToWideChar = MultiByteToWideChar;
9589 pWideCharToMultiByte = WideCharToMultiByte;
9590 /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported. */
9591 if (w32_major_version < 5)
9592 multiByteToWideCharFlags = 0;
9593 else
9594 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9595 return LoadLibrary ("Gdi32.dll");
9600 globals_of_w32 is used to initialize those global variables that
9601 must always be initialized on startup even when the global variable
9602 initialized is non zero (see the function main in emacs.c).
9604 void
9605 globals_of_w32 (void)
9607 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
9609 get_process_times_fn = (GetProcessTimes_Proc)
9610 GetProcAddress (kernel32, "GetProcessTimes");
9612 DEFSYM (QCloaded_from, ":loaded-from");
9614 g_b_init_is_windows_9x = 0;
9615 g_b_init_open_process_token = 0;
9616 g_b_init_get_token_information = 0;
9617 g_b_init_lookup_account_sid = 0;
9618 g_b_init_get_sid_sub_authority = 0;
9619 g_b_init_get_sid_sub_authority_count = 0;
9620 g_b_init_get_security_info = 0;
9621 g_b_init_get_file_security_w = 0;
9622 g_b_init_get_file_security_a = 0;
9623 g_b_init_get_security_descriptor_owner = 0;
9624 g_b_init_get_security_descriptor_group = 0;
9625 g_b_init_is_valid_sid = 0;
9626 g_b_init_create_toolhelp32_snapshot = 0;
9627 g_b_init_process32_first = 0;
9628 g_b_init_process32_next = 0;
9629 g_b_init_open_thread_token = 0;
9630 g_b_init_impersonate_self = 0;
9631 g_b_init_revert_to_self = 0;
9632 g_b_init_get_process_memory_info = 0;
9633 g_b_init_get_process_working_set_size = 0;
9634 g_b_init_global_memory_status = 0;
9635 g_b_init_global_memory_status_ex = 0;
9636 g_b_init_equal_sid = 0;
9637 g_b_init_copy_sid = 0;
9638 g_b_init_get_length_sid = 0;
9639 g_b_init_get_native_system_info = 0;
9640 g_b_init_get_system_times = 0;
9641 g_b_init_create_symbolic_link_w = 0;
9642 g_b_init_create_symbolic_link_a = 0;
9643 g_b_init_get_security_descriptor_dacl = 0;
9644 g_b_init_convert_sd_to_sddl = 0;
9645 g_b_init_convert_sddl_to_sd = 0;
9646 g_b_init_is_valid_security_descriptor = 0;
9647 g_b_init_set_file_security_w = 0;
9648 g_b_init_set_file_security_a = 0;
9649 g_b_init_set_named_security_info_w = 0;
9650 g_b_init_set_named_security_info_a = 0;
9651 g_b_init_get_adapters_info = 0;
9652 g_b_init_compare_string_w = 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 */